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