]>
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 | |
546c8f95 JL |
61 | ;; Instruction length is calculated by examining the type and number of |
62 | ;; operands. | |
63 | ;; Whether the insn uses the 430X extension word, or is a 430X address | |
64 | ;; instruction also has an effect. | |
65 | ;; "Cheap" source operands do not contribute to the overall length of the insn | |
66 | ;; and are register (Rn), indirect post-increment (@Rn+) and indirect register | |
67 | ;; (@Rn). | |
68 | ;; The lengths of instructions in bytes are: | |
69 | ;; Single-op 430: Cheap op == 2 | |
70 | ;; (also CALLA) Other op == 4 | |
71 | ;; Double-op 430: Source is not cheap == 2 | |
72 | ;; (also MOVA, Dest is register == 2 | |
73 | ;; CMPA, ADDA, Dest is not a register == 4 | |
74 | ;; SUBA) (sum the source and dest cost) | |
75 | ;; Single-op 430X: For insn names ending in 'X' add 2 to single-op 430 cost. | |
76 | ;; Double-op 430X: Insn name ends in 'M' == 2 | |
77 | ;; Others have the same cost as double-op 430 but add 2. | |
78 | ;; | |
79 | ;; The insn type describes whether it is a single or double operand MSP430 | |
80 | ;; instruction (some single-operand GCC instructions are actually | |
81 | ;; double-operand on the target). | |
82 | ;; "triple" and "cmp" types use the costs of a double operand type but | |
83 | ;; instead assume that the src operand is in op2, and also cmp types assume the | |
84 | ;; dst operand is in op1. | |
85 | ;; This attribute also describes which operands are safe to examine | |
86 | ;; when calculating the length or extension. GCC will segfault trying to | |
87 | ;; examine a non-existant operand of an insn. | |
88 | (define_attr "type" "none,single,double,triple,cmp" (const_string "none")) | |
89 | ||
90 | ;; The M extension is for instructions like RRAM - they always | |
91 | ;; only, and the operand must be a register. | |
92 | (define_attr "extension" "none,x,a,m" | |
93 | (cond [(eq_attr "type" "none") | |
94 | (const_string "none") | |
95 | (match_operand 0 "msp430_high_memory_operand" "") | |
96 | (const_string "x") | |
97 | (and (eq_attr "type" "double") | |
98 | (match_operand 1 "msp430_high_memory_operand" "")) | |
99 | (const_string "x") | |
100 | (and (ior (eq_attr "type" "triple") (eq_attr "type" "cmp")) | |
101 | (ior (match_operand 1 "msp430_high_memory_operand" "") | |
102 | (match_operand 2 "msp430_high_memory_operand" ""))) | |
103 | (const_string "x")] | |
104 | (const_string "none"))) | |
105 | ||
106 | ;; Multiply the default length by this constant value. | |
107 | (define_attr "length_multiplier" "" (const_int 1)) | |
108 | ||
109 | ;; Add an additional amount to the total length of the insn. | |
110 | (define_attr "extra_length" "" (const_int 0)) | |
111 | ||
112 | ;; FIXME for some reason if we move the addition of 2 for extension == x to | |
113 | ;; ADJUST_INSN_LENGTH, codesize gets much worse. | |
114 | (define_attr "length" "" | |
115 | (cond [(eq_attr "extension" "m") | |
116 | (const_int 2) | |
117 | (eq_attr "type" "single") | |
118 | (plus (if_then_else (match_operand 0 "msp430_cheap_operand" "") | |
119 | (const_int 2) | |
120 | (const_int 4)) | |
121 | (if_then_else (eq_attr "extension" "x") | |
122 | (const_int 2) | |
123 | (const_int 0))) | |
124 | (eq_attr "type" "double") | |
125 | (plus (plus (if_then_else (match_operand 0 "register_operand" "") | |
126 | (const_int 2) | |
127 | (const_int 4)) | |
128 | (if_then_else (match_operand 1 "msp430_cheap_operand" "") | |
129 | (const_int 0) | |
130 | (const_int 2))) | |
131 | (if_then_else (eq_attr "extension" "x") | |
132 | (const_int 2) | |
133 | (const_int 0))) | |
134 | (eq_attr "type" "triple") | |
135 | (plus (plus (if_then_else (match_operand 0 "register_operand" "") | |
136 | (const_int 2) | |
137 | (const_int 4)) | |
138 | (if_then_else (match_operand 2 "msp430_cheap_operand" "") | |
139 | (const_int 0) | |
140 | (const_int 2))) | |
141 | (if_then_else (eq_attr "extension" "x") | |
142 | (const_int 2) | |
143 | (const_int 0))) | |
144 | (eq_attr "type" "cmp") | |
145 | (plus (plus (if_then_else (match_operand 1 "register_operand" "") | |
146 | (const_int 2) | |
147 | (const_int 4)) | |
148 | (if_then_else (match_operand 2 "msp430_cheap_operand" "") | |
149 | (const_int 0) | |
150 | (const_int 2))) | |
151 | (if_then_else (eq_attr "extension" "x") | |
152 | (const_int 2) | |
153 | (const_int 0)))] | |
154 | (const_int 2))) | |
d7edde11 | 155 | |
f6a83b4a DD |
156 | (include "predicates.md") |
157 | (include "constraints.md") | |
158 | ||
159 | (define_mode_iterator QHI [QI HI PSI]) | |
703e049a JL |
160 | (define_mode_iterator HPSI [HI PSI]) |
161 | (define_mode_iterator HDI [HI PSI SI DI]) | |
162 | ||
163 | ;; Mapping of all shift operators | |
164 | (define_code_iterator any_shift [ashift ashiftrt lshiftrt]) | |
165 | ||
166 | ;; Base name for define_insn | |
167 | (define_code_attr shift_insn | |
168 | [(ashift "ashl") (lshiftrt "lshr") (ashiftrt "ashr")]) | |
f6a83b4a DD |
169 | |
170 | ;; There are two basic "family" tests we do here: | |
171 | ;; | |
172 | ;; msp430x - true if 430X instructions are available. | |
173 | ;; TARGET_LARGE - true if pointers are 20-bits | |
174 | ;; | |
175 | ;; Note that there are three supported cases, since the base 430 | |
176 | ;; doesn't have 20-bit pointers: | |
177 | ;; | |
178 | ;; 1. MSP430 cpu, small model | |
179 | ;; 2. MSP430X cpu, small model. | |
180 | ;; 3. MSP430X cpu, large model. | |
181 | ||
182 | ;;------------------------------------------------------------ | |
183 | ;; Moves | |
184 | ||
185 | ;; Push/Pop must be before the generic move patterns | |
186 | ||
187 | (define_insn "push" | |
188 | [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNO))) | |
189 | (match_operand:HI 0 "register_operand" "r"))] | |
190 | "" | |
191 | "PUSH\t%0" | |
546c8f95 JL |
192 | [(set_attr "type" "single")] |
193 | ) | |
f6a83b4a DD |
194 | |
195 | (define_insn "pusha" | |
196 | [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO))) | |
197 | (match_operand:PSI 0 "register_operand" "r"))] | |
198 | "TARGET_LARGE" | |
199 | "PUSHX.A\t%0" | |
546c8f95 JL |
200 | [(set_attr "type" "single") |
201 | (set_attr "extension" "x")] | |
202 | ) | |
f6a83b4a DD |
203 | |
204 | (define_insn "pushm" | |
205 | [(unspec_volatile [(match_operand 0 "register_operand" "r") | |
cad055a4 | 206 | (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)] |
f6a83b4a | 207 | "" |
51ac3042 | 208 | "PUSHM%b0\t%1, %0" |
546c8f95 JL |
209 | [(set_attr "type" "single") |
210 | (set_attr "extension" "m")] | |
211 | ) | |
f6a83b4a DD |
212 | |
213 | (define_insn "pop" | |
214 | [(set (match_operand:HI 0 "register_operand" "=r") | |
215 | (mem:HI (post_inc:HI (reg:HI SP_REGNO))))] | |
216 | "" | |
217 | "POP\t%0" | |
546c8f95 JL |
218 | [(set_attr "type" "single")] |
219 | ) | |
f6a83b4a DD |
220 | |
221 | (define_insn "popa" | |
222 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
223 | (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))] | |
224 | "TARGET_LARGE" | |
225 | "POPX.A\t%0" | |
546c8f95 JL |
226 | [(set_attr "type" "single") |
227 | (set_attr "extension" "x")] | |
228 | ) | |
f6a83b4a DD |
229 | |
230 | ;; This is nasty. Operand0 is bogus. It is only there so that we can get a | |
51ac3042 | 231 | ;; mode for the %b0 to work. We should use operand1 for this, but that does |
f6a83b4a DD |
232 | ;; not have a mode. |
233 | ;; | |
234 | ;; Operand1 is actually a register, but we cannot accept (REG...) because the | |
235 | ;; cprop_hardreg pass can and will renumber registers even inside | |
236 | ;; unspec_volatiles. So we take an integer register number parameter and | |
d4f283a1 | 237 | ;; fudge it to be a register name when we generate the assembler. |
f6a83b4a DD |
238 | ;; |
239 | ;; The pushm pattern does not have this problem because of all of the | |
240 | ;; frame info cruft attached to it, so cprop_hardreg leaves it alone. | |
241 | (define_insn "popm" | |
242 | [(unspec_volatile [(match_operand 0 "register_operand" "r") | |
243 | (match_operand 1 "immediate_operand" "i") | |
244 | (match_operand 2 "immediate_operand" "i")] UNS_POPM)] | |
245 | "" | |
d4f283a1 | 246 | "POPM%b0\t%2, r%J1" |
546c8f95 JL |
247 | [(set_attr "type" "single") |
248 | (set_attr "extension" "m")] | |
249 | ) | |
f6a83b4a DD |
250 | |
251 | ;; The next two patterns are here to support a "feature" of how GCC implements | |
252 | ;; varargs. When a function uses varargs and the *second* to last named | |
253 | ;; argument is split between argument registers and the stack, gcc expects the | |
254 | ;; callee to allocate space on the stack that can contain the register-based | |
255 | ;; part of the argument. This space *has* to be just before the remaining | |
256 | ;; arguments (ie the ones that are fully on the stack). | |
257 | ;; | |
258 | ;; The problem is that the MSP430 CALL instruction pushes the return address | |
259 | ;; onto the stack in the exact place where the callee wants to allocate | |
260 | ;; this extra space. So we need a sequence of instructions that can allocate | |
261 | ;; the extra space and then move the return address down the stack, so that | |
262 | ;; the extra space is now adjacent to the remaining arguments. | |
263 | ;; | |
264 | ;; This could be constructed through regular insns, but they might be split up | |
265 | ;; by a misguided optimization, so an unspec volatile is used instead. | |
266 | ||
267 | (define_insn "grow_and_swap" | |
268 | [(unspec_volatile [(const_int 0)] UNS_GROW_AND_SWAP)] | |
269 | "" | |
c6f709ec NC |
270 | "* |
271 | if (TARGET_LARGE) | |
272 | return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\"; | |
273 | return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\"; | |
274 | " | |
546c8f95 JL |
275 | [(set (attr "length") |
276 | (if_then_else (match_test "TARGET_LARGE") | |
277 | (const_int 8) | |
278 | (const_int 6)))] | |
c6f709ec | 279 | ) |
f6a83b4a DD |
280 | |
281 | (define_insn "swap_and_shrink" | |
282 | [(unspec_volatile [(const_int 0)] UNS_SWAP_AND_SHRINK)] | |
283 | "" | |
c6f709ec NC |
284 | "* return TARGET_LARGE |
285 | ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\" | |
286 | : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\"; | |
546c8f95 JL |
287 | " |
288 | [(set (attr "length") | |
289 | (if_then_else (match_test "TARGET_LARGE") | |
290 | (const_int 10) | |
291 | (const_int 8)))] | |
292 | ) | |
f6a83b4a DD |
293 | |
294 | ; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a | |
295 | ; zero_extend anyway. Catch it here. | |
296 | (define_insn "movqihi" | |
297 | [(set (match_operand:HI 0 "register_operand" "=r,r") | |
298 | (zero_extend:HI (match_operand:QI 1 "memory_operand" "Ys,m")))] | |
299 | "" | |
300 | "@ | |
301 | MOV.B\t%1, %0 | |
302 | MOV%X1.B\t%1, %0" | |
546c8f95 | 303 | [(set_attr "type" "double")] |
f6a83b4a DD |
304 | ) |
305 | ||
c32ab325 | 306 | (define_insn "movqi_topbyte" |
28987d8b | 307 | [(set (match_operand:QI 0 "msp430_general_dst_operand" "=r") |
8a896995 | 308 | (subreg:QI (match_operand:PSI 1 "msp430_general_operand" "r") 2))] |
c32ab325 DD |
309 | "msp430x" |
310 | "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0" | |
546c8f95 JL |
311 | [(set_attr "length" "6") |
312 | (set_attr "type" "double")] | |
c32ab325 DD |
313 | ) |
314 | ||
f6a83b4a | 315 | (define_insn "movqi" |
28987d8b | 316 | [(set (match_operand:QI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
8a896995 | 317 | (match_operand:QI 1 "msp430_general_operand" "riYsYx,rmi"))] |
f6a83b4a DD |
318 | "" |
319 | "@ | |
320 | MOV.B\t%1, %0 | |
8682b1a5 | 321 | MOVX.B\t%1, %0" |
546c8f95 | 322 | [(set_attr "type" "double")] |
f6a83b4a DD |
323 | ) |
324 | ||
325 | (define_insn "movhi" | |
28987d8b | 326 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=r,rYsYx,rm") |
8a896995 | 327 | (match_operand:HI 1 "msp430_general_operand" "N,riYsYx,rmi"))] |
f6a83b4a DD |
328 | "" |
329 | "@ | |
3f02735b | 330 | MOV.B\t%1, %0 |
f6a83b4a | 331 | MOV.W\t%1, %0 |
8682b1a5 | 332 | MOVX.W\t%1, %0" |
546c8f95 | 333 | [(set_attr "type" "double")] |
f6a83b4a DD |
334 | ) |
335 | ||
336 | (define_expand "movsi" | |
28987d8b | 337 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand") |
40ada30a | 338 | (match_operand:SI 1 "general_operand"))] |
f6a83b4a DD |
339 | "" |
340 | "" | |
546c8f95 | 341 | ) |
d7edde11 | 342 | |
14ae1d88 | 343 | (define_insn_and_split "movsi_s" |
28987d8b | 344 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
14ae1d88 DD |
345 | (subreg:SI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] |
346 | "" | |
347 | "" | |
348 | "reload_completed" | |
28987d8b | 349 | [(set (match_operand:HI 2 "msp430_general_dst_nonv_operand") |
14ae1d88 | 350 | (match_operand:HI 4 "general_operand")) |
28987d8b | 351 | (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") |
14ae1d88 DD |
352 | (match_operand:HI 5 "general_operand"))] |
353 | "msp430_split_movsi (operands);" | |
546c8f95 JL |
354 | [(set_attr "type" "double")] |
355 | ) | |
14ae1d88 | 356 | |
f6a83b4a | 357 | (define_insn_and_split "movsi_x" |
28987d8b | 358 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") |
f6a83b4a DD |
359 | (match_operand:SI 1 "general_operand" "rmi"))] |
360 | "" | |
361 | "#" | |
362 | "reload_completed" | |
28987d8b | 363 | [(set (match_operand:HI 2 "msp430_general_dst_nonv_operand") |
f6a83b4a | 364 | (match_operand:HI 4 "general_operand")) |
28987d8b | 365 | (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
366 | (match_operand:HI 5 "general_operand"))] |
367 | "msp430_split_movsi (operands);" | |
546c8f95 | 368 | [(set_attr "type" "double")] |
f6a83b4a DD |
369 | ) |
370 | ||
8682b1a5 | 371 | ;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them. |
f6a83b4a | 372 | (define_insn "movpsi" |
28987d8b | 373 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,r,r,Ya,rm") |
8a896995 | 374 | (match_operand:PSI 1 "msp430_general_operand" "N,O,riYa,r,rmi"))] |
f6a83b4a DD |
375 | "" |
376 | "@ | |
3f02735b DD |
377 | MOV.B\t%1, %0 |
378 | MOV.W\t%1, %0 | |
c32ab325 DD |
379 | MOVA\t%1, %0 |
380 | MOVA\t%1, %0 | |
546c8f95 JL |
381 | MOVX.A\t%1, %0" |
382 | [(set_attr "extension" "none,none,a,a,x") | |
383 | (set_attr "type" "double")] | |
384 | ) | |
f6a83b4a DD |
385 | |
386 | ; This pattern is identical to the truncsipsi2 pattern except | |
387 | ; that it uses a SUBREG instead of a TRUNC. It is needed in | |
388 | ; order to prevent reload from converting (set:SI (SUBREG:PSI (SI))) | |
389 | ; into (SET:PSI (PSI)). | |
390 | ; | |
391 | ; Note: using POPM.A #1 is two bytes smaller than using POPX.A.... | |
392 | ||
393 | (define_insn "movsipsi2" | |
394 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
395 | (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))] | |
c32ab325 | 396 | "msp430x" |
d4f283a1 | 397 | "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0" |
546c8f95 JL |
398 | [(set_attr "length" "6") |
399 | (set_attr "type" "double")] | |
f6a83b4a DD |
400 | ) |
401 | ||
e56989ff NC |
402 | ;; Produced when converting a pointer to an integer via a union, eg gcc.dg/pr47201.c. |
403 | (define_insn "*movpsihi2_lo" | |
404 | [(set (match_operand:HI 0 "register_operand" "=r") | |
405 | (subreg:HI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] | |
406 | "msp430x" | |
407 | "MOVA\t%1, %0" | |
546c8f95 JL |
408 | [(set_attr "extension" "a") |
409 | (set_attr "type" "double")] | |
e56989ff NC |
410 | ) |
411 | ||
f6a83b4a DD |
412 | ;;------------------------------------------------------------ |
413 | ;; Math | |
414 | ||
415 | (define_insn "addpsi3" | |
28987d8b JL |
416 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,rm") |
417 | (plus:PSI (match_operand:PSI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 418 | (match_operand:PSI 2 "msp430_general_operand" "rLs,rmi")))] |
f6a83b4a DD |
419 | "" |
420 | "@ | |
421 | ADDA\t%2, %0 | |
422 | ADDX.A\t%2, %0" | |
546c8f95 JL |
423 | [(set_attr "extension" "a,x") |
424 | (set_attr "type" "triple")] | |
f6a83b4a DD |
425 | ) |
426 | ||
427 | (define_insn "addqi3" | |
28987d8b JL |
428 | [(set (match_operand:QI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
429 | (plus:QI (match_operand:QI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 430 | (match_operand:QI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
431 | "" |
432 | "@ | |
433 | ADD.B\t%2, %0 | |
8682b1a5 | 434 | ADDX.B\t%2, %0" |
546c8f95 | 435 | [(set_attr "type" "triple")] |
f6a83b4a DD |
436 | ) |
437 | ||
438 | (define_insn "addhi3" | |
28987d8b JL |
439 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
440 | (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 441 | (match_operand:HI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
442 | "" |
443 | "@ | |
444 | ADD.W\t%2, %0 | |
8682b1a5 | 445 | ADDX.W\t%2, %0" |
546c8f95 | 446 | [(set_attr "type" "triple")] |
f6a83b4a DD |
447 | ) |
448 | ||
449 | ; This pattern is needed in order to avoid reload problems. | |
450 | ; It takes an SI pair of registers, adds a value to them, and | |
451 | ; then converts them into a single PSI register. | |
452 | ||
453 | (define_insn "addsipsi3" | |
454 | [(set (subreg:SI (match_operand:PSI 0 "register_operand" "=&r") 0) | |
455 | (plus:SI (match_operand:SI 1 "register_operand" "0") | |
456 | (match_operand 2 "general_operand" "rmi")))] | |
457 | "" | |
8682b1a5 | 458 | "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" |
546c8f95 JL |
459 | [(set (attr "length") |
460 | (if_then_else (match_operand 2 "register_operand" "") | |
461 | (const_int 10) | |
462 | (if_then_else (match_operand 2 "msp430_high_memory_operand" "") | |
463 | (const_int 18) | |
464 | (const_int 14)))) | |
465 | (set_attr "type" "triple")] | |
f6a83b4a DD |
466 | ) |
467 | ||
468 | (define_insn "addsi3" | |
28987d8b JL |
469 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=&rYsYx,rm") |
470 | (plus:SI (match_operand:SI 1 "general_operand" "%0,0") | |
8682b1a5 | 471 | (match_operand:SI 2 "general_operand" "rYsYxi,mi")))] |
f6a83b4a DD |
472 | "" |
473 | "@ | |
474 | ADD\t%L2, %L0 { ADDC\t%H2, %H0 | |
8682b1a5 | 475 | ADDX\t%L2, %L0 { ADDCX\t%H2, %H0" |
546c8f95 JL |
476 | [(set_attr "length_multiplier" "2") |
477 | (set_attr "type" "triple")] | |
f6a83b4a DD |
478 | ) |
479 | ||
480 | ; Version of addhi that exposes the carry operations, for SImode adds. | |
481 | ; | |
482 | ; NOTE - we are playing a dangerous game with GCC here. We have these two | |
483 | ; add patterns and the splitter that follows because our tests have shown | |
484 | ; that this results in a significant reduction in code size - because GCC is | |
485 | ; able to discard any unused part of the addition. We have to annotate the | |
486 | ; patterns with the set and use of the carry flag because otherwise GCC will | |
487 | ; discard parts of the addition when they are actually needed. But we have | |
488 | ; not annotated all the other patterns that set the CARRY flag as doing so | |
489 | ; results in an overall increase in code size[1]. Instead we just *hope* | |
490 | ; that GCC will not move a carry-setting instruction in between the first | |
491 | ; and second adds. | |
492 | ; | |
493 | ; So far our experiments have shown that GCC is likely to move MOV and CMP | |
494 | ; instructions in between the two adds, but not other instructions. MOV is | |
495 | ; safe, CMP is not. So we have annotated the CMP patterns and left the | |
496 | ; subtract, shift and other add patterns alone. At the moment this is | |
497 | ; working, but with future changes to the generic parts of GCC that might | |
498 | ; change. | |
499 | ; | |
500 | ; [1] It is not clear exactly why the code size increases. The cause appears | |
501 | ; to be that reload is more prevelent to spilling a variable onto the stack | |
502 | ; but why it does this is unknown. Possibly the additional CLOBBERs necessary | |
503 | ; to correctly annotate the other patterns makes reload think that there is | |
504 | ; increased register pressure. Or possibly reload does not handle ADD patterns | |
505 | ; that are not single_set() very well. | |
506 | ||
28987d8b JL |
507 | ; match_operand 3 is likely to be the same as op2 most of the time - except |
508 | ; when op2 is a post_inc and we have stripped the post_inc from match_operand 3 | |
509 | ||
f6a83b4a | 510 | (define_insn "addhi3_cy" |
28987d8b JL |
511 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
512 | (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 513 | (match_operand:HI 2 "msp430_nonimmediate_operand" "rYsYxi,rm"))) |
f6a83b4a DD |
514 | (set (reg:BI CARRY) |
515 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
28987d8b | 516 | (zero_extend:SI (match_operand:HI 3 "msp430_nonimmediate_operand" "rYsYxi,rm"))) |
f6a83b4a DD |
517 | (const_int 16)))) |
518 | ] | |
519 | "" | |
520 | "@ | |
40ada30a | 521 | ADD\t%2, %1 ; cy |
8682b1a5 | 522 | ADDX\t%2, %1 ; cy" |
546c8f95 JL |
523 | [(set_attr "type" "triple")] |
524 | ) | |
f6a83b4a DD |
525 | |
526 | (define_insn "addhi3_cy_i" | |
28987d8b JL |
527 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=r,rm") |
528 | (plus:HI (match_operand:HI 1 "general_operand" "%0,0") | |
d4f283a1 | 529 | (match_operand:HI 2 "immediate_operand" "i,i"))) |
f6a83b4a DD |
530 | (set (reg:BI CARRY) |
531 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
532 | (match_operand 3 "immediate_operand" "i,i")) | |
533 | (const_int 16)))) | |
534 | ] | |
535 | "" | |
536 | "@ | |
40ada30a NC |
537 | ADD\t%2, %1 ; cy |
538 | ADD%X0\t%2, %1 ; cy" | |
546c8f95 JL |
539 | [(set_attr "type" "triple")] |
540 | ) | |
f6a83b4a DD |
541 | |
542 | ; Version of addhi that adds the carry, for SImode adds. | |
543 | (define_insn "addchi4_cy" | |
28987d8b JL |
544 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
545 | (plus:HI (plus:HI (match_operand:HI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 546 | (match_operand:HI 2 "msp430_general_operand" "riYsYx,rmi")) |
f6a83b4a DD |
547 | (zero_extend:HI (reg:BI CARRY)))) |
548 | ] | |
549 | "" | |
550 | "@ | |
40ada30a | 551 | ADDC\t%2, %1 |
8682b1a5 | 552 | ADDCX\t%2, %1" |
546c8f95 JL |
553 | [(set_attr "type" "triple")] |
554 | ) | |
f6a83b4a DD |
555 | |
556 | ; Split an SImode add into two HImode adds, keeping track of the carry | |
557 | ; so that gcc knows when it can and can't optimize away the two | |
558 | ; halves. | |
28987d8b JL |
559 | ; We use the ugly predicate "msp430_nonsubregnonpostinc_or_imm_operand" to |
560 | ; enforce the position of a post_inc into op2 if present | |
f6a83b4a | 561 | (define_split |
28987d8b JL |
562 | [(set (match_operand:SI 0 "msp430_nonsubreg_dst_operand") |
563 | (plus:SI (match_operand:SI 1 "msp430_nonsubregnonpostinc_or_imm_operand") | |
9c5f6203 | 564 | (match_operand:SI 2 "msp430_nonsubreg_or_imm_operand"))) |
f6a83b4a DD |
565 | ] |
566 | "" | |
28987d8b | 567 | [(parallel [(set (match_operand:HI 3 "msp430_general_dst_nonv_operand" "=&rm") |
f6a83b4a DD |
568 | (plus:HI (match_dup 4) |
569 | (match_dup 5))) | |
570 | (set (reg:BI CARRY) | |
571 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 4)) | |
572 | (match_dup 9)) | |
573 | (const_int 16)))) | |
574 | ]) | |
28987d8b | 575 | (set (match_operand:HI 6 "msp430_general_dst_nonv_operand" "=&rm") |
f6a83b4a DD |
576 | (plus:HI (plus:HI (match_dup 7) |
577 | (match_dup 8)) | |
578 | (zero_extend:HI (reg:BI CARRY)))) | |
579 | ] | |
580 | " | |
53f45082 JL |
581 | if (msp430_split_addsi (operands)) |
582 | FAIL; | |
583 | " | |
546c8f95 | 584 | ) |
f6a83b4a DD |
585 | |
586 | ||
587 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
588 | (define_insn "subpsi3" | |
28987d8b JL |
589 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r, rm, &?r, ?&r") |
590 | (minus:PSI (match_operand:PSI 1 "general_operand" "0, 0, !r, !i") | |
591 | (match_operand:PSI 2 "general_operand" "rLs, rmi, rmi, r")))] | |
f6a83b4a DD |
592 | "" |
593 | "@ | |
594 | SUBA\t%2, %0 | |
595 | SUBX.A\t%2, %0 | |
596 | MOVX.A\t%1, %0 { SUBX.A\t%2, %0 | |
597 | MOVX.A\t%1, %0 { SUBA\t%2, %0" | |
546c8f95 JL |
598 | [(set_attr "type" "triple") |
599 | (set_attr "extension" "a,x,x,x") | |
600 | (set_attr "length_multiplier" "1,1,2,2")] | |
f6a83b4a DD |
601 | ) |
602 | ||
603 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
604 | (define_insn "subqi3" | |
28987d8b | 605 | [(set (match_operand:QI 0 "msp430_general_dst_nonv_operand" "=rYsYx, rm, &?r, ?&r") |
f6a83b4a | 606 | (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i") |
8682b1a5 | 607 | (match_operand:QI 2 "general_operand" " riYsYx, rmi, rmi, r")))] |
f6a83b4a DD |
608 | "" |
609 | "@ | |
610 | SUB.B\t%2, %0 | |
8682b1a5 JL |
611 | SUBX.B\t%2, %0 |
612 | MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0 | |
f6a83b4a | 613 | MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" |
546c8f95 JL |
614 | [(set_attr "length_multiplier" "1,1,2,2") |
615 | (set_attr "type" "triple")] | |
f6a83b4a DD |
616 | ) |
617 | ||
618 | ;; Alternatives 2 and 3 are to handle cases generated by reload. | |
619 | (define_insn "subhi3" | |
28987d8b | 620 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rYsYx, rm, &?r, ?&r") |
f6a83b4a | 621 | (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i") |
8682b1a5 | 622 | (match_operand:HI 2 "general_operand" " riYsYx, rmi, rmi, r")))] |
f6a83b4a DD |
623 | "" |
624 | "@ | |
625 | SUB.W\t%2, %0 | |
8682b1a5 JL |
626 | SUBX.W\t%2, %0 |
627 | MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0 | |
f6a83b4a | 628 | MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" |
546c8f95 JL |
629 | [(set_attr "length_multiplier" "1,1,2,2") |
630 | (set_attr "type" "triple")] | |
f6a83b4a DD |
631 | ) |
632 | ||
633 | (define_insn "subsi3" | |
28987d8b JL |
634 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=&rYsYx,m") |
635 | (minus:SI (match_operand:SI 1 "general_operand" "0,0") | |
8682b1a5 | 636 | (match_operand:SI 2 "general_operand" "riYsYx,mi")))] |
f6a83b4a | 637 | "" |
8682b1a5 JL |
638 | "@ |
639 | SUB\t%L2, %L0 { SUBC\t%H2, %H0 | |
640 | SUBX\t%L2, %L0 { SUBCX\t%H2, %H0" | |
546c8f95 JL |
641 | [(set_attr "length_multiplier" "2") |
642 | (set_attr "type" "triple")] | |
f6a83b4a DD |
643 | ) |
644 | ||
645 | (define_insn "*bic<mode>_cg" | |
28987d8b | 646 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYs,m") |
8a896995 | 647 | (and:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0") |
f6a83b4a DD |
648 | (match_operand 2 "msp430_inv_constgen_operator" "n,n")))] |
649 | "" | |
650 | "@ | |
51ac3042 NC |
651 | BIC%x0%b0\t#%I2, %0 |
652 | BIC%X0%b0\t#%I2, %0" | |
546c8f95 JL |
653 | [(set_attr "length" "2") ; Smaller length achieved by using constant generator |
654 | (set_attr "type" "double")] | |
f6a83b4a DD |
655 | ) |
656 | ||
657 | (define_insn "bic<mode>3" | |
28987d8b | 658 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
8a896995 | 659 | (and:QHI (not:QHI (match_operand:QHI 1 "msp430_general_operand" "rYsYx,rmn")) |
28987d8b | 660 | (match_operand:QHI 2 "msp430_general_operand" "0,0")))] |
f6a83b4a DD |
661 | "" |
662 | "@ | |
51ac3042 | 663 | BIC%x0%b0\t%1, %0 |
8682b1a5 | 664 | BICX%b0\t%1, %0" |
546c8f95 | 665 | [(set_attr "type" "double")] |
f6a83b4a DD |
666 | ) |
667 | ||
668 | (define_insn "and<mode>3" | |
28987d8b JL |
669 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=r,rYsYx,rm") |
670 | (and:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0,0") | |
8a896995 | 671 | (match_operand:QHI 2 "msp430_general_operand" "N,riYsYx,rmi")))] |
f6a83b4a DD |
672 | "" |
673 | "@ | |
3f02735b | 674 | AND%x0.B\t%2, %0 |
51ac3042 | 675 | AND%x0%b0\t%2, %0 |
8682b1a5 | 676 | ANDX%b0\t%2, %0" |
546c8f95 | 677 | [(set_attr "type" "triple")] |
f6a83b4a DD |
678 | ) |
679 | ||
680 | (define_insn "ior<mode>3" | |
28987d8b JL |
681 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
682 | (ior:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 683 | (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
684 | "" |
685 | "@ | |
51ac3042 | 686 | BIS%x0%b0\t%2, %0 |
8682b1a5 | 687 | BISX%b0\t%2, %0" |
546c8f95 | 688 | [(set_attr "type" "triple")] |
f6a83b4a DD |
689 | ) |
690 | ||
691 | (define_insn "xor<mode>3" | |
28987d8b JL |
692 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYsYx,rm") |
693 | (xor:QHI (match_operand:QHI 1 "msp430_general_operand" "%0,0") | |
8a896995 | 694 | (match_operand:QHI 2 "msp430_general_operand" "riYsYx,rmi")))] |
f6a83b4a DD |
695 | "" |
696 | "@ | |
51ac3042 | 697 | XOR%x0%b0\t%2, %0 |
8682b1a5 | 698 | XORX%b0\t%2, %0" |
546c8f95 | 699 | [(set_attr "type" "triple")] |
f6a83b4a DD |
700 | ) |
701 | ||
702 | ;; Macro : XOR #~0, %0 | |
703 | (define_insn "one_cmpl<mode>2" | |
28987d8b JL |
704 | [(set (match_operand:QHI 0 "msp430_general_dst_operand" "=rYs,m") |
705 | (not:QHI (match_operand:QHI 1 "msp430_general_operand" "0,0")))] | |
f6a83b4a DD |
706 | "" |
707 | "@ | |
51ac3042 NC |
708 | INV%x0%b0\t%0 |
709 | INV%X0%b0\t%0" | |
546c8f95 | 710 | [(set_attr "type" "double")] |
f6a83b4a DD |
711 | ) |
712 | ||
713 | (define_insn "extendqihi2" | |
28987d8b JL |
714 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYs,m") |
715 | (sign_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,0")))] | |
f6a83b4a DD |
716 | "" |
717 | "@ | |
718 | SXT%X0\t%0 | |
719 | SXT%X0\t%0" | |
546c8f95 | 720 | [(set_attr "type" "single")] |
f6a83b4a DD |
721 | ) |
722 | ||
aa360dd1 JL |
723 | (define_insn "extendqipsi2" |
724 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,m") | |
725 | (sign_extend:PSI (match_operand:QI 1 "msp430_general_operand" "0,0")))] | |
726 | "" | |
727 | "@ | |
728 | SXT\t%0 | |
729 | SXTX.A\t%0" | |
546c8f95 JL |
730 | [(set_attr "type" "single") |
731 | (set_attr "extension" "none,x")] | |
aa360dd1 JL |
732 | ) |
733 | ||
a0a9a3fc JL |
734 | ;; ------------------------ |
735 | ;; ZERO EXTEND INSTRUCTIONS | |
736 | ;; Byte-writes to registers clear bits 19:8 | |
737 | ;; * Byte-writes to memory do not affect bits 15:8 | |
738 | ;; Word-writes to registers clear bits 19:16 | |
739 | ;; PSImode writes to memory clear bits 15:4 of the second memory word | |
740 | ;; We define all possible insns since that results in better code than if | |
741 | ;; they are inferred. | |
742 | ;; ------------------------ | |
743 | ||
f6a83b4a | 744 | (define_insn "zero_extendqihi2" |
28987d8b JL |
745 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rYs,r,r,m") |
746 | (zero_extend:HI (match_operand:QI 1 "msp430_general_operand" "0,rYs,m,0")))] | |
f6a83b4a DD |
747 | "" |
748 | "@ | |
749 | AND\t#0xff, %0 | |
3f02735b | 750 | MOV.B\t%1, %0 |
8682b1a5 | 751 | MOV%X1.B\t%1, %0 |
f6a83b4a | 752 | AND%X0\t#0xff, %0" |
546c8f95 | 753 | [(set_attr "type" "double")] |
f6a83b4a DD |
754 | ) |
755 | ||
a0a9a3fc JL |
756 | (define_insn "zero_extendqipsi2" |
757 | [(set (match_operand:PSI 0 "register_operand" "=r,r") | |
758 | (zero_extend:PSI (match_operand:QI 1 "general_operand" "rYs,m")))] | |
759 | "msp430x" | |
760 | "@ | |
761 | MOV.B\t%1, %0 | |
762 | MOV%X1.B\t%1, %0" | |
546c8f95 | 763 | [(set_attr "type" "double")] |
a0a9a3fc JL |
764 | ) |
765 | ||
582b4055 | 766 | (define_insn "zero_extendqisi2" |
a0a9a3fc JL |
767 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r,r") |
768 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,rm")))] | |
582b4055 | 769 | "" |
a0a9a3fc JL |
770 | "@ |
771 | CLR\t%H0 | |
772 | MOV%X1.B\t%1,%L0 { CLR\t%H0" | |
546c8f95 JL |
773 | [(set_attr "extra_length" "2") |
774 | (set_attr "length_multiplier" "1,2") | |
775 | (set_attr "type" "double")] | |
f6a83b4a | 776 | ) |
d7edde11 | 777 | |
f6a83b4a | 778 | (define_insn "zero_extendhipsi2" |
a0a9a3fc JL |
779 | [(set (match_operand:PSI 0 "msp430_general_dst_operand" "=r,r,m") |
780 | (zero_extend:PSI (match_operand:HI 1 "msp430_general_operand" "rYs,m,r")))] | |
781 | "msp430x" | |
85bd3c01 | 782 | "@ |
a0a9a3fc JL |
783 | MOV.W\t%1, %0 |
784 | MOV%X1\t%1, %0 | |
85bd3c01 | 785 | MOVX.A\t%1, %0" |
546c8f95 | 786 | [(set_attr "type" "double")] |
f6a83b4a | 787 | ) |
cac52161 | 788 | |
f6a83b4a | 789 | (define_insn "zero_extendhisi2" |
28987d8b JL |
790 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm,r") |
791 | (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")))] | |
525213a5 | 792 | "" |
bdafd679 | 793 | "@ |
8682b1a5 | 794 | MOV%X0.W\t#0,%H0 |
bdafd679 | 795 | MOV.W\t%1,%L0 { MOV.W\t#0,%H0" |
546c8f95 JL |
796 | [(set_attr "length_multiplier" "1,2") |
797 | (set_attr "type" "double")] | |
f6a83b4a DD |
798 | ) |
799 | ||
800 | (define_insn "zero_extendhisipsi2" | |
28987d8b JL |
801 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r,r") |
802 | (subreg:PSI (zero_extend:SI (match_operand:HI 1 "general_operand" "0,r")) 0))] | |
c32ab325 | 803 | "msp430x" |
f6a83b4a DD |
804 | "@ |
805 | AND.W\t#-1,%0 | |
806 | MOV.W\t%1,%0" | |
546c8f95 JL |
807 | [(set_attr "length" "4,2") |
808 | (set_attr "type" "double")] | |
f6a83b4a DD |
809 | ) |
810 | ||
f6a83b4a DD |
811 | ; Nasty - we are sign-extending a 20-bit PSI value in one register into |
812 | ; two adjacent 16-bit registers to make an SI value. There is no MSP430X | |
813 | ; instruction that will do this, so we push the 20-bit value onto the stack | |
814 | ; and then pop it off as two 16-bit values. | |
815 | ; | |
816 | ; FIXME: The MSP430X documentation does not specify if zero-extension or | |
817 | ; sign-extension happens when the 20-bit value is pushed onto the stack. | |
818 | ; It is probably zero-extension, but if not this pattern will not work | |
819 | ; when the PSI value is negative.. | |
820 | ; | |
821 | ; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A.... | |
8f0e7f6f NC |
822 | ; |
823 | ; Note: We use a + constraint on operand 0 as otherwise GCC gets confused | |
824 | ; about extending a single PSI mode register into a pair of SImode registers | |
825 | ; with the same starting register. It thinks that the upper register of | |
826 | ; the pair is unused and so it can clobber it. Try compiling 20050826-2.c | |
827 | ; at -O2 to see this. | |
f6a83b4a | 828 | |
a0a9a3fc | 829 | ; FIXME we can use MOVA for r->m if m is &abs20 or z16(rdst) |
f6a83b4a | 830 | (define_insn "zero_extendpsisi2" |
a0a9a3fc JL |
831 | [(set (match_operand:SI 0 "register_operand" "+r,m") |
832 | (zero_extend:SI (match_operand:PSI 1 "register_operand" "r,r")))] | |
f6a83b4a | 833 | "" |
a0a9a3fc JL |
834 | "@ |
835 | * if (REGNO (operands[1]) == SP_REGNO) \ | |
836 | /* If the source register is the stack pointer, the value \ | |
837 | stored in the stack slot will be the value *after* the \ | |
838 | stack pointer has been decremented. So allow for that \ | |
839 | here. */ \ | |
840 | 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\"; \ | |
841 | else \ | |
d4f283a1 | 842 | return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\"; |
a0a9a3fc | 843 | MOVX.A %1, %0" |
546c8f95 JL |
844 | [(set (attr "length") |
845 | (cond [(match_test "REGNO (operands[1]) == SP_REGNO") | |
846 | (const_int 18) | |
847 | (eq_attr "alternative" "1") | |
848 | (const_int 6)] | |
849 | (const_int 10))) | |
850 | (set_attr "type" "double")] | |
a0a9a3fc JL |
851 | ) |
852 | ||
853 | ;; Below are unnamed insn patterns to catch pointer manipulation insns | |
854 | ;; generated by combine. | |
855 | ;; We get large code size bloat when a PSImode pointer is stored in | |
856 | ;; memory, so we try to avoid that where possible and keep point manipulation | |
857 | ;; between registers. | |
858 | ; FIXME many of these should be unnnecessary once combine deals with | |
859 | ; (sign_extend (zero_extend)) or (sign_extend (subreg)) BZ 91865. | |
860 | ||
861 | ;; This is just another way of writing movqipsi/zero_extendqipsi | |
862 | (define_insn "" | |
863 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
864 | (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))] | |
865 | "msp430x" | |
866 | "MOV%X1.B\t%1, %0" | |
546c8f95 | 867 | [(set_attr "type" "double")] |
40ada30a NC |
868 | ) |
869 | ||
a0a9a3fc JL |
870 | (define_insn "" |
871 | [(set (match_operand:PSI 0 "register_operand" "=r,r") | |
872 | (sign_extend:PSI (zero_extend:HI (match_operand:QI 1 "general_operand" "rYs,m"))))] | |
873 | "msp430x" | |
874 | "@ | |
875 | MOV.B\t%1, %0 | |
876 | MOV%X1.B\t%1, %0" | |
546c8f95 | 877 | [(set_attr "type" "double")] |
a0a9a3fc JL |
878 | ) |
879 | ||
703e049a JL |
880 | ;; The next three insns emit identical assembly code. |
881 | ;; They take a QImode and shift it in SImode. Only shift counts <= 8 | |
882 | ;; are handled since that is the simple case where the high 16-bits (i.e. the | |
883 | ;; high register) are always 0. | |
a0a9a3fc | 884 | (define_insn "" |
703e049a JL |
885 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
886 | (ashift:SI (zero_extend:SI (match_operand:QI 1 "general_operand" "0,rm,rm")) | |
887 | (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] | |
a0a9a3fc | 888 | "msp430x" |
703e049a JL |
889 | "@ |
890 | RLAM.W %2, %L0 { CLR %H0 | |
891 | MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 | |
892 | MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" | |
546c8f95 JL |
893 | [(set_attr "length" "4,*,*") |
894 | (set_attr "extra_length" "0,4,6") | |
895 | (set_attr "type" "double")] | |
a0a9a3fc JL |
896 | ) |
897 | ||
a0a9a3fc | 898 | (define_insn "" |
703e049a JL |
899 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
900 | (ashift:SI (zero_extend:SI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0)) | |
901 | (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] | |
a0a9a3fc | 902 | "msp430x" |
703e049a JL |
903 | "@ |
904 | RLAM.W %2, %L0 { CLR %H0 | |
905 | MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 | |
906 | MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" | |
546c8f95 JL |
907 | [(set_attr "length" "4,*,*") |
908 | (set_attr "extra_length" "0,4,6") | |
909 | (set_attr "type" "double")] | |
a0a9a3fc JL |
910 | ) |
911 | ||
912 | ;; Same as above but with a NOP sign_extend round the subreg | |
913 | (define_insn "" | |
703e049a JL |
914 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
915 | (ashift:SI (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0))) | |
916 | (match_operand:HI 2 "const_1_to_8_operand" "M,M,i")))] | |
a0a9a3fc | 917 | "msp430x" |
703e049a JL |
918 | "@ |
919 | RLAM.W %2, %L0 { CLR %H0 | |
920 | MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 | |
921 | MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" | |
546c8f95 JL |
922 | [(set_attr "length" "4,*,*") |
923 | (set_attr "extra_length" "0,4,6") | |
924 | (set_attr "type" "double")] | |
a0a9a3fc JL |
925 | ) |
926 | ||
927 | (define_insn "" | |
928 | [(set (match_operand:SI 0 "register_operand" "=r") | |
929 | (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))))] | |
930 | "msp430x" | |
931 | "MOV%X1.B %1, %L0 { CLR %H0" | |
546c8f95 JL |
932 | [(set_attr "extra_length" "4") |
933 | (set_attr "type" "double")] | |
a0a9a3fc JL |
934 | ) |
935 | ||
936 | (define_insn "" | |
703e049a JL |
937 | [(set (match_operand:PSI 0 "register_operand" "=r,r,r") |
938 | (ashift:PSI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "0,rm,rm") 0)) | |
939 | (match_operand:HI 2 "const_1_to_19_operand" "M,M,i")))] | |
a0a9a3fc | 940 | "msp430x" |
703e049a JL |
941 | "@ |
942 | RLAM.W %2, %0 | |
943 | MOV%X1.B %1, %0 { RLAM.W %2, %0 | |
944 | MOV%X1.B %1, %0 { RPT %2 { RLAX.A %0" | |
546c8f95 JL |
945 | [(set_attr "length" "2,*,*") |
946 | (set_attr "extra_length" "0,2,4") | |
947 | (set_attr "type" "double")] | |
a0a9a3fc JL |
948 | ) |
949 | ;; END msp430 pointer manipulation combine insn patterns | |
582b4055 JL |
950 | |
951 | ;; Eliminate extraneous zero-extends mysteriously created by gcc. | |
952 | (define_peephole2 | |
953 | [(set (match_operand:HI 0 "register_operand") | |
954 | (zero_extend:HI (match_operand:QI 1 "general_operand"))) | |
955 | (set (match_operand:HI 2 "register_operand") | |
956 | (zero_extend:HI (match_operand:QI 3 "register_operand")))] | |
957 | "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])" | |
958 | [(set (match_dup 0) | |
959 | (zero_extend:HI (match_dup 1)))] | |
960 | ) | |
961 | ||
962 | (define_insn "truncpsihi2" | |
963 | [(set (match_operand:HI 0 "msp430_general_dst_operand" "=rm") | |
964 | (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] | |
965 | "" | |
966 | "MOVX\t%1, %0" | |
546c8f95 JL |
967 | [(set_attr "extension" "m") |
968 | (set_attr "type" "double")] | |
582b4055 JL |
969 | ) |
970 | ||
971 | (define_insn "extendhisi2" | |
972 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") | |
973 | (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))] | |
974 | "" | |
546c8f95 JL |
975 | { msp430x_extendhisi (operands, 0); return ""; } |
976 | [(set (attr "length") | |
977 | (symbol_ref "msp430x_extendhisi (operands, 1)")) | |
978 | (set_attr "type" "double")] | |
582b4055 JL |
979 | ) |
980 | ||
981 | (define_insn "extendhipsi2" | |
982 | [(set (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") | |
983 | (subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))] | |
984 | "msp430x" | |
985 | "RLAM.A #4, %0 { RRAM.A #4, %0" | |
546c8f95 JL |
986 | [(set_attr "length_multiplier" "2") |
987 | (set_attr "extension" "m") | |
988 | (set_attr "type" "double")] | |
582b4055 JL |
989 | ) |
990 | ||
991 | ;; Look for cases where integer/pointer conversions are suboptimal due | |
992 | ;; to missing patterns, despite us not having opcodes for these | |
993 | ;; patterns. Doing these manually allows for alternate optimization | |
994 | ;; paths. | |
995 | ||
996 | (define_insn "extend_and_shift1_hipsi2" | |
997 | [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0) | |
998 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) | |
999 | (const_int 1)))] | |
1000 | "msp430x" | |
1001 | "RLAM.A #4, %0 { RRAM.A #3, %0" | |
546c8f95 JL |
1002 | [(set_attr "length_multiplier" "2") |
1003 | (set_attr "extension" "m") | |
1004 | (set_attr "type" "double")] | |
582b4055 JL |
1005 | ) |
1006 | ||
1007 | (define_insn "extend_and_shift2_hipsi2" | |
1008 | [(set (subreg:SI (match_operand:PSI 0 "msp430_general_dst_nonv_operand" "=r") 0) | |
1009 | (ashift:SI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) | |
1010 | (const_int 2)))] | |
1011 | "msp430x" | |
1012 | "RLAM.A #4, %0 { RRAM.A #2, %0" | |
546c8f95 JL |
1013 | [(set_attr "length_multiplier" "2") |
1014 | (set_attr "extension" "m") | |
1015 | (set_attr "type" "double")] | |
582b4055 JL |
1016 | ) |
1017 | ||
40ada30a NC |
1018 | ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t). |
1019 | ;; Since (we assume) pushing a 20-bit value onto the stack zero-extends | |
1020 | ;; it, we use a different method here. | |
1021 | ||
1022 | (define_insn "extendpsisi2" | |
1023 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1024 | (sign_extend:SI (match_operand:PSI 1 "register_operand" "r")))] | |
c32ab325 | 1025 | "msp430x" |
40ada30a NC |
1026 | "* |
1027 | /* The intention here is that we copy the bottom 16-bits of | |
1028 | %1 into %L0 (zeroing the top four bits). Then we copy the | |
1029 | entire 20-bits of %1 into %H0 and then arithmetically shift | |
1030 | it right by 16 bits, to get the top four bits of the pointer | |
1031 | sign-extended in %H0. */ | |
1032 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
d4f283a1 | 1033 | 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 | 1034 | else |
d4f283a1 | 1035 | 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 | 1036 | " |
546c8f95 JL |
1037 | [(set_attr "length" "10") |
1038 | (set_attr "type" "double")] | |
f6a83b4a DD |
1039 | ) |
1040 | ||
1041 | ; See the movsipsi2 pattern above for another way that GCC performs this | |
1042 | ; conversion. | |
1043 | (define_insn "truncsipsi2" | |
1044 | [(set (match_operand:PSI 0 "register_operand" "=r") | |
1045 | (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] | |
1046 | "" | |
d4f283a1 | 1047 | "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0" |
546c8f95 JL |
1048 | [(set_attr "length" "6") |
1049 | (set_attr "type" "single")] | |
f6a83b4a DD |
1050 | ) |
1051 | ||
1052 | ;;------------------------------------------------------------ | |
1053 | ;; Shift Functions | |
1054 | ||
1055 | ;; Note: We do not use the RPT ... SHIFT instruction sequence | |
1056 | ;; when the repeat count is in a register, because even though RPT | |
1057 | ;; accepts counts in registers, it does not work if the count is | |
1058 | ;; zero, and the actual count in the register has to be one less | |
1059 | ;; than the required number of iterations. We could encode a | |
1060 | ;; seqeunce like this: | |
1061 | ;; | |
1062 | ;; bit #0xf, Rn | |
1063 | ;; bz 1f | |
1064 | ;; dec Rn | |
1065 | ;; rpt Rn | |
1066 | ;; <shift> Rm | |
1067 | ;; inc Rn | |
1068 | ;; 1: | |
1069 | ;; | |
1070 | ;; But is longer than calling a helper function, and we are mostly | |
1071 | ;; concerned with code size. FIXME: Maybe enable a sequence like | |
1072 | ;; this at -O3 and above ? | |
1073 | ;; | |
1074 | ;; Note - we ignore shift counts of less than one or more than 15. | |
1075 | ;; This is permitted by the ISO C99 standard as such shifts result | |
9c582551 | 1076 | ;; in "undefined" behavior. [6.5.7 (3)] |
703e049a JL |
1077 | ;; |
1078 | ;; We avoid emitting insns in msp430_expand_shift, since we would have to handle | |
1079 | ;; many extra cases such as op0 != op1, or, op0 or op1 in memory. Instead we | |
1080 | ;; let reload coerce op0 and op1 into the same register. | |
f6a83b4a | 1081 | |
703e049a JL |
1082 | (define_expand "<shift_insn><mode>3" |
1083 | [(set (match_operand:HDI 0 "msp430_general_dst_nonv_operand") | |
1084 | (any_shift:HDI (match_operand:HDI 1 "general_operand") | |
1085 | (match_operand:HDI 2 "general_operand")))] | |
0fcc78f7 JL |
1086 | "" |
1087 | { | |
703e049a JL |
1088 | if (msp430_expand_shift (<CODE>, <MODE>mode, operands)) |
1089 | DONE; | |
1090 | /* Otherwise, fallthrough. */ | |
0fcc78f7 JL |
1091 | } |
1092 | ) | |
1093 | ||
703e049a JL |
1094 | ;; All 430 HImode constant shifts |
1095 | (define_insn "<shift_insn>hi3_430" | |
1096 | [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=rm") | |
1097 | (any_shift:HI (match_operand:HI 1 "general_operand" "0") | |
1098 | (match_operand:HI 2 "const_int_operand" "n")))] | |
1099 | "!msp430x" | |
546c8f95 JL |
1100 | "* msp430_output_asm_shift_insns (<CODE>, HImode, operands, false); return \"\";" |
1101 | [(set (attr "length") | |
1102 | (symbol_ref "msp430_output_asm_shift_insns (<CODE>, HImode, operands, true)")) | |
1103 | (set_attr "type" "single")] | |
f6a83b4a DD |
1104 | ) |
1105 | ||
703e049a JL |
1106 | ;; All 430 and 430X SImode constant shifts |
1107 | (define_insn "<shift_insn>si3_const" | |
1108 | [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") | |
1109 | (any_shift:SI (match_operand:SI 1 "general_operand" "0") | |
1110 | (match_operand:SI 2 "const_int_operand" "n")))] | |
f6a83b4a | 1111 | "" |
546c8f95 JL |
1112 | "* msp430_output_asm_shift_insns (<CODE>, SImode, operands, false); return \"\";" |
1113 | [(set (attr "length") | |
1114 | (symbol_ref "msp430_output_asm_shift_insns (<CODE>, SImode, operands, true)")) | |
1115 | (set_attr "type" "single")] | |
f6a83b4a DD |
1116 | ) |
1117 | ||
703e049a JL |
1118 | (define_insn "ashl<mode>3_430x" |
1119 | [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") | |
1120 | (ashift:HPSI (match_operand:HPSI 1 "general_operand" "0 ,0,0,0") | |
1121 | (match_operand:HPSI 2 "const_int_operand" "M ,P,K,i")))] | |
f6a83b4a | 1122 | "msp430x" |
703e049a JL |
1123 | "@ |
1124 | RLAM%b0\t%2, %0 | |
1125 | RPT\t%2 { RLAX%b0\t%0 | |
1126 | RPT\t#16 { RLAX%b0\t%0 { RPT\t%W2 { RLAX%b0\t%0 | |
1127 | # undefined behavior left shift of %1 by %2" | |
546c8f95 JL |
1128 | [(set_attr "length" "2,4,8,0") |
1129 | (set_attr "type" "single")] | |
f6a83b4a DD |
1130 | ) |
1131 | ||
703e049a JL |
1132 | (define_insn "ashr<mode>3_430x" |
1133 | [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") | |
1134 | (ashiftrt:HPSI (match_operand:HPSI 1 "general_operand" "0,0,0,0") | |
1135 | (match_operand:HPSI 2 "const_int_operand" "M,P,K,i")))] | |
f6a83b4a | 1136 | "msp430x" |
703e049a JL |
1137 | "@ |
1138 | RRAM%b0\t%2, %0 | |
1139 | RPT\t%2 { RRAX%b0\t%0 | |
1140 | RPT\t#16 { RRAX%b0\t%0 { RPT\t%W2 { RRAX%b0\t%0 | |
1141 | # undefined behavior arithmetic right shift of %1 by %2" | |
546c8f95 JL |
1142 | [(set_attr "length" "2,4,8,0") |
1143 | (set_attr "type" "single")] | |
f6a83b4a DD |
1144 | ) |
1145 | ||
703e049a JL |
1146 | (define_insn "lshr<mode>3_430x" |
1147 | [(set (match_operand:HPSI 0 "msp430_general_dst_nonv_operand" "=r,r,r,r") | |
1148 | (lshiftrt:HPSI (match_operand:HPSI 1 "general_operand" "0,0,0,0") | |
1149 | (match_operand:HPSI 2 "const_int_operand" "M,P,K,i")))] | |
f6a83b4a | 1150 | "msp430x" |
703e049a JL |
1151 | "@ |
1152 | RRUM%b0\t%2, %0 | |
1153 | RPT\t%2 { RRUX%b0\t%0 | |
1154 | RPT\t#16 { RRUX%b0\t%0 { RPT\t%W2 { RRUX%b0\t%0 | |
1155 | # undefined behavior logical right shift of %1 by %2" | |
546c8f95 JL |
1156 | [(set_attr "length" "2,4,8,0") |
1157 | (set_attr "type" "single")] | |
0fcc78f7 JL |
1158 | ) |
1159 | ||
f6a83b4a DD |
1160 | ;;------------------------------------------------------------ |
1161 | ;; Function Entry/Exit | |
1162 | ||
1163 | (define_expand "prologue" | |
1164 | [(const_int 0)] | |
1165 | "" | |
1166 | "msp430_expand_prologue (); DONE;" | |
546c8f95 | 1167 | ) |
f6a83b4a DD |
1168 | |
1169 | (define_expand "epilogue" | |
1170 | [(const_int 0)] | |
1171 | "" | |
1172 | "msp430_expand_epilogue (0); DONE;" | |
546c8f95 | 1173 | ) |
f6a83b4a | 1174 | |
f6a83b4a | 1175 | (define_insn "epilogue_helper" |
07432a80 | 1176 | [(set (pc) |
546c8f95 | 1177 | (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)) |
07432a80 | 1178 | (return)] |
546c8f95 | 1179 | "!msp430x" |
fb28dac0 | 1180 | "BR%Q0\t#__mspabi_func_epilog_%J0" |
546c8f95 JL |
1181 | [(set_attr "length" "2")] |
1182 | ) | |
f6a83b4a | 1183 | |
f6a83b4a DD |
1184 | (define_insn "prologue_start_marker" |
1185 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] | |
1186 | "" | |
1187 | "; start of prologue" | |
546c8f95 JL |
1188 | [(set_attr "length" "0")] |
1189 | ) | |
f6a83b4a DD |
1190 | |
1191 | (define_insn "prologue_end_marker" | |
1192 | [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] | |
1193 | "" | |
1194 | "; end of prologue" | |
546c8f95 JL |
1195 | [(set_attr "length" "0")] |
1196 | ) | |
f6a83b4a DD |
1197 | |
1198 | (define_insn "epilogue_start_marker" | |
1199 | [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] | |
1200 | "" | |
1201 | "; start of epilogue" | |
546c8f95 JL |
1202 | [(set_attr "length" "0")] |
1203 | ) | |
f6a83b4a | 1204 | |
4f50b9ff DD |
1205 | ;; This makes the linker add a call to exit() after the call to main() |
1206 | ;; in crt0 | |
1207 | (define_insn "msp430_refsym_need_exit" | |
1208 | [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)] | |
1209 | "" | |
1210 | ".refsym\t__crt0_call_exit" | |
546c8f95 JL |
1211 | [(set_attr "length" "0")] |
1212 | ) | |
4f50b9ff | 1213 | |
f6a83b4a DD |
1214 | ;;------------------------------------------------------------ |
1215 | ;; Jumps | |
1216 | ||
1217 | (define_expand "call" | |
1218 | [(call:HI (match_operand 0 "") | |
40ada30a | 1219 | (match_operand 1 ""))] |
f6a83b4a DD |
1220 | "" |
1221 | "" | |
1222 | ) | |
1223 | ||
1224 | (define_insn "call_internal" | |
fb28dac0 | 1225 | [(call (mem:HI (match_operand 0 "general_operand" "rYci")) |
f6a83b4a DD |
1226 | (match_operand 1 ""))] |
1227 | "" | |
51ac3042 | 1228 | "CALL%Q0\t%0" |
546c8f95 JL |
1229 | [(set_attr "extension" "none") |
1230 | (set_attr "type" "single")] | |
f6a83b4a DD |
1231 | ) |
1232 | ||
1233 | (define_expand "call_value" | |
1234 | [(set (match_operand 0 "register_operand") | |
1235 | (call:HI (match_operand 1 "general_operand") | |
1236 | (match_operand 2 "")))] | |
1237 | "" | |
1238 | "" | |
1239 | ) | |
1240 | ||
1241 | (define_insn "call_value_internal" | |
1242 | [(set (match_operand 0 "register_operand" "=r") | |
fb28dac0 | 1243 | (call (mem:HI (match_operand 1 "general_operand" "rYci")) |
f6a83b4a DD |
1244 | (match_operand 2 "")))] |
1245 | "" | |
51ac3042 | 1246 | "CALL%Q0\t%1" |
546c8f95 JL |
1247 | [(set_attr "extension" "none") |
1248 | (set_attr "type" "single")] | |
f6a83b4a DD |
1249 | ) |
1250 | ||
8a896995 | 1251 | (define_insn "msp430_return" |
f6a83b4a DD |
1252 | [(return)] |
1253 | "" | |
cad055a4 | 1254 | { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); } |
546c8f95 | 1255 | [(set_attr "length" "2")] |
f6a83b4a DD |
1256 | ) |
1257 | ||
1258 | ;; This pattern is NOT, as expected, a return pattern. It's called | |
1259 | ;; before reload and must only store its operands, and emit a | |
1260 | ;; placeholder where the epilog needs to be. AFTER reload, the | |
1261 | ;; placeholder should get expanded into a regular-type epilogue that | |
1262 | ;; also does the EH return. | |
1263 | (define_expand "eh_return" | |
40ada30a | 1264 | [(match_operand:HI 0 "")] |
f6a83b4a DD |
1265 | "" |
1266 | "msp430_expand_eh_return (operands[0]); | |
1267 | emit_jump_insn (gen_msp430_eh_epilogue ()); | |
1268 | emit_barrier (); | |
1269 | DONE;" | |
1270 | ) | |
1271 | ||
1272 | ;; This is the actual EH epilogue. We emit it in the pattern above, | |
1273 | ;; before reload, and convert it to a real epilogue after reload. | |
1274 | (define_insn_and_split "msp430_eh_epilogue" | |
1275 | [(eh_return)] | |
1276 | "" | |
1277 | "#" | |
1278 | "reload_completed" | |
1279 | [(const_int 0)] | |
1280 | "msp430_expand_epilogue (1); DONE;" | |
546c8f95 JL |
1281 | [(set_attr "length" "40")] |
1282 | ) | |
f6a83b4a DD |
1283 | |
1284 | (define_insn "jump" | |
1285 | [(set (pc) | |
1286 | (label_ref (match_operand 0 "" "")))] | |
1287 | "" | |
51ac3042 | 1288 | "BR%Q0\t#%l0" |
546c8f95 | 1289 | [(set_attr "length" "4")] |
f6a83b4a DD |
1290 | ) |
1291 | ||
1292 | ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs | |
1293 | ;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c). | |
1294 | (define_insn "indirect_jump" | |
1295 | [(set (pc) | |
1296 | (match_operand 0 "nonimmediate_operand" "rYl"))] | |
1297 | "" | |
51ac3042 | 1298 | "BR%Q0\t%0" |
546c8f95 JL |
1299 | [(set (attr "length") |
1300 | (if_then_else (match_operand 0 "register_operand" "") | |
1301 | (const_int 2) | |
1302 | (const_int 4)))] | |
f6a83b4a DD |
1303 | ) |
1304 | ||
1305 | ;;------------------------------------------------------------ | |
1306 | ;; Various Conditionals | |
1307 | ||
1308 | (define_expand "cbranch<mode>4" | |
1309 | [(parallel [(set (pc) (if_then_else | |
1310 | (match_operator 0 "" | |
6ff8ab6a | 1311 | [(match_operand:QHI 1 "msp430_general_dst_nonv_operand") |
f6a83b4a DD |
1312 | (match_operand:QHI 2 "general_operand")]) |
1313 | (label_ref (match_operand 3 "" "")) | |
1314 | (pc))) | |
1315 | (clobber (reg:BI CARRY))] | |
1316 | )] | |
1317 | "" | |
1318 | "msp430_fixup_compare_operands (<MODE>mode, operands);" | |
546c8f95 | 1319 | ) |
f6a83b4a DD |
1320 | |
1321 | (define_insn "cbranchpsi4_real" | |
1322 | [(set (pc) (if_then_else | |
1323 | (match_operator 0 "msp430_cmp_operator" | |
6ff8ab6a | 1324 | [(match_operand:PSI 1 "msp430_general_dst_nonv_operand" "r,rYs,rm") |
f6a83b4a | 1325 | (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) |
546c8f95 | 1326 | (label_ref (match_operand 3 "" "")) |
f6a83b4a DD |
1327 | (pc))) |
1328 | (clobber (reg:BI CARRY)) | |
1329 | ] | |
1330 | "" | |
1331 | "@ | |
51ac3042 | 1332 | CMP%Q0\t%2, %1 { J%0\t%l3 |
f6a83b4a DD |
1333 | CMPX.A\t%2, %1 { J%0\t%l3 |
1334 | CMPX.A\t%2, %1 { J%0\t%l3" | |
546c8f95 JL |
1335 | [(set_attr "extra_length" "2") |
1336 | (set_attr "type" "cmp")] | |
1337 | ) | |
f6a83b4a DD |
1338 | |
1339 | (define_insn "cbranchqi4_real" | |
1340 | [(set (pc) (if_then_else | |
1341 | (match_operator 0 "msp430_cmp_operator" | |
6ff8ab6a | 1342 | [(match_operand:QI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm") |
8682b1a5 | 1343 | (match_operand:QI 2 "general_operand" "rYsYxi,rmi")]) |
f6a83b4a DD |
1344 | (label_ref (match_operand 3 "" "")) |
1345 | (pc))) | |
1346 | (clobber (reg:BI CARRY)) | |
1347 | ] | |
1348 | "" | |
1349 | "@ | |
1350 | CMP.B\t%2, %1 { J%0\t%l3 | |
8682b1a5 | 1351 | CMPX.B\t%2, %1 { J%0\t%l3" |
546c8f95 JL |
1352 | [(set_attr "extra_length" "2") |
1353 | (set_attr "type" "cmp")] | |
1354 | ) | |
f6a83b4a DD |
1355 | |
1356 | (define_insn "cbranchhi4_real" | |
1357 | [(set (pc) (if_then_else | |
1358 | (match_operator 0 "msp430_cmp_operator" | |
6ff8ab6a | 1359 | [(match_operand:HI 1 "msp430_general_dst_nonv_operand" "rYsYx,rm") |
8682b1a5 | 1360 | (match_operand:HI 2 "general_operand" "rYsYxi,rmi")]) |
f6a83b4a DD |
1361 | (label_ref (match_operand 3 "" "")) |
1362 | (pc))) | |
1363 | (clobber (reg:BI CARRY)) | |
1364 | ] | |
1365 | "" | |
b4ca70a3 JL |
1366 | "@ |
1367 | CMP.W\t%2, %1 { J%0\t%l3 | |
1368 | CMPX.W\t%2, %1 { J%0\t%l3" | |
546c8f95 JL |
1369 | [(set_attr "extra_length" "2") |
1370 | (set_attr "type" "cmp")] | |
b4ca70a3 | 1371 | ) |
f6a83b4a DD |
1372 | |
1373 | (define_insn "cbranchpsi4_reversed" | |
1374 | [(set (pc) (if_then_else | |
1375 | (match_operator 0 "msp430_reversible_cmp_operator" | |
1376 | [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi") | |
6ff8ab6a | 1377 | (match_operand:PSI 2 "msp430_general_dst_nonv_operand" "r,rYs,rm")]) |
f6a83b4a DD |
1378 | (label_ref (match_operand 3 "" "")) |
1379 | (pc))) | |
1380 | (clobber (reg:BI CARRY)) | |
1381 | ] | |
1382 | "" | |
1383 | "@ | |
51ac3042 | 1384 | CMP%Q0\t%1, %2 { J%R0\t%l3 |
f6a83b4a DD |
1385 | CMPX.A\t%1, %2 { J%R0\t%l3 |
1386 | CMPX.A\t%1, %2 { J%R0\t%l3" | |
546c8f95 JL |
1387 | [(set_attr "extra_length" "2") |
1388 | (set_attr "type" "cmp")] | |
1389 | ) | |
f6a83b4a DD |
1390 | |
1391 | (define_insn "cbranchqi4_reversed" | |
1392 | [(set (pc) (if_then_else | |
1393 | (match_operator 0 "msp430_reversible_cmp_operator" | |
8682b1a5 | 1394 | [(match_operand:QI 1 "general_operand" "rYsYxi,rmi") |
6ff8ab6a | 1395 | (match_operand:QI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")]) |
f6a83b4a DD |
1396 | (label_ref (match_operand 3 "" "")) |
1397 | (pc))) | |
1398 | (clobber (reg:BI CARRY)) | |
1399 | ] | |
1400 | "" | |
1401 | "@ | |
1402 | CMP.B\t%1, %2 { J%R0\t%l3 | |
8682b1a5 | 1403 | CMPX.B\t%1, %2 { J%R0\t%l3" |
546c8f95 JL |
1404 | [(set_attr "extra_length" "2") |
1405 | (set_attr "type" "cmp")] | |
1406 | ) | |
f6a83b4a DD |
1407 | |
1408 | (define_insn "cbranchhi4_reversed" | |
1409 | [(set (pc) (if_then_else | |
1410 | (match_operator 0 "msp430_reversible_cmp_operator" | |
8682b1a5 | 1411 | [(match_operand:HI 1 "general_operand" "rYsYxi,rmi") |
6ff8ab6a | 1412 | (match_operand:HI 2 "msp430_general_dst_nonv_operand" "rYsYx,rm")]) |
f6a83b4a DD |
1413 | (label_ref (match_operand 3 "" "")) |
1414 | (pc))) | |
1415 | (clobber (reg:BI CARRY)) | |
1416 | ] | |
1417 | "" | |
1418 | "@ | |
1419 | CMP.W\t%1, %2 { J%R0\t%l3 | |
8682b1a5 | 1420 | CMPX.W\t%1, %2 { J%R0\t%l3" |
546c8f95 JL |
1421 | [(set_attr "extra_length" "2") |
1422 | (set_attr "type" "cmp")] | |
1423 | ) | |
f6a83b4a | 1424 | |
f6a83b4a DD |
1425 | (define_insn "*bitbranch<mode>4" |
1426 | [(set (pc) (if_then_else | |
28987d8b | 1427 | (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1428 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a | 1429 | (const_int 0)) |
546c8f95 | 1430 | (label_ref (match_operand 2 "" "")) |
f6a83b4a DD |
1431 | (pc))) |
1432 | (clobber (reg:BI CARRY)) | |
1433 | ] | |
1434 | "" | |
1435 | "@ | |
51ac3042 | 1436 | BIT%x0%b0\t%1, %0 { JNE\t%l2 |
8682b1a5 | 1437 | BITX%b0\t%1, %0 { JNE\t%l2" |
546c8f95 JL |
1438 | [(set_attr "extra_length" "2") |
1439 | (set_attr "type" "double")] | |
1440 | ) | |
f6a83b4a DD |
1441 | |
1442 | (define_insn "*bitbranch<mode>4" | |
1443 | [(set (pc) (if_then_else | |
28987d8b | 1444 | (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1445 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a | 1446 | (const_int 0)) |
546c8f95 | 1447 | (label_ref (match_operand 2 "" "")) |
f6a83b4a DD |
1448 | (pc))) |
1449 | (clobber (reg:BI CARRY)) | |
1450 | ] | |
1451 | "" | |
8682b1a5 JL |
1452 | "@ |
1453 | BIT%x0%b0\t%1, %0 { JEQ\t%l2 | |
1454 | BITX%b0\t%1, %0 { JEQ\t%l2" | |
546c8f95 JL |
1455 | [(set_attr "extra_length" "2") |
1456 | (set_attr "type" "double")] | |
1457 | ) | |
f6a83b4a DD |
1458 | |
1459 | (define_insn "*bitbranch<mode>4" | |
1460 | [(set (pc) (if_then_else | |
28987d8b | 1461 | (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1462 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a | 1463 | (const_int 0)) |
546c8f95 | 1464 | (pc) |
f6a83b4a DD |
1465 | (label_ref (match_operand 2 "" "")))) |
1466 | (clobber (reg:BI CARRY)) | |
1467 | ] | |
1468 | "" | |
8682b1a5 JL |
1469 | "@ |
1470 | BIT%x0%b0\t%1, %0 { JNE\t%l2 | |
1471 | BITX%b0\t%1, %0 { JNE\t%l2" | |
546c8f95 JL |
1472 | [(set_attr "extra_length" "2") |
1473 | (set_attr "type" "double")] | |
1474 | ) | |
f6a83b4a DD |
1475 | |
1476 | (define_insn "*bitbranch<mode>4" | |
1477 | [(set (pc) (if_then_else | |
28987d8b | 1478 | (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") |
8a896995 | 1479 | (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) |
f6a83b4a | 1480 | (const_int 0)) |
546c8f95 | 1481 | (pc) |
f6a83b4a DD |
1482 | (label_ref (match_operand 2 "" "")))) |
1483 | (clobber (reg:BI CARRY)) | |
1484 | ] | |
1485 | "" | |
8682b1a5 JL |
1486 | "@ |
1487 | BIT%x0%b0\t%1, %0 { JEQ\t%l2 | |
1488 | BITX%b0\t%1, %0 { JEQ\t%l2" | |
546c8f95 JL |
1489 | [(set_attr "extra_length" "2") |
1490 | (set_attr "type" "double")] | |
1491 | ) | |
f6a83b4a DD |
1492 | |
1493 | ;;------------------------------------------------------------ | |
cad055a4 | 1494 | ;; zero-extract versions of the above |
f6a83b4a DD |
1495 | |
1496 | (define_insn "*bitbranch<mode>4_z" | |
1497 | [(set (pc) (if_then_else | |
28987d8b | 1498 | (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rYs,rm") |
f6a83b4a | 1499 | (const_int 1) |
703e049a | 1500 | (match_operand 1 "const_0_to_15_operand" "i,i")) |
f6a83b4a | 1501 | (const_int 0)) |
546c8f95 | 1502 | (label_ref (match_operand 2 "" "")) |
f6a83b4a DD |
1503 | (pc))) |
1504 | (clobber (reg:BI CARRY)) | |
1505 | ] | |
1506 | "" | |
1507 | "@ | |
51ac3042 NC |
1508 | BIT%x0%b0\t%p1, %0 { JNE\t%l2 |
1509 | BIT%X0%b0\t%p1, %0 { JNE\t%l2" | |
546c8f95 JL |
1510 | [(set_attr "extra_length" "2") |
1511 | (set_attr "type" "double")] | |
1512 | ) | |
f6a83b4a DD |
1513 | |
1514 | (define_insn "*bitbranch<mode>4_z" | |
1515 | [(set (pc) (if_then_else | |
28987d8b | 1516 | (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a | 1517 | (const_int 1) |
703e049a | 1518 | (match_operand 1 "const_0_to_15_operand" "i")) |
f6a83b4a | 1519 | (const_int 0)) |
546c8f95 | 1520 | (label_ref (match_operand 2 "" "")) |
f6a83b4a DD |
1521 | (pc))) |
1522 | (clobber (reg:BI CARRY)) | |
1523 | ] | |
1524 | "" | |
8682b1a5 | 1525 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
546c8f95 JL |
1526 | [(set_attr "extra_length" "2") |
1527 | (set_attr "type" "double")] | |
1528 | ) | |
f6a83b4a DD |
1529 | |
1530 | (define_insn "*bitbranch<mode>4_z" | |
1531 | [(set (pc) (if_then_else | |
28987d8b | 1532 | (eq (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a | 1533 | (const_int 1) |
703e049a | 1534 | (match_operand 1 "const_0_to_15_operand" "i")) |
f6a83b4a | 1535 | (const_int 0)) |
546c8f95 | 1536 | (pc) |
f6a83b4a DD |
1537 | (label_ref (match_operand 2 "" "")))) |
1538 | (clobber (reg:BI CARRY)) | |
1539 | ] | |
1540 | "" | |
51ac3042 | 1541 | "BIT%X0%b0\t%p1, %0 { JNE\t%l2" |
546c8f95 JL |
1542 | [(set_attr "extra_length" "2") |
1543 | (set_attr "type" "double")] | |
1544 | ) | |
f6a83b4a DD |
1545 | |
1546 | (define_insn "*bitbranch<mode>4_z" | |
1547 | [(set (pc) (if_then_else | |
28987d8b | 1548 | (ne (zero_extract:HI (match_operand:QHI 0 "msp430_general_dst_operand" "rm") |
f6a83b4a | 1549 | (const_int 1) |
703e049a | 1550 | (match_operand 1 "const_0_to_15_operand" "i")) |
f6a83b4a | 1551 | (const_int 0)) |
546c8f95 | 1552 | (pc) |
f6a83b4a DD |
1553 | (label_ref (match_operand 2 "" "")))) |
1554 | (clobber (reg:BI CARRY)) | |
1555 | ] | |
1556 | "" | |
51ac3042 | 1557 | "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" |
546c8f95 JL |
1558 | [(set_attr "extra_length" "2") |
1559 | (set_attr "type" "double")] | |
1560 | ) | |
f6a83b4a DD |
1561 | |
1562 | ;;------------------------------------------------------------ | |
1563 | ;; Misc | |
1564 | ||
1565 | (define_insn "nop" | |
1566 | [(const_int 0)] | |
1567 | "1" | |
1568 | "NOP" | |
546c8f95 | 1569 | [(set_attr "length" "2")] |
f6a83b4a | 1570 | ) |
a005b5be | 1571 | |
cad055a4 NC |
1572 | (define_insn "disable_interrupts" |
1573 | [(unspec_volatile [(const_int 0)] UNS_DINT)] | |
1574 | "" | |
a005b5be | 1575 | "DINT \; NOP" |
546c8f95 JL |
1576 | [(set_attr "length" "2")] |
1577 | ) | |
cad055a4 NC |
1578 | |
1579 | (define_insn "enable_interrupts" | |
1580 | [(unspec_volatile [(const_int 0)] UNS_EINT)] | |
1581 | "" | |
1582 | "EINT" | |
546c8f95 JL |
1583 | [(set_attr "length" "2")] |
1584 | ) | |
cad055a4 NC |
1585 | |
1586 | (define_insn "push_intr_state" | |
1587 | [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)] | |
1588 | "" | |
1589 | "PUSH\tSR" | |
546c8f95 JL |
1590 | [(set_attr "length" "2")] |
1591 | ) | |
cad055a4 NC |
1592 | |
1593 | (define_insn "pop_intr_state" | |
1594 | [(unspec_volatile [(const_int 0)] UNS_POP_INTR)] | |
1595 | "" | |
1596 | "POP\tSR" | |
546c8f95 JL |
1597 | [(set_attr "length" "2")] |
1598 | ) | |
cad055a4 NC |
1599 | |
1600 | ;; Clear bits in the copy of the status register that is currently | |
1601 | ;; saved on the stack at the top of the interrupt handler. | |
1602 | (define_insn "bic_SR" | |
1603 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)] | |
1604 | "" | |
1605 | "BIC.W\t%0, %O0(SP)" | |
546c8f95 JL |
1606 | [(set_attr "type" "single") |
1607 | (set_attr "extra_length" "2")] | |
1608 | ) | |
cad055a4 NC |
1609 | |
1610 | ;; Set bits in the copy of the status register that is currently | |
1611 | ;; saved on the stack at the top of the interrupt handler. | |
1612 | (define_insn "bis_SR" | |
1613 | [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)] | |
1614 | "" | |
1615 | "BIS.W\t%0, %O0(SP)" | |
546c8f95 JL |
1616 | [(set_attr "type" "single") |
1617 | (set_attr "extra_length" "2")] | |
1618 | ) | |
40ada30a NC |
1619 | |
1620 | ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int))) | |
1621 | ;; very late on in the compilation and not splitting it into separate | |
1622 | ;; instructions, so we provide a pattern to support it here. | |
1623 | (define_insn "andneghi3" | |
546c8f95 JL |
1624 | [(set (match_operand:HI 0 "register_operand" "=r,r") |
1625 | (and:HI (neg:HI (match_operand:HI 1 "general_operand" "0,rm")) | |
1626 | (match_operand 2 "immediate_operand" "n,n")))] | |
40ada30a | 1627 | "" |
546c8f95 JL |
1628 | "@ |
1629 | INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0 | |
1630 | MOV%X1.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0" | |
1631 | [(set_attr "length" "12,14") | |
1632 | (set_attr "type" "double")] | |
1633 | ) | |
1634 | ||
c6f709ec | 1635 | |
5f35dde5 DD |
1636 | (define_insn "delay_cycles_start" |
1637 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1638 | UNS_DELAY_START)] | |
1639 | "" | |
1640 | "; Begin %J0 cycle delay" | |
546c8f95 JL |
1641 | [(set_attr "length" "0")] |
1642 | ) | |
5f35dde5 DD |
1643 | |
1644 | (define_insn "delay_cycles_end" | |
1645 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] | |
1646 | UNS_DELAY_END)] | |
1647 | "" | |
1648 | "; End %J0 cycle delay" | |
1649 | ) | |
1650 | ||
1651 | (define_insn "delay_cycles_32" | |
1652 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1653 | (match_operand 1 "immediate_operand" "i") | |
1654 | ] UNS_DELAY_32)] | |
1655 | "" | |
1656 | "PUSH r13 | |
1657 | PUSH r14 | |
1658 | MOV.W %A0, r13 | |
1659 | MOV.W %B0, r14 | |
1660 | 1: SUB.W #1, r13 | |
1661 | SUBC.W #0, r14 | |
1662 | JNE 1b | |
1663 | TST.W r13 | |
1664 | JNE 1b | |
1665 | POP r14 | |
1666 | POP r13" | |
546c8f95 JL |
1667 | [(set_attr "length" "32")] |
1668 | ) | |
5f35dde5 DD |
1669 | |
1670 | (define_insn "delay_cycles_32x" | |
1671 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1672 | (match_operand 1 "immediate_operand" "i") | |
1673 | ] UNS_DELAY_32X)] | |
1674 | "" | |
47f138d1 | 1675 | "PUSHM.A #2,r14 |
5f35dde5 DD |
1676 | MOV.W %A0, r13 |
1677 | MOV.W %B0, r14 | |
1678 | 1: SUB.W #1, r13 | |
1679 | SUBC.W #0, r14 | |
1680 | JNE 1b | |
1681 | TST.W r13 | |
1682 | JNE 1b | |
47f138d1 | 1683 | POPM.A #2,r14" |
546c8f95 JL |
1684 | [(set_attr "length" "28")] |
1685 | ) | |
5f35dde5 DD |
1686 | |
1687 | (define_insn "delay_cycles_16" | |
1688 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1689 | (match_operand 1 "immediate_operand" "i") | |
1690 | ] UNS_DELAY_16)] | |
1691 | "" | |
1692 | "PUSH r13 | |
1693 | MOV.W %0, r13 | |
1694 | 1: SUB.W #1, r13 | |
1695 | JNE 1b | |
1696 | POP r13" | |
546c8f95 JL |
1697 | [(set_attr "length" "14")] |
1698 | ) | |
5f35dde5 DD |
1699 | |
1700 | (define_insn "delay_cycles_16x" | |
1701 | [(unspec_volatile [(match_operand 0 "immediate_operand" "i") | |
1702 | (match_operand 1 "immediate_operand" "i") | |
1703 | ] UNS_DELAY_16X)] | |
1704 | "" | |
1705 | "PUSHM.A #1,r13 | |
1706 | MOV.W %0, r13 | |
1707 | 1: SUB.W #1, r13 | |
1708 | JNE 1b | |
1709 | POPM.A #1,r13" | |
546c8f95 JL |
1710 | [(set_attr "length" "14")] |
1711 | ) | |
5f35dde5 DD |
1712 | |
1713 | (define_insn "delay_cycles_2" | |
1714 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] | |
1715 | "" | |
1716 | "JMP .+2" | |
546c8f95 JL |
1717 | [(set_attr "length" "2")] |
1718 | ) | |
5f35dde5 DD |
1719 | |
1720 | (define_insn "delay_cycles_1" | |
1721 | [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] | |
1722 | "" | |
1723 | "NOP" | |
546c8f95 JL |
1724 | [(set_attr "length" "2")] |
1725 | ) | |
5f35dde5 | 1726 | |
499a39af JL |
1727 | ; libgcc helper functions for widening multiplication aren't currently |
1728 | ; generated by gcc, so we can't catch them later and map them to the mspabi | |
1729 | ; functions. | |
1730 | ; We catch the patterns here and either generate a call to the helper function, | |
1731 | ; or emit the hardware multiply instruction sequence inline. | |
1732 | ; | |
1733 | ; If we don't have hardware multiply support, it will generally be slower and | |
1734 | ; result in larger code to call the mspabi library function to perform the | |
1735 | ; widening multiplication than just leaving GCC to widen the arguments itself. | |
1736 | ; | |
1737 | ; We don't use library functions for SImode->DImode widening since its always | |
1738 | ; larger and slower than letting GCC widen the arguments inline. | |
1739 | (define_expand "mulhisi3" | |
1740 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1741 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1742 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
1743 | "msp430_has_hwmult ()" | |
1744 | { | |
1745 | /* Leave the other case for the inline insn. */ | |
1746 | if (!(optimize > 2 && msp430_has_hwmult ())) | |
1747 | { | |
1748 | msp430_expand_helper (operands, "__mspabi_mpysl", false); | |
1749 | DONE; | |
1750 | } | |
1751 | } | |
1752 | ) | |
1753 | ||
1754 | (define_expand "umulhisi3" | |
1755 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1756 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1757 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
1758 | "msp430_has_hwmult ()" | |
1759 | { | |
1760 | /* Leave the other case for the inline insn. */ | |
1761 | if (!(optimize > 2 && msp430_has_hwmult ())) | |
1762 | { | |
1763 | msp430_expand_helper (operands, "__mspabi_mpyul", false); | |
1764 | DONE; | |
1765 | } | |
1766 | } | |
1767 | ) | |
1768 | ||
1769 | (define_insn "*mulhisi3_inline" | |
c6f709ec NC |
1770 | [(set (match_operand:SI 0 "register_operand" "=r") |
1771 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1772 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
0744333e | 1773 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1774 | "* |
f7961364 | 1775 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1776 | 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 | 1777 | else |
ba3cf9f1 | 1778 | 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 | 1779 | " |
546c8f95 | 1780 | [(set_attr "length" "24")] |
c6f709ec NC |
1781 | ) |
1782 | ||
499a39af | 1783 | (define_insn "*umulhisi3_inline" |
c6f709ec NC |
1784 | [(set (match_operand:SI 0 "register_operand" "=r") |
1785 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0")) | |
1786 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
0744333e | 1787 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1788 | "* |
f7961364 | 1789 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1790 | 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 | 1791 | else |
ba3cf9f1 | 1792 | 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 | 1793 | " |
546c8f95 | 1794 | [(set_attr "length" "24")] |
c6f709ec NC |
1795 | ) |
1796 | ||
1797 | (define_insn "mulsidi3" | |
1798 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1799 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1800 | (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
0744333e | 1801 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1802 | "* |
f7961364 | 1803 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1804 | 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 | 1805 | else |
ba3cf9f1 | 1806 | 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 | 1807 | " |
546c8f95 | 1808 | [(set_attr "length" "40")] |
c6f709ec NC |
1809 | ) |
1810 | ||
1811 | (define_insn "umulsidi3" | |
1812 | [(set (match_operand:DI 0 "register_operand" "=r") | |
1813 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) | |
1814 | (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))] | |
0744333e | 1815 | "optimize > 2 && msp430_has_hwmult ()" |
c6f709ec | 1816 | "* |
f7961364 | 1817 | if (msp430_use_f5_series_hwmult ()) |
ba3cf9f1 | 1818 | 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 | 1819 | else |
ba3cf9f1 | 1820 | 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 | 1821 | " |
546c8f95 | 1822 | [(set_attr "length" "40")] |
c6f709ec | 1823 | ) |