]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/msp430/msp430.c
Factor unrelated declarations out of tree.h.
[thirdparty/gcc.git] / gcc / config / msp430 / msp430.c
CommitLineData
e4a25868 1/* Subroutines used for code generation on TI MSP430 processors.
2 Copyright (C) 2012-2013 Free Software Foundation, Inc.
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#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "tree.h"
9ed99284 26#include "stor-layout.h"
27#include "calls.h"
e4a25868 28#include "rtl.h"
29#include "regs.h"
30#include "hard-reg-set.h"
31#include "insn-config.h"
32#include "conditions.h"
33#include "output.h"
34#include "insn-attr.h"
35#include "flags.h"
36#include "function.h"
37#include "expr.h"
38#include "optabs.h"
39#include "libfuncs.h"
40#include "recog.h"
41#include "diagnostic-core.h"
42#include "toplev.h"
43#include "reload.h"
44#include "df.h"
45#include "ggc.h"
46#include "tm_p.h"
47#include "debug.h"
48#include "target.h"
49#include "target-def.h"
50#include "langhooks.h"
51#include "msp430-protos.h"
52#include "dumpfile.h"
53#include "opts.h"
54
55\f
56
57static void msp430_compute_frame_info (void);
58
59\f
60
61/* Run-time Target Specification */
62
63bool msp430x = false;
64
65struct GTY(()) machine_function
66{
67 /* If set, the rest of the fields have been computed. */
68 int computed;
69 /* Which registers need to be saved in the pro/epilogue. */
70 int need_to_save [FIRST_PSEUDO_REGISTER];
71
72 /* These fields describe the frame layout... */
73 /* arg pointer */
74 /* 2/4 bytes for saved PC */
75 int framesize_regs;
76 /* frame pointer */
77 int framesize_locals;
78 int framesize_outgoing;
79 /* stack pointer */
80 int framesize;
81
82 /* How much we adjust the stack when returning from an exception
83 handler. */
84 rtx eh_stack_adjust;
85};
86
87/* This is our init_machine_status, as set in
88 msp_option_override. */
89static struct machine_function *
90msp430_init_machine_status (void)
91{
92 struct machine_function *m;
93
94 m = ggc_alloc_cleared_machine_function ();
95
96 return m;
97}
98
99#undef TARGET_HANDLE_OPTION
100#define TARGET_HANDLE_OPTION msp430_handle_option
101
102bool
103msp430_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
104 struct gcc_options *opts_set ATTRIBUTE_UNUSED,
105 const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED,
106 location_t loc ATTRIBUTE_UNUSED)
107{
108 return true;
109}
110
111#undef TARGET_OPTION_OVERRIDE
112#define TARGET_OPTION_OVERRIDE msp430_option_override
113
8e246851 114/* This list provides a set of known MCU names that support the MSP430X
115 ISA. The list has been provided by TI and should be kept in sync with
116 the ones in:
117
118 gcc/config/msp430/t-msp430
119 gas/config/tc-msp430.c
1b80b2b4 120
8e246851 121 FIXME: We ought to read the names in from a file at run, rather
122 than having them built in like this. Also such a file should be
123 shared with gas. */
1b80b2b4 124
8e246851 125static const char * msp430x_names [] =
126{
127 "cc430f5123", "cc430f5125", "cc430f5133", "cc430f5135", "cc430f5137",
128 "cc430f5143", "cc430f5145", "cc430f5147", "cc430f6125", "cc430f6126",
129 "cc430f6127", "cc430f6135", "cc430f6137", "cc430f6143", "cc430f6145",
130 "cc430f6147", "msp430bt5190", "msp430cg4616", "msp430cg4617", "msp430cg4618",
131 "msp430cg4619", "msp430f2416", "msp430f2417", "msp430f2418", "msp430f2419",
132 "msp430f2616", "msp430f2617", "msp430f2618", "msp430f2619", "msp430f4616",
133 "msp430f46161", "msp430f4617", "msp430f46171", "msp430f4618", "msp430f46181",
134 "msp430f4619", "msp430f46191", "msp430f47126", "msp430f47127", "msp430f47163",
135 "msp430f47166", "msp430f47167", "msp430f47173", "msp430f47176", "msp430f47177",
136 "msp430f47183", "msp430f47186", "msp430f47187", "msp430f47193", "msp430f47196",
137 "msp430f47197", "msp430f5131", "msp430f5132", "msp430f5151", "msp430f5152",
138 "msp430f5171", "msp430f5172", "msp430f5212", "msp430f5213", "msp430f5214",
139 "msp430f5217", "msp430f5218", "msp430f5219", "msp430f5222", "msp430f5223",
140 "msp430f5224", "msp430f5227", "msp430f5228", "msp430f5229", "msp430f5304",
141 "msp430f5308", "msp430f5309", "msp430f5310", "msp430f5324", "msp430f5325",
142 "msp430f5326", "msp430f5327", "msp430f5328", "msp430f5329", "msp430f5333",
143 "msp430f5335", "msp430f5336", "msp430f5338", "msp430f5340", "msp430f5341",
144 "msp430f5342", "msp430f5358", "msp430f5359", "msp430f5418", "msp430f5418a",
145 "msp430f5419", "msp430f5419a", "msp430f5435", "msp430f5435a", "msp430f5436",
146 "msp430f5436a", "msp430f5437", "msp430f5437a", "msp430f5438", "msp430f5438a",
1b80b2b4 147 "msp430f5500", "msp430f5501", "msp430f5502", "msp430f5503", "msp430f5504",
148 "msp430f5505", "msp430f5506", "msp430f5507", "msp430f5508", "msp430f5509",
149 "msp430f5510", "msp430f5513", "msp430f5514", "msp430f5515", "msp430f5517",
150 "msp430f5519", "msp430f5521", "msp430f5522", "msp430f5524", "msp430f5525",
8e246851 151 "msp430f5526", "msp430f5527", "msp430f5528", "msp430f5529", "msp430f5630",
1b80b2b4 152 "msp430f5631", "msp430f5632", "msp430f5633", "msp430f5634", "msp430f5635",
8e246851 153 "msp430f5636", "msp430f5637", "msp430f5638", "msp430f5658", "msp430f5659",
154 "msp430f6433", "msp430f6435", "msp430f6436", "msp430f6438", "msp430f6458",
155 "msp430f6459", "msp430f6630", "msp430f6631", "msp430f6632", "msp430f6633",
156 "msp430f6634", "msp430f6635", "msp430f6636", "msp430f6637", "msp430f6638",
157 "msp430f6658", "msp430f6659", "msp430f6720", "msp430f6721", "msp430f6723",
158 "msp430f6724", "msp430f6725", "msp430f6726", "msp430f6730", "msp430f6731",
159 "msp430f6733", "msp430f6734", "msp430f6735", "msp430f6736", "msp430f6745",
160 "msp430f67451", "msp430f6746", "msp430f67461", "msp430f6747", "msp430f67471",
161 "msp430f6748", "msp430f67481", "msp430f6749", "msp430f67491", "msp430f6765",
162 "msp430f67651", "msp430f6766", "msp430f67661", "msp430f6767", "msp430f67671",
163 "msp430f6768", "msp430f67681", "msp430f6769", "msp430f67691", "msp430f6775",
164 "msp430f67751", "msp430f6776", "msp430f67761", "msp430f6777", "msp430f67771",
165 "msp430f6778", "msp430f67781", "msp430f6779", "msp430f67791", "msp430fg4616",
166 "msp430fg4617", "msp430fg4618", "msp430fg4619", "msp430fr5720", "msp430fr5721",
167 "msp430fr5722", "msp430fr5723", "msp430fr5724", "msp430fr5725", "msp430fr5726",
168 "msp430fr5727", "msp430fr5728", "msp430fr5729", "msp430fr5730", "msp430fr5731",
169 "msp430fr5732", "msp430fr5733", "msp430fr5734", "msp430fr5735", "msp430fr5736",
170 "msp430fr5737", "msp430fr5738", "msp430fr5739", "msp430fr5949", "msp430fr5969",
171 "msp430sl5438a","msp430x241x", "msp430x26x", "msp430x461x1", "msp430x46x",
172 "msp430x471x3", "msp430x471x6", "msp430x471x7", "msp430xg46x"
1b80b2b4 173};
8e246851 174
175/* Generate a C preprocessor symbol based upon the MCU selected by the user.
176 If a specific MCU has not been selected then return a generic symbol instead. */
177
178const char *
179msp430_mcu_name (void)
180{
181 if (target_cpu)
182 {
183 unsigned int i;
184 static char mcu_name [64];
185
186 snprintf (mcu_name, sizeof (mcu_name) - 1, "__%s__", target_cpu);
187 for (i = strlen (mcu_name); i--;)
188 mcu_name[i] = TOUPPER (mcu_name[i]);
189 return mcu_name;
190 }
1b80b2b4 191
8e246851 192 return msp430x ? "__MSP430XGENERIC__" : "__MSP430GENERIC__";
193}
194
e4a25868 195static void
196msp430_option_override (void)
197{
198 init_machine_status = msp430_init_machine_status;
199
1b80b2b4 200 if (target_cpu)
201 {
202 unsigned i;
203
204 for (i = ARRAY_SIZE (msp430x_names); i--;)
ebeb88c0 205 if (strcasecmp (target_cpu, msp430x_names[i]) == 0)
1b80b2b4 206 {
207 msp430x = true;
208 break;
209 }
210 /* Note - it is not an error if we did not recognize the MCU
211 name. The msp430x_names array only contains those MCU names
212 which are currently known to use the MSP430X ISA. There are
213 lots of other MCUs which just use the MSP430 ISA. */
8e246851 214
215 /* We also recognise two generic MCU 430X names. They do not
216 appear in the msp430x_names table as we want to be able to
217 generate special C preprocessor defines for them. */
218 if (strcasecmp (target_cpu, "msp430x") == 0
219 || strcasecmp (target_cpu, "msp430xv2") == 0)
220 msp430x = true;
1b80b2b4 221 }
e4a25868 222
223 if (TARGET_LARGE && !msp430x)
62b2ccbe 224 error ("-mlarge requires a 430X-compatible -mmcu=");
e4a25868 225
226 if (flag_exceptions || flag_non_call_exceptions
227 || flag_unwind_tables || flag_asynchronous_unwind_tables)
228 flag_omit_frame_pointer = false;
229 else
230 flag_omit_frame_pointer = true;
231
232 /* This is a hack to work around a problem with the newlib build
233 mechanism. Newlib always appends CFLAGS to the end of the GCC
234 command line and always sets -O2 in CFLAGS. Thus it is not
235 possible to build newlib with -Os enabled. Until now... */
236 if (TARGET_OPT_SPACE && optimize < 3)
237 optimize_size = 1;
238}
239
240\f
241
242/* Storage Layout */
243
244#undef TARGET_MS_BITFIELD_LAYOUT_P
245#define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p
246
247bool
248msp430_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED)
249{
250 return false;
251}
252
253\f
254
255/* Register Usage */
256
257/* Implements HARD_REGNO_NREGS. MSP430X registers can hold a single
258 PSImode value, but not an SImode value. */
259int
260msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED,
261 enum machine_mode mode)
262{
263 if (mode == PSImode && msp430x)
264 return 1;
265 return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
266 / UNITS_PER_WORD);
267}
268
269/* Implements HARD_REGNO_MODE_OK. */
270int
271msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED,
272 enum machine_mode mode)
273{
274 return regno <= (ARG_POINTER_REGNUM - msp430_hard_regno_nregs (regno, mode));
275}
276
277/* Implements MODES_TIEABLE_P. */
278bool
279msp430_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
280{
281 if ((mode1 == PSImode || mode2 == SImode)
282 || (mode1 == SImode || mode2 == PSImode))
283 return false;
284
285 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
286 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
287 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
288 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
289}
290
291#undef TARGET_FRAME_POINTER_REQUIRED
292#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required
293
294static bool
295msp430_frame_pointer_required (void)
296{
297 return false;
298}
299
300#undef TARGET_CAN_ELIMINATE
301#define TARGET_CAN_ELIMINATE msp430_can_eliminate
302
303static bool
304msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED,
305 const int to_reg ATTRIBUTE_UNUSED)
306{
307 return true;
308}
309
310/* Implements INITIAL_ELIMINATION_OFFSET. */
311int
62b2ccbe 312msp430_initial_elimination_offset (int from, int to)
e4a25868 313{
62b2ccbe 314 int rv = 0; /* As if arg to arg. */
e4a25868 315
316 msp430_compute_frame_info ();
317
318 switch (to)
319 {
320 case STACK_POINTER_REGNUM:
321 rv += cfun->machine->framesize_outgoing;
322 rv += cfun->machine->framesize_locals;
323 /* Fall through. */
324 case FRAME_POINTER_REGNUM:
325 rv += cfun->machine->framesize_regs;
326 /* Allow for the saved return address. */
327 rv += (TARGET_LARGE ? 4 : 2);
328 /* NB/ No need to allow for crtl->args.pretend_args_size.
329 GCC does that for us. */
330 break;
331 default:
332 gcc_unreachable ();
333 }
334
335 switch (from)
336 {
337 case FRAME_POINTER_REGNUM:
338 /* Allow for the fall through above. */
339 rv -= (TARGET_LARGE ? 4 : 2);
340 rv -= cfun->machine->framesize_regs;
341 case ARG_POINTER_REGNUM:
342 break;
343 default:
344 gcc_unreachable ();
345 }
346
347 return rv;
348}
349\f
350/* Named Address Space support */
351
352
353/* Return the appropriate mode for a named address pointer. */
354#undef TARGET_ADDR_SPACE_POINTER_MODE
355#define TARGET_ADDR_SPACE_POINTER_MODE msp430_addr_space_pointer_mode
356#undef TARGET_ADDR_SPACE_ADDRESS_MODE
357#define TARGET_ADDR_SPACE_ADDRESS_MODE msp430_addr_space_pointer_mode
358
359static enum machine_mode
360msp430_addr_space_pointer_mode (addr_space_t addrspace)
361{
362 switch (addrspace)
363 {
364 default:
365 case ADDR_SPACE_GENERIC:
366 return Pmode;
367 case ADDR_SPACE_NEAR:
368 return HImode;
369 case ADDR_SPACE_FAR:
370 return PSImode;
371 }
372}
373
374/* Function pointers are stored in unwind_word sized
375 variables, so make sure that unwind_word is big enough. */
376#undef TARGET_UNWIND_WORD_MODE
377#define TARGET_UNWIND_WORD_MODE msp430_unwind_word_mode
378
379static enum machine_mode
380msp430_unwind_word_mode (void)
381{
382 return TARGET_LARGE ? SImode : HImode;
383}
384
385/* Determine if one named address space is a subset of another. */
386#undef TARGET_ADDR_SPACE_SUBSET_P
387#define TARGET_ADDR_SPACE_SUBSET_P msp430_addr_space_subset_p
388static bool
389msp430_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
390{
391 if (subset == superset)
392 return true;
393 else
394 return (subset != ADDR_SPACE_FAR && superset == ADDR_SPACE_FAR);
395}
396
397#undef TARGET_ADDR_SPACE_CONVERT
398#define TARGET_ADDR_SPACE_CONVERT msp430_addr_space_convert
399/* Convert from one address space to another. */
400static rtx
401msp430_addr_space_convert (rtx op, tree from_type, tree to_type)
402{
403 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
404 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
405 rtx result;
406
407 if (to_as != ADDR_SPACE_FAR && from_as == ADDR_SPACE_FAR)
408 {
409 /* This is unpredictable, as we're truncating off usable address
410 bits. */
411
412 if (CONSTANT_P (op))
413 return gen_rtx_CONST (HImode, op);
414
415 result = gen_reg_rtx (HImode);
416 emit_insn (gen_truncpsihi2 (result, op));
417 return result;
418 }
419 else if (to_as == ADDR_SPACE_FAR && from_as != ADDR_SPACE_FAR)
420 {
421 /* This always works. */
422
423 if (CONSTANT_P (op))
424 return gen_rtx_CONST (PSImode, op);
425
426 result = gen_reg_rtx (PSImode);
427 emit_insn (gen_zero_extendhipsi2 (result, op));
428 return result;
429 }
430 else
431 gcc_unreachable ();
432}
433\f
434/* Stack Layout and Calling Conventions. */
435
436/* For each function, we list the gcc version and the TI version on
437 each line, where we're converting the function names. */
438static char const * const special_convention_function_names [] =
439{
440 "__muldi3", "__mspabi_mpyll",
441 "__udivdi3", "__mspabi_divull",
442 "__umoddi3", "__mspabi_remull",
443 "__divdi3", "__mspabi_divlli",
444 "__moddi3", "__mspabi_remlli",
445 "__mspabi_srall",
446 "__mspabi_srlll",
447 "__mspabi_sllll",
448 "__adddf3", "__mspabi_addd",
449 "__subdf3", "__mspabi_subd",
450 "__muldf3", "__mspabi_mpyd",
451 "__divdf3", "__mspabi_divd",
452 "__mspabi_cmpd",
453 NULL
454};
455
456/* TRUE if the function passed is a "speical" function. Special
457 functions pass two DImode parameters in registers. */
458static bool
459msp430_special_register_convention_p (const char *name)
460{
461 int i;
462
463 for (i = 0; special_convention_function_names [i]; i++)
464 if (! strcmp (name, special_convention_function_names [i]))
465 return true;
466
467 return false;
468}
469
470#undef TARGET_FUNCTION_VALUE_REGNO_P
471#define TARGET_FUNCTION_VALUE_REGNO_P msp430_function_value_regno_p
472
473bool
474msp430_function_value_regno_p (unsigned int regno)
475{
476 return regno == 12;
477}
478
479
480#undef TARGET_FUNCTION_VALUE
481#define TARGET_FUNCTION_VALUE msp430_function_value
482
483rtx
484msp430_function_value (const_tree ret_type,
485 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
486 bool outgoing ATTRIBUTE_UNUSED)
487{
488 return gen_rtx_REG (TYPE_MODE (ret_type), 12);
489}
490
491#undef TARGET_LIBCALL_VALUE
492#define TARGET_LIBCALL_VALUE msp430_libcall_value
493
494rtx
495msp430_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
496{
497 return gen_rtx_REG (mode, 12);
498}
499
500/* Implements INIT_CUMULATIVE_ARGS. */
501void
502msp430_init_cumulative_args (CUMULATIVE_ARGS *ca,
503 tree fntype ATTRIBUTE_UNUSED,
504 rtx libname ATTRIBUTE_UNUSED,
505 tree fndecl ATTRIBUTE_UNUSED,
506 int n_named_args ATTRIBUTE_UNUSED)
507{
508 const char *fname;
509 memset (ca, 0, sizeof(*ca));
510
511 ca->can_split = 1;
512
513 if (fndecl)
514 fname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
515 else if (libname)
516 fname = XSTR (libname, 0);
517 else
518 fname = NULL;
519
520 if (fname && msp430_special_register_convention_p (fname))
521 ca->special_p = 1;
522}
523
524/* Helper function for argument passing; this function is the common
525 code that determines where an argument will be passed. */
526static void
527msp430_evaluate_arg (cumulative_args_t cap,
528 enum machine_mode mode,
529 const_tree type ATTRIBUTE_UNUSED,
530 bool named)
531{
532 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
533 int nregs = GET_MODE_SIZE (mode);
534 int i;
535
536 ca->reg_count = 0;
537 ca->mem_count = 0;
538
539 if (!named)
540 return;
541
542 if (mode == PSImode)
543 nregs = 1;
544 else
545 nregs = (nregs + 1) / 2;
546
547 if (ca->special_p)
548 {
549 /* Function is passed two DImode operands, in R8:R11 and
550 R12:15. */
551 ca->start_reg = 8;
552 ca->reg_count = 4;
553 return;
554 }
555
556 switch (nregs)
557 {
558 case 1:
559 for (i = 0; i < 4; i++)
560 if (! ca->reg_used [i])
561 {
562 ca->reg_count = 1;
563 ca->start_reg = CA_FIRST_REG + i;
564 return;
565 }
566 break;
567 case 2:
568 for (i = 0; i < 3; i++)
569 if (! ca->reg_used [i] && ! ca->reg_used [i + 1])
570 {
571 ca->reg_count = 2;
572 ca->start_reg = CA_FIRST_REG + i;
573 return;
574 }
575 if (! ca->reg_used [3] && ca->can_split)
576 {
577 ca->reg_count = 1;
578 ca->mem_count = 2;
579 ca->start_reg = CA_FIRST_REG + 3;
580 return;
581 }
582 break;
583 case 3:
584 case 4:
585 ca->can_split = 0;
586 if (! ca->reg_used [0]
587 && ! ca->reg_used [1]
588 && ! ca->reg_used [2]
589 && ! ca->reg_used [3])
590 {
591 ca->reg_count = 4;
592 ca->start_reg = CA_FIRST_REG;
593 return;
594 }
595 break;
596 }
597}
598
599#undef TARGET_PROMOTE_PROTOTYPES
600#define TARGET_PROMOTE_PROTOTYPES msp430_promote_prototypes
601
602bool
603msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
604{
605 return false;
606}
607
608#undef TARGET_FUNCTION_ARG
609#define TARGET_FUNCTION_ARG msp430_function_arg
610
611rtx
612msp430_function_arg (cumulative_args_t cap,
613 enum machine_mode mode,
614 const_tree type,
615 bool named)
616{
617 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
618
619 msp430_evaluate_arg (cap, mode, type, named);
620
621 if (ca->reg_count)
622 return gen_rtx_REG (mode, ca->start_reg);
623
624 return 0;
625}
626
627#undef TARGET_ARG_PARTIAL_BYTES
628#define TARGET_ARG_PARTIAL_BYTES msp430_arg_partial_bytes
629
630int
631msp430_arg_partial_bytes (cumulative_args_t cap,
632 enum machine_mode mode,
633 tree type,
634 bool named)
635{
636 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
637
638 msp430_evaluate_arg (cap, mode, type, named);
639
640 if (ca->reg_count && ca->mem_count)
641 return ca->reg_count * UNITS_PER_WORD;
642
643 return 0;
644}
645
646#undef TARGET_PASS_BY_REFERENCE
647#define TARGET_PASS_BY_REFERENCE msp430_pass_by_reference
648
649static bool
650msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED,
651 enum machine_mode mode,
652 const_tree type,
653 bool named ATTRIBUTE_UNUSED)
654{
655 return (mode == BLKmode
656 || (type && TREE_CODE (type) == RECORD_TYPE)
657 || (type && TREE_CODE (type) == UNION_TYPE));
658}
659
660#undef TARGET_CALLEE_COPIES
661#define TARGET_CALLEE_COPIES msp430_callee_copies
662
663static bool
664msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED,
665 enum machine_mode mode ATTRIBUTE_UNUSED,
666 const_tree type ATTRIBUTE_UNUSED,
667 bool named ATTRIBUTE_UNUSED)
668{
669 return true;
670}
671
672#undef TARGET_FUNCTION_ARG_ADVANCE
673#define TARGET_FUNCTION_ARG_ADVANCE msp430_function_arg_advance
674
675void
676msp430_function_arg_advance (cumulative_args_t cap,
677 enum machine_mode mode,
678 const_tree type,
679 bool named)
680{
681 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
682 int i;
683
684 msp430_evaluate_arg (cap, mode, type, named);
685
686 if (ca->start_reg >= CA_FIRST_REG)
687 for (i = 0; i < ca->reg_count; i ++)
688 ca->reg_used [i + ca->start_reg - CA_FIRST_REG] = 1;
689
690 ca->special_p = 0;
691}
692
693#undef TARGET_FUNCTION_ARG_BOUNDARY
694#define TARGET_FUNCTION_ARG_BOUNDARY msp430_function_arg_boundary
695
696static unsigned int
697msp430_function_arg_boundary (enum machine_mode mode, const_tree type)
698{
699 if (mode == BLKmode
700 && int_size_in_bytes (type) > 1)
701 return 16;
702 if (GET_MODE_BITSIZE (mode) > 8)
703 return 16;
704 return 8;
705}
706
707#undef TARGET_RETURN_IN_MEMORY
708#define TARGET_RETURN_IN_MEMORY msp430_return_in_memory
709
710static bool
711msp430_return_in_memory (const_tree ret_type, const_tree fntype ATTRIBUTE_UNUSED)
712{
713 enum machine_mode mode = TYPE_MODE (ret_type);
714
715 if (mode == BLKmode
716 || (fntype && TREE_CODE (TREE_TYPE (fntype)) == RECORD_TYPE)
717 || (fntype && TREE_CODE (TREE_TYPE (fntype)) == UNION_TYPE))
718 return true;
719
720 if (GET_MODE_SIZE (mode) > 8)
721 return true;
722
723 return false;
724}
725
726#undef TARGET_GET_RAW_ARG_MODE
727#define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode
728
729static enum machine_mode
730msp430_get_raw_arg_mode (int regno)
731{
732 return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
733}
734
735#undef TARGET_GET_RAW_RESULT_MODE
736#define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode
737
738static enum machine_mode
739msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED)
740{
741 return Pmode;
742}
743\f
744/* Addressing Modes */
745
746#undef TARGET_LEGITIMATE_ADDRESS_P
747#define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p
748
749static bool
750reg_ok_for_addr (rtx r, bool strict)
751{
752 int rn = REGNO (r);
753
754 if (strict && rn >= FIRST_PSEUDO_REGISTER)
755 rn = reg_renumber [rn];
756 if (strict && 0 <= rn && rn < FIRST_PSEUDO_REGISTER)
757 return true;
758 if (!strict)
759 return true;
760 return false;
761}
762
763bool
764msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
765 rtx x ATTRIBUTE_UNUSED,
766 bool strict ATTRIBUTE_UNUSED)
767{
768 switch (GET_CODE (x))
769 {
770 case MEM:
771 return false;
772
773 case PLUS:
774 if (REG_P (XEXP (x, 0)))
775 {
776 if (GET_MODE (x) != GET_MODE (XEXP (x, 0)))
777 return false;
778 if (!reg_ok_for_addr (XEXP (x, 0), strict))
779 return false;
780 switch (GET_CODE (XEXP (x, 1)))
781 {
782 case CONST:
783 case SYMBOL_REF:
784 case CONST_INT:
785 return true;
786 default:
787 return false;
788 }
789 }
790 return false;
791
792 case REG:
793 if (!reg_ok_for_addr (x, strict))
794 return false;
795 /* else... */
796 case CONST:
797 case SYMBOL_REF:
798 case CONST_INT:
799 return true;
800
801 default:
802 return false;
803 }
804}
805
806#undef TARGET_LEGITIMATE_CONSTANT_P
807#define TARGET_LEGITIMATE_CONSTANT_P msp430_legitimate_constant
808
809static bool
810msp430_legitimate_constant (enum machine_mode mode, rtx x)
811{
812 return ! CONST_INT_P (x)
813 || mode != PSImode
814 /* GCC does not know the width of the PSImode, so make
815 sure that it does not try to use a constant value that
816 is out of range. */
817 || (INTVAL (x) < (1 << 20) && INTVAL (x) >= (-1 << 20));
818}
819
820\f
821#undef TARGET_RTX_COSTS
822#define TARGET_RTX_COSTS msp430_rtx_costs
823
824static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED,
825 int code,
826 int outer_code ATTRIBUTE_UNUSED,
827 int opno ATTRIBUTE_UNUSED,
828 int * total,
829 bool speed ATTRIBUTE_UNUSED)
830{
831 switch (code)
832 {
833 case SIGN_EXTEND:
834 if (GET_MODE (x) == SImode && outer_code == SET)
835 {
836 *total = COSTS_N_INSNS (4);
837 return true;
838 }
839 break;
840 case ASHIFT:
841 case ASHIFTRT:
842 case LSHIFTRT:
843 if (!msp430x)
844 {
845 *total = COSTS_N_INSNS (100);
846 return true;
847 }
848 break;
849 }
850 return false;
851}
852\f
853/* Function Entry and Exit */
854
855/* The MSP430 call frame looks like this:
856
857 <higher addresses>
858 +--------------------+
859 | |
860 | Stack Arguments |
861 | |
862 +--------------------+ <-- "arg pointer"
863 | |
864 | PC from call | (2 bytes for 430, 4 for TARGET_LARGE)
865 | |
62b2ccbe 866 +--------------------+
867 | SR if this func has|
868 | been called via an |
869 | interrupt. |
e4a25868 870 +--------------------+ <-- SP before prologue, also AP
871 | |
872 | Saved Regs | (2 bytes per reg for 430, 4 per for TARGET_LARGE)
873 | |
874 +--------------------+ <-- "frame pointer"
875 | |
876 | Locals |
877 | |
878 +--------------------+
879 | |
880 | Outgoing Args |
881 | |
882 +--------------------+ <-- SP during function
883 <lower addresses>
884
885*/
886
887/* We use this to wrap all emitted insns in the prologue, so they get
888 the "frame-related" (/f) flag set. */
889static rtx
890F (rtx x)
891{
892 RTX_FRAME_RELATED_P (x) = 1;
893 return x;
894}
895
896/* This is the one spot that decides if a register is to be saved and
897 restored in the prologue/epilogue. */
898static bool
899msp430_preserve_reg_p (int regno)
900{
901 /* PC, SP, SR, and the constant generator. */
902 if (regno <= 3)
903 return false;
904
905 /* FIXME: add interrupt, EH, etc. */
906 if (crtl->calls_eh_return)
907 return true;
908
909 /* Shouldn't be more than the above, but just in case... */
910 if (fixed_regs [regno])
911 return false;
912
62b2ccbe 913 /* Interrupt handlers save all registers they use, even
914 ones which are call saved. If they call other functions
915 then *every* register is saved. */
916 if (msp430_is_interrupt_func ())
917 return ! crtl->is_leaf || df_regs_ever_live_p (regno);
918
e4a25868 919 if (!call_used_regs [regno]
920 && df_regs_ever_live_p (regno))
921 return true;
922
923 return false;
924}
925
926/* Compute all the frame-related fields in our machine_function
927 structure. */
928static void
929msp430_compute_frame_info (void)
930{
931 int i;
932
933 cfun->machine->computed = 1;
934 cfun->machine->framesize_regs = 0;
935 cfun->machine->framesize_locals = get_frame_size ();
936 cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
937
62b2ccbe 938 for (i = 0; i < ARG_POINTER_REGNUM; i ++)
e4a25868 939 if (msp430_preserve_reg_p (i))
940 {
941 cfun->machine->need_to_save [i] = 1;
942 cfun->machine->framesize_regs += (TARGET_LARGE ? 4 : 2);
943 }
944 else
945 cfun->machine->need_to_save [i] = 0;
946
947 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
948 cfun->machine->framesize_locals ++;
949
950 cfun->machine->framesize = (cfun->machine->framesize_regs
951 + cfun->machine->framesize_locals
952 + cfun->machine->framesize_outgoing);
953}
954
62b2ccbe 955static inline bool
956is_attr_func (const char * attr)
957{
958 return lookup_attribute (attr, DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
959}
960
961/* Returns true if the current function has the "interrupt" attribute. */
962
963bool
964msp430_is_interrupt_func (void)
965{
966 return is_attr_func ("interrupt");
967}
968
969static inline bool
970is_naked_func (void)
971{
972 return is_attr_func ("naked");
973}
974
975static inline bool
976is_reentrant_func (void)
977{
978 return is_attr_func ("reentrant");
979}
980
981static inline bool
982is_critical_func (void)
983{
984 return is_attr_func ("critical");
985}
986
e4a25868 987#undef TARGET_ASM_FUNCTION_PROLOGUE
988#define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function
989
990static void
991msp430_start_function (FILE *outfile, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
992{
993 int r, n;
994
995 fprintf (outfile, "; start of function\n");
62b2ccbe 996
997 if (DECL_ATTRIBUTES (current_function_decl) != NULL_TREE)
998 {
999 fprintf (outfile, "; attributes: ");
1000 if (is_naked_func ())
1001 fprintf (outfile, "naked ");
1002 if (msp430_is_interrupt_func ())
1003 fprintf (outfile, "interrupt ");
1004 if (is_reentrant_func ())
1005 fprintf (outfile, "reentrant ");
1006 if (is_critical_func ())
1007 fprintf (outfile, "critical ");
1008 fprintf (outfile, "\n");
1009 }
1010
e4a25868 1011 fprintf (outfile, "; framesize_regs: %d\n", cfun->machine->framesize_regs);
1012 fprintf (outfile, "; framesize_locals: %d\n", cfun->machine->framesize_locals);
1013 fprintf (outfile, "; framesize_outgoing: %d\n", cfun->machine->framesize_outgoing);
1014 fprintf (outfile, "; framesize: %d\n", cfun->machine->framesize);
1015 fprintf (outfile, "; elim ap -> fp %d\n", msp430_initial_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM));
1016 fprintf (outfile, "; elim fp -> sp %d\n", msp430_initial_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM));
1017
1018 n = 0;
1019 fprintf (outfile, "; saved regs:");
62b2ccbe 1020 for (r = 0; r < ARG_POINTER_REGNUM; r++)
e4a25868 1021 if (cfun->machine->need_to_save [r])
1022 {
1023 fprintf (outfile, " %s", reg_names [r]);
1024 n = 1;
1025 }
1026 if (n == 0)
1027 fprintf (outfile, "(none)");
1028 fprintf (outfile, "\n");
1029}
1030
1031/* Common code to change the stack pointer. */
1032static void
1033increment_stack (HOST_WIDE_INT amount)
1034{
1035 rtx inc;
1036 rtx sp = stack_pointer_rtx;
1037
1038 if (amount == 0)
1039 return;
1040
1041 if (amount < 0)
1042 {
1043 inc = GEN_INT (- amount);
1044 if (TARGET_LARGE)
1045 F (emit_insn (gen_subpsi3 (sp, sp, inc)));
1046 else
1047 F (emit_insn (gen_subhi3 (sp, sp, inc)));
1048 }
1049 else
1050 {
1051 inc = GEN_INT (amount);
1052 if (TARGET_LARGE)
1053 emit_insn (gen_addpsi3 (sp, sp, inc));
1054 else
1055 emit_insn (gen_addhi3 (sp, sp, inc));
1056 }
1057}
1058
62b2ccbe 1059/* Verify MSP430 specific attributes. */
1060
1061static tree
1062msp430_attr (tree * node,
1063 tree name,
1064 tree args,
1065 int flags ATTRIBUTE_UNUSED,
1066 bool * no_add_attrs)
1067{
1068 gcc_assert (DECL_P (* node));
1069
1070 if (args != NULL)
1071 {
1072 tree value = TREE_VALUE (args);
1073
1074 switch (TREE_CODE (value))
1075 {
1076 case STRING_CST:
1077 if ( strcmp (TREE_STRING_POINTER (value), "reset")
1078 && strcmp (TREE_STRING_POINTER (value), "nmi")
1079 && strcmp (TREE_STRING_POINTER (value), "watchdog"))
1080 /* Allow the attribute to be added - the linker script
1081 being used may still recognise this name. */
1082 warning (OPT_Wattributes,
1083 "unrecognised interrupt vector argument of %qE attribute",
1084 name);
1085 break;
1086
1087 case INTEGER_CST:
1088 if (TREE_INT_CST_LOW (value) > 31)
1089 /* Allow the attribute to be added - the linker script
1090 being used may still recognise this value. */
1091 warning (OPT_Wattributes,
1092 "numeric argument of %qE attribute must be in range 0..31",
1093 name);
1094 break;
1095
1096 default:
1097 warning (OPT_Wattributes,
1098 "argument of %qE attribute is not a string constant or number",
1099 name);
1100 *no_add_attrs = true;
1101 break;
1102 }
1103 }
1104
1105 if (TREE_CODE (* node) != FUNCTION_DECL)
1106 {
1107 warning (OPT_Wattributes,
1108 "%qE attribute only applies to functions",
1109 name);
1110 * no_add_attrs = true;
1111 }
1112
1113 /* FIXME: We ought to check that the interrupt handler
1114 attribute has been applied to a void function. */
1115 /* FIXME: We should check that reentrant and critical
1116 functions are not naked and that critical functions
1117 are not reentrant. */
1118
1119 return NULL_TREE;
1120}
1121
1122#undef TARGET_ATTRIBUTE_TABLE
1123#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table
1124
1125/* Table of MSP430-specific attributes. */
1126const struct attribute_spec msp430_attribute_table[] =
1127{
1128 /* Name min_len decl_req, fn_type_req, affects_type_identity
1129 max_len, type_req, handler. */
1130 { "interrupt", 0, 1, true, false, false, msp430_attr, false },
1131 { "naked", 0, 0, true, false, false, msp430_attr, false },
1132 { "reentrant", 0, 0, true, false, false, msp430_attr, false },
1133 { "critical", 0, 0, true, false, false, msp430_attr, false },
1134 { NULL, 0, 0, false, false, false, NULL, false }
1135};
1136
1137void
1138msp430_start_function (FILE *file, const char *name, tree decl)
1139{
1140 tree int_attr;
1141
1142 int_attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
1143 if (int_attr != NULL_TREE)
1144 {
1145 tree intr_vector = TREE_VALUE (int_attr);
1146
1147 if (intr_vector != NULL_TREE)
1148 {
1149 char buf[101];
1150
1151 intr_vector = TREE_VALUE (intr_vector);
1152
1153 /* The interrupt attribute has a vector value. Turn this into a
1154 section name, switch to that section and put the address of
1155 the current function into that vector slot. Note msp430_attr()
1156 has already verified the vector name for us. */
1157 if (TREE_CODE (intr_vector) == STRING_CST)
1158 sprintf (buf, "__interrupt_vector_%.80s",
1159 TREE_STRING_POINTER (intr_vector));
1160 else /* TREE_CODE (intr_vector) == INTEGER_CST */
1161 sprintf (buf, "__interrupt_vector_%u",
1162 (unsigned int) TREE_INT_CST_LOW (intr_vector));
1163
1164 switch_to_section (get_section (buf, SECTION_CODE, decl));
1165 fputs ("\t.word\t", file);
1166 assemble_name (file, name);
1167 fputc ('\n', file);
1168 fputc ('\t', file);
1169 }
1170 }
1171
1172 switch_to_section (function_section (decl));
1173 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
1174}
1175
1176static section *
1177msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit)
1178{
1179 /* In large mode we must make sure that interrupt handlers are put into
1180 low memory as the vector table only accepts 16-bit addresses. */
1181 if (TARGET_LARGE
1182 && lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl)))
1183 return get_section (".lowtext", SECTION_CODE | SECTION_WRITE , decl);
1184
1185 /* Otherwise, use the default function section. */
1186 return default_function_section (decl, freq, startup, exit);
1187}
1188
1189#undef TARGET_ASM_FUNCTION_SECTION
1190#define TARGET_ASM_FUNCTION_SECTION msp430_function_section
1191
1192enum msp430_builtin
1193{
1194 MSP430_BUILTIN_BIC_SR,
1195 MSP430_BUILTIN_BIS_SR,
1196 MSP430_BUILTIN_max
1197};
1198
1199static GTY(()) tree msp430_builtins [(int) MSP430_BUILTIN_max];
1200
1201static void
1202msp430_init_builtins (void)
1203{
1204 tree void_ftype_int = build_function_type_list (void_type_node, integer_type_node, NULL);
1205
1206 msp430_builtins[MSP430_BUILTIN_BIC_SR] =
1207 add_builtin_function ( "__bic_SR_register_on_exit", void_ftype_int,
1208 MSP430_BUILTIN_BIC_SR, BUILT_IN_MD, NULL, NULL_TREE);
1209
1210 msp430_builtins[MSP430_BUILTIN_BIS_SR] =
1211 add_builtin_function ( "__bis_SR_register_on_exit", void_ftype_int,
1212 MSP430_BUILTIN_BIS_SR, BUILT_IN_MD, NULL, NULL_TREE);
1213}
1214
1215static tree
1216msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED)
1217{
1218 switch (code)
1219 {
1220 case MSP430_BUILTIN_BIC_SR:
1221 case MSP430_BUILTIN_BIS_SR:
1222 return msp430_builtins[code];
1223 default:
1224 return error_mark_node;
1225 }
1226}
1227
1228static rtx
1229msp430_expand_builtin (tree exp,
1230 rtx target ATTRIBUTE_UNUSED,
1231 rtx subtarget ATTRIBUTE_UNUSED,
1232 enum machine_mode mode ATTRIBUTE_UNUSED,
1233 int ignore ATTRIBUTE_UNUSED)
1234{
1235 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1236 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
1237 rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
1238
1239 if (! msp430_is_interrupt_func ())
1240 {
1241 error ("MSP430 builtin functions only work inside interrupt handlers");
1242 return NULL_RTX;
1243 }
1244
1245 if (! REG_P (arg1) && ! CONSTANT_P (arg1))
1246 arg1 = force_reg (mode, arg1);
1247
1248 switch (fcode)
1249 {
1250 case MSP430_BUILTIN_BIC_SR: emit_insn (gen_bic_SR (arg1)); break;
1251 case MSP430_BUILTIN_BIS_SR: emit_insn (gen_bis_SR (arg1)); break;
1252 default:
1253 internal_error ("bad builtin code");
1254 break;
1255 }
1256 return NULL_RTX;
1257}
1258
1259#undef TARGET_INIT_BUILTINS
1260#define TARGET_INIT_BUILTINS msp430_init_builtins
1261
1262#undef TARGET_EXPAND_BUILTIN
1263#define TARGET_EXPAND_BUILTIN msp430_expand_builtin
1264
1265#undef TARGET_BUILTIN_DECL
1266#define TARGET_BUILTIN_DECL msp430_builtin_decl
1267
e4a25868 1268void
1269msp430_expand_prologue (void)
1270{
1271 int i, j;
1272 int fs;
1273 /* Always use stack_pointer_rtx instead of calling
1274 rtx_gen_REG ourselves. Code elsewhere in GCC assumes
1275 that there is a single rtx representing the stack pointer,
1276 namely stack_pointer_rtx, and uses == to recognize it. */
1277 rtx sp = stack_pointer_rtx;
1278 rtx p;
1279
62b2ccbe 1280 if (is_naked_func ())
1281 return;
1282
e4a25868 1283 emit_insn (gen_prologue_start_marker ());
1284
62b2ccbe 1285 if (is_critical_func ())
1286 {
1287 emit_insn (gen_push_intr_state ());
1288 emit_insn (gen_disable_interrupts ());
1289 }
1290 else if (is_reentrant_func ())
1291 emit_insn (gen_disable_interrupts ());
1292
e4a25868 1293 if (!cfun->machine->computed)
1294 msp430_compute_frame_info ();
1295
1296 if (flag_stack_usage_info)
1297 current_function_static_stack_size = cfun->machine->framesize;
1298
1299 if (crtl->args.pretend_args_size)
1300 {
1301 rtx note;
1302
1303 gcc_assert (crtl->args.pretend_args_size == 2);
1304
1305 p = emit_insn (gen_grow_and_swap ());
1306
1307 /* Document the stack decrement... */
1308 note = F (gen_rtx_SET (Pmode, stack_pointer_rtx,
1309 gen_rtx_MINUS (Pmode, stack_pointer_rtx, GEN_INT (2))));
1310 add_reg_note (p, REG_FRAME_RELATED_EXPR, note);
1311
1312 /* ...and the establishment of a new location for the return address. */
1313 note = F (gen_rtx_SET (Pmode, gen_rtx_MEM (Pmode,
1314 gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-2))),
1315 pc_rtx));
1316 add_reg_note (p, REG_CFA_OFFSET, note);
1317 F (p);
1318 }
1319
1320 for (i = 15; i >= 4; i--)
1321 if (cfun->machine->need_to_save [i])
1322 {
1323 int seq, count;
1324 rtx note;
1325
1326 for (seq = i - 1; seq >= 4 && cfun->machine->need_to_save[seq]; seq --)
1327 ;
1328 count = i - seq;
1329
1330 if (msp430x)
1331 {
1332 /* Note: with TARGET_LARGE we still use PUSHM as PUSHX.A is two bytes bigger. */
1333 p = F (emit_insn (gen_pushm (gen_rtx_REG (Pmode, i),
1334 GEN_INT (count))));
1335
1336 note = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
1337
1338 XVECEXP (note, 0, 0)
1339 = F (gen_rtx_SET (VOIDmode,
1340 stack_pointer_rtx,
1341 gen_rtx_PLUS (Pmode,
1342 stack_pointer_rtx,
1343 GEN_INT (count * (TARGET_LARGE ? -4 : -2)))));
1344
1345 /* *sp-- = R[i-j] */
1346 /* sp+N R10
1347 ...
1348 sp R4 */
1349 for (j = 0; j < count; j ++)
1350 {
1351 rtx addr;
1352 int ofs = (count - j - 1) * (TARGET_LARGE ? 4 : 2);
1353
1354 if (ofs)
1355 addr = gen_rtx_PLUS (Pmode, sp, GEN_INT (ofs));
1356 else
1357 addr = stack_pointer_rtx;
1358
1359 XVECEXP (note, 0, j + 1) =
1360 F (gen_rtx_SET (VOIDmode,
1361 gen_rtx_MEM (Pmode, addr),
1362 gen_rtx_REG (Pmode, i - j)) );
1363 }
1364
1365 add_reg_note (p, REG_FRAME_RELATED_EXPR, note);
1366 i -= count - 1;
1367 }
1368 else
1369 F (emit_insn (gen_push (gen_rtx_REG (Pmode, i))));
1370 }
1371
1372 if (frame_pointer_needed)
1373 F (emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM), sp));
1374
1375 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1376
1377 increment_stack (- fs);
1378
1379 emit_insn (gen_prologue_end_marker ());
1380}
1381
1382void
1383msp430_expand_epilogue (int is_eh)
1384{
1385 int i;
1386 int fs;
1387 int helper_n = 0;
1388
62b2ccbe 1389 if (is_naked_func ())
1390 return;
1391
e4a25868 1392 if (cfun->machine->need_to_save [10])
1393 {
1394 /* Check for a helper function. */
9b52871c 1395 helper_n = 7; /* For when the loop below never sees a match. */
e4a25868 1396 for (i = 9; i >= 4; i--)
1397 if (!cfun->machine->need_to_save [i])
1398 {
1399 helper_n = 10 - i;
1400 for (; i >= 4; i--)
1401 if (cfun->machine->need_to_save [i])
1402 {
1403 helper_n = 0;
1404 break;
1405 }
1406 break;
1407 }
1408 }
1409
1410 emit_insn (gen_epilogue_start_marker ());
1411
1412 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1413
1414 increment_stack (fs);
1415
1416 if (is_eh)
1417 {
1418 /* We need to add the right "SP" register save just after the
1419 regular ones, so that when we pop it off we're in the EH
1420 return frame, not this one. This overwrites our own return
1421 address, but we're not going to be returning anyway. */
1422 rtx r12 = gen_rtx_REG (Pmode, 12);
1423 rtx (*addPmode)(rtx, rtx, rtx) = TARGET_LARGE ? gen_addpsi3 : gen_addhi3;
1424
1425 /* R12 will hold the new SP. */
1426 i = cfun->machine->framesize_regs;
1427 emit_move_insn (r12, stack_pointer_rtx);
1428 emit_insn (addPmode (r12, r12, EH_RETURN_STACKADJ_RTX));
1429 emit_insn (addPmode (r12, r12, GEN_INT (i)));
1430 emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (Pmode, stack_pointer_rtx, i)), r12);
1431 }
1432
1433 for (i = 4; i <= 15; i++)
1434 if (cfun->machine->need_to_save [i])
1435 {
1436 int seq, count;
1437
1438 for (seq = i + 1; seq <= 15 && cfun->machine->need_to_save[seq]; seq ++)
1439 ;
1440 count = seq - i;
1441
1442 if (msp430x)
1443 {
1444 /* Note: With TARGET_LARGE we still use POPM as POPX.A is two
1445 bytes bigger.
1446 Note: See the popm pattern for the explanation of the strange
1447 arguments. */
1448 emit_insn (gen_popm (stack_pointer_rtx, GEN_INT (~(seq - 1)),
1449 GEN_INT (count)));
1450 i += count - 1;
1451 }
1452 else if (i == 11 - helper_n
62b2ccbe 1453 && ! msp430_is_interrupt_func ()
1454 && ! is_reentrant_func ()
1455 && ! is_critical_func ()
e4a25868 1456 && crtl->args.pretend_args_size == 0
1457 /* Calling the helper takes as many bytes as the POP;RET sequence. */
9b52871c 1458 && helper_n > 1
e4a25868 1459 && !is_eh)
1460 {
1461 emit_insn (gen_epilogue_helper (GEN_INT (helper_n)));
1462 return;
1463 }
1464 else
1465 emit_insn (gen_pop (gen_rtx_REG (Pmode, i)));
1466 }
1467
1468 if (is_eh)
1469 {
1470 /* Also pop SP, which puts us into the EH return frame. Except
1471 that you can't "pop" sp, you have to just load it off the
1472 stack. */
1473 emit_move_insn (stack_pointer_rtx, gen_rtx_MEM (Pmode, stack_pointer_rtx));
1474 }
1475
1476 if (crtl->args.pretend_args_size)
1477 emit_insn (gen_swap_and_shrink ());
62b2ccbe 1478
1479 if (is_critical_func ())
1480 emit_insn (gen_pop_intr_state ());
1481 else if (is_reentrant_func ())
1482 emit_insn (gen_enable_interrupts ());
1483
e4a25868 1484 emit_jump_insn (gen_msp_return ());
1485}
1486
1487/* Implements EH_RETURN_STACKADJ_RTX. Saved and used later in
1488 m32c_emit_eh_epilogue. */
1489rtx
1490msp430_eh_return_stackadj_rtx (void)
1491{
1492 if (!cfun->machine->eh_stack_adjust)
1493 {
1494 rtx sa;
1495
1496 sa = gen_rtx_REG (Pmode, 15);
1497 cfun->machine->eh_stack_adjust = sa;
1498 }
1499 return cfun->machine->eh_stack_adjust;
1500}
1501
1502/* This function is called before reload, to "fix" the stack in
1503 preparation for an EH return. */
1504void
1505msp430_expand_eh_return (rtx eh_handler)
1506{
1507 /* These are all Pmode */
1508 rtx ap, sa, ra, tmp;
1509
1510 ap = arg_pointer_rtx;
1511 sa = msp430_eh_return_stackadj_rtx ();
1512 ra = eh_handler;
1513
1514 tmp = ap;
1515 tmp = gen_rtx_PLUS (Pmode, ap, sa);
1516 tmp = plus_constant (Pmode, tmp, TARGET_LARGE ? -4 : -2);
1517 tmp = gen_rtx_MEM (Pmode, tmp);
1518 emit_move_insn (tmp, ra);
1519}
1520
1521/* This is a list of MD patterns that implement fixed-count shifts. */
62b2ccbe 1522static struct
1523{
e4a25868 1524 const char *name;
1525 int count;
1526 int need_430x;
1527 rtx (*genfunc)(rtx,rtx);
62b2ccbe 1528}
1529 const_shift_helpers[] =
1530{
e4a25868 1531#define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }
1532
1533 CSH ("slli", 1, 1, slli_1),
1534 CSH ("slll", 1, 1, slll_1),
1535 CSH ("slll", 2, 1, slll_2),
1536
1537 CSH ("srai", 1, 0, srai_1),
1538 CSH ("sral", 1, 0, sral_1),
1539 CSH ("sral", 2, 0, sral_2),
1540
1541 CSH ("srll", 1, 0, srll_1),
1542 CSH ("srll", 2, 1, srll_2x),
1543 { 0, 0, 0, 0 }
1544#undef CSH
1545};
1546
1547/* The MSP430 ABI defines a number of helper functions that should be
1548 used for, for example, 32-bit shifts. This function is called to
1549 emit such a function, using the table above to optimize some
1550 cases. */
1551void
1552msp430_expand_helper (rtx *operands, const char *helper_name, bool const_variants)
1553{
1554 rtx c, f;
1555 char *helper_const = NULL;
1556 int arg2 = 13;
1557 int arg1sz = 1;
1558 enum machine_mode arg0mode = GET_MODE (operands[0]);
1559 enum machine_mode arg1mode = GET_MODE (operands[1]);
1560 enum machine_mode arg2mode = GET_MODE (operands[2]);
1561 int have_430x = msp430x ? 1 : 0;
1562
1563 if (CONST_INT_P (operands[2]))
1564 {
1565 int i;
1566
1567 for (i=0; const_shift_helpers[i].name; i++)
1568 {
1569 if (const_shift_helpers[i].need_430x <= have_430x
1570 && strcmp (helper_name, const_shift_helpers[i].name) == 0
1571 && INTVAL (operands[2]) == const_shift_helpers[i].count)
1572 {
1573 emit_insn (const_shift_helpers[i].genfunc (operands[0], operands[1]));
1574 return;
1575 }
1576 }
1577 }
1578
1579 if (arg1mode == VOIDmode)
1580 arg1mode = arg0mode;
1581 if (arg2mode == VOIDmode)
1582 arg2mode = arg0mode;
1583
1584 if (arg1mode == SImode)
1585 {
1586 arg2 = 14;
1587 arg1sz = 2;
1588 }
1589
1590 if (const_variants
1591 && CONST_INT_P (operands[2])
1592 && INTVAL (operands[2]) >= 1
1593 && INTVAL (operands[2]) <= 15)
1594 {
1595 /* Note that the INTVAL is limited in value and length by the conditional above. */
1596 int len = strlen (helper_name) + 4;
1597 helper_const = (char *) xmalloc (len);
9b52871c 1598 snprintf (helper_const, len, "%s_%d", helper_name, (int) INTVAL (operands[2]));
e4a25868 1599 }
1600
1601 emit_move_insn (gen_rtx_REG (arg1mode, 12),
1602 operands[1]);
1603 if (!helper_const)
1604 emit_move_insn (gen_rtx_REG (arg2mode, arg2),
1605 operands[2]);
1606
1607 c = gen_call_value_internal (gen_rtx_REG (arg0mode, 12),
1608 gen_rtx_SYMBOL_REF (VOIDmode, helper_const ? helper_const : helper_name),
1609 GEN_INT (0));
1610 c = emit_call_insn (c);
1611 RTL_CONST_CALL_P (c) = 1;
1612
1613 f = 0;
1614 use_regs (&f, 12, arg1sz);
1615 if (!helper_const)
1616 use_regs (&f, arg2, 1);
1617 add_function_usage_to (c, f);
1618
1619 emit_move_insn (operands[0],
1620 gen_rtx_REG (arg0mode, 12));
1621}
1622
1623/* Called by cbranch<mode>4 to coerce operands into usable forms. */
1624void
1625msp430_fixup_compare_operands (enum machine_mode my_mode, rtx * operands)
1626{
1627 /* constants we're looking for, not constants which are allowed. */
1628 int const_op_idx = 1;
1629
1630 if (msp430_reversible_cmp_operator (operands[0], VOIDmode))
1631 const_op_idx = 2;
1632
1633 if (GET_CODE (operands[const_op_idx]) != REG
1634 && GET_CODE (operands[const_op_idx]) != MEM)
1635 operands[const_op_idx] = copy_to_mode_reg (my_mode, operands[const_op_idx]);
1636}
1637
1638/* Simplify_gen_subreg() doesn't handle memory references the way we
1639 need it to below, so we use this function for when we must get a
1640 valid subreg in a "natural" state. */
1641rtx
1642msp430_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte)
1643{
1644 rtx rv;
1645
1646 if (GET_CODE (r) == SUBREG
1647 && SUBREG_BYTE (r) == 0)
1648 {
1649 rtx ireg = SUBREG_REG (r);
1650 enum machine_mode imode = GET_MODE (ireg);
1651
1652 /* special case for (HI (SI (PSI ...), 0)) */
1653 if (imode == PSImode
1654 && mode == HImode
1655 && byte == 0)
1656 rv = gen_rtx_SUBREG (mode, ireg, byte);
1657 else
1658 rv = simplify_gen_subreg (mode, ireg, imode, byte);
1659 }
1660 else if (GET_CODE (r) == MEM)
1661 rv = adjust_address (r, mode, byte);
1662 else
1663 rv = simplify_gen_subreg (mode, r, omode, byte);
1664
1665 if (!rv)
1666 gcc_unreachable ();
1667
1668 return rv;
1669}
1670
1671/* Called by movsi_x to generate the HImode operands. */
1672void
1673msp430_split_movsi (rtx *operands)
1674{
1675 rtx op00, op02, op10, op12;
1676
1677 op00 = msp430_subreg (HImode, operands[0], SImode, 0);
1678 op02 = msp430_subreg (HImode, operands[0], SImode, 2);
1679
1680 if (GET_CODE (operands[1]) == CONST
1681 || GET_CODE (operands[1]) == SYMBOL_REF)
1682 {
1683 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
1684 op10 = gen_rtx_CONST (HImode, op10);
1685 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
1686 op12 = gen_rtx_CONST (HImode, op12);
1687 }
1688 else
1689 {
1690 op10 = msp430_subreg (HImode, operands[1], SImode, 0);
1691 op12 = msp430_subreg (HImode, operands[1], SImode, 2);
1692 }
1693
1694 if (rtx_equal_p (operands[0], operands[1]))
1695 {
1696 operands[2] = op02;
1697 operands[4] = op12;
1698 operands[3] = op00;
1699 operands[5] = op10;
1700 }
1701 else if (rtx_equal_p (op00, op12)
1702 /* Catch the case where we are loading (rN, rN+1) from mem (rN). */
1703 || (REG_P (op00) && reg_mentioned_p (op00, op10))
1704 /* Or storing (rN) into mem (rN). */
1705 || (REG_P (op10) && reg_mentioned_p (op10, op00))
1706 )
1707 {
1708 operands[2] = op02;
1709 operands[4] = op12;
1710 operands[3] = op00;
1711 operands[5] = op10;
1712 }
1713 else
1714 {
1715 operands[2] = op00;
1716 operands[4] = op10;
1717 operands[3] = op02;
1718 operands[5] = op12;
1719 }
1720}
1721
1722\f
e4a25868 1723/* The MSPABI specifies the names of various helper functions, many of
1724 which are compatible with GCC's helpers. This table maps the GCC
1725 name to the MSPABI name. */
1726static const struct
1727{
1728 char const * const gcc_name;
1729 char const * const ti_name;
1730}
1731 helper_function_name_mappings [] =
1732{
1733 /* Floating point to/from integer conversions. */
1734 { "__truncdfsf2", "__mspabi_cvtdf" },
1735 { "__extendsfdf2", "__mspabi_cvtfd" },
1736 { "__fixdfhi", "__mspabi_fixdi" },
1737 { "__fixdfsi", "__mspabi_fixdli" },
1738 { "__fixdfdi", "__mspabi_fixdlli" },
1739 { "__fixunsdfhi", "__mspabi_fixdu" },
1740 { "__fixunsdfsi", "__mspabi_fixdul" },
1741 { "__fixunsdfdi", "__mspabi_fixdull" },
1742 { "__fixsfhi", "__mspabi_fixfi" },
1743 { "__fixsfsi", "__mspabi_fixfli" },
1744 { "__fixsfdi", "__mspabi_fixflli" },
1745 { "__fixunsfhi", "__mspabi_fixfu" },
1746 { "__fixunsfsi", "__mspabi_fixful" },
1747 { "__fixunsfdi", "__mspabi_fixfull" },
1748 { "__floathisf", "__mspabi_fltif" },
1749 { "__floatsisf", "__mspabi_fltlif" },
1750 { "__floatdisf", "__mspabi_fltllif" },
1751 { "__floathidf", "__mspabi_fltid" },
1752 { "__floatsidf", "__mspabi_fltlid" },
1753 { "__floatdidf", "__mspabi_fltllid" },
1754 { "__floatunhisf", "__mspabi_fltuf" },
1755 { "__floatunsisf", "__mspabi_fltulf" },
1756 { "__floatundisf", "__mspabi_fltullf" },
1757 { "__floatunhidf", "__mspabi_fltud" },
1758 { "__floatunsidf", "__mspabi_fltuld" },
1759 { "__floatundidf", "__mspabi_fltulld" },
1760
1761 /* Floating point comparisons. */
1762 /* GCC uses individual functions for each comparison, TI uses one
1763 compare <=> function. */
1764
1765 /* Floating point arithmatic */
1766 { "__adddf3", "__mspabi_addd" },
1767 { "__addsf3", "__mspabi_addf" },
1768 { "__divdf3", "__mspabi_divd" },
1769 { "__divsf3", "__mspabi_divf" },
1770 { "__muldf3", "__mspabi_mpyd" },
1771 { "__mulsf3", "__mspabi_mpyf" },
1772 { "__subdf3", "__mspabi_subd" },
1773 { "__subsf3", "__mspabi_subf" },
1774 /* GCC does not use helper functions for negation */
1775
1776 /* Integer multiply, divide, remainder. */
1777 /* Note: gcc doesn't know about hardware multiply options (yet?) */
1778 { "__mulhi3", "__mspabi_mpyi" },
1779 { "__mulsi3", "__mspabi_mpyl" },
1780 { "__muldi3", "__mspabi_mpyll" },
1781#if 0
1782 /* Clarify signed vs unsigned first. */
1783 { "__mulhisi3", "__mspabi_mpysl" }, /* gcc doesn't use widening multiply (yet?) */
1784 { "__mulsidi3", "__mspabi_mpysll" }, /* gcc doesn't use widening multiply (yet?) */
1785#endif
1786
1787 { "__divhi3", "__mspabi_divi" },
1788 { "__divsi3", "__mspabi_divli" },
1789 { "__divdi3", "__mspabi_divlli" },
1790 { "__udivhi3", "__mspabi_divu" },
1791 { "__udivsi3", "__mspabi_divlu" },
1792 { "__udivdi3", "__mspabi_divllu" },
1793 { "__modhi3", "__mspabi_remi" },
1794 { "__modsi3", "__mspabi_remli" },
1795 { "__moddi3", "__mspabi_remlli" },
1796 { "__umodhi3", "__mspabi_remu" },
1797 { "__umodsi3", "__mspabi_remul" },
1798 { "__umoddi3", "__mspabi_remull" },
1799
1800 /* Bitwise operations. */
1801 /* Rotation - no rotation support yet. */
1802 /* Logical left shift - gcc already does these itself. */
1803 /* Arithmetic left shift - gcc already does these itself. */
1804 /* Arithmetic right shift - gcc already does these itself. */
1805
1806 { NULL, NULL }
1807};
1808
1809/* This function does the same as the default, but it will replace GCC
1810 function names with the MSPABI-specified ones. */
1811void
1812msp430_output_labelref (FILE *file, const char *name)
1813{
1814 int i;
1815
1816 for (i = 0; helper_function_name_mappings [i].gcc_name; i++)
1817 if (! strcmp (helper_function_name_mappings [i].gcc_name, name))
1818 {
1819 fputs (helper_function_name_mappings [i].ti_name, file);
1820 return;
1821 }
1822
1823 fputs (name, file);
1824}
1825
9b52871c 1826/* Common code for msp430_print_operand... */
e4a25868 1827
e4a25868 1828static void
9b52871c 1829msp430_print_operand_raw (FILE * file, rtx op)
e4a25868 1830{
1831 int i;
1832
1833 switch (GET_CODE (op))
1834 {
1835 case REG:
1836 fprintf (file, "%s", reg_names [REGNO (op)]);
1837 break;
1838
1839 case CONST_INT:
1840 i = INTVAL (op);
1841 if (TARGET_ASM_HEX)
1842 fprintf (file, "%#x", i);
1843 else
1844 fprintf (file, "%d", i);
1845 break;
1846
1847 case CONST:
1848 case PLUS:
1849 case MINUS:
1850 case SYMBOL_REF:
1851 case LABEL_REF:
1852 output_addr_const (file, op);
1853 break;
1854
1855 default:
1856 print_rtl (file, op);
1857 break;
1858 }
1859}
1860
9b52871c 1861#undef TARGET_PRINT_OPERAND_ADDRESS
1862#define TARGET_PRINT_OPERAND_ADDRESS msp430_print_operand_addr
1863
1864/* Output to stdio stream FILE the assembler syntax for an
1865 instruction operand that is a memory reference whose address
1866 is ADDR. */
1867
1868static void
1869msp430_print_operand_addr (FILE * file, rtx addr)
1870{
1871 switch (GET_CODE (addr))
1872 {
1873 case PLUS:
1874 msp430_print_operand_raw (file, XEXP (addr, 1));
1875 gcc_assert (REG_P (XEXP (addr, 0)));
1876 fprintf (file, "(%s)", reg_names [REGNO (XEXP (addr, 0))]);
1877 return;
1878
1879 case REG:
1880 fprintf (file, "@");
1881 break;
1882
1883 case CONST:
1884 case CONST_INT:
1885 case SYMBOL_REF:
1886 case LABEL_REF:
1887 fprintf (file, "&");
1888 break;
1889
1890 default:
1891 break;
1892 }
1893
1894 msp430_print_operand_raw (file, addr);
1895}
1896
1897#undef TARGET_PRINT_OPERAND
1898#define TARGET_PRINT_OPERAND msp430_print_operand
1899
e4a25868 1900static void
1901msp430_print_operand (FILE * file, rtx op, int letter)
1902{
1903 rtx addr;
1904
1905 /* We can't use c, n, a, or l. */
1906 switch (letter)
1907 {
1908 case 'Z':
1909 gcc_assert (CONST_INT_P (op));
1910 /* Print the constant value, less one. */
1911 fprintf (file, "#%ld", INTVAL (op) - 1);
1912 return;
1913 case 'Y':
1914 gcc_assert (CONST_INT_P (op));
1915 /* Print the constant value, less four. */
1916 fprintf (file, "#%ld", INTVAL (op) - 4);
1917 return;
1918 /* case 'D': used for "decimal without '#'" */
1919 case 'I':
1920 if (GET_CODE (op) == CONST_INT)
1921 {
1922 /* Inverse of constants */
1923 int i = INTVAL (op);
1924 fprintf (file, "%d", ~i);
1925 return;
1926 }
1927 op = XEXP (op, 0);
1928 break;
1929 case 'r': /* Conditional jump where the condition is reversed. */
1930 switch (GET_CODE (op))
1931 {
1932 case EQ: fprintf (file, "NE"); break;
1933 case NE: fprintf (file, "EQ"); break;
1934 case GEU: fprintf (file, "LO"); break;
1935 case LTU: fprintf (file, "HS"); break;
1936 case GE: fprintf (file, "L"); break;
1937 case LT: fprintf (file, "GE"); break;
1938 /* Assume these have reversed operands. */
1939 case GTU: fprintf (file, "HS"); break;
1940 case LEU: fprintf (file, "LO"); break;
1941 case GT: fprintf (file, "GE"); break;
1942 case LE: fprintf (file, "L"); break;
1943 default:
9b52871c 1944 msp430_print_operand_raw (file, op);
e4a25868 1945 break;
1946 }
1947 return;
1948 case 'R': /* Conditional jump where the operands are reversed. */
1949 switch (GET_CODE (op))
1950 {
1951 case GTU: fprintf (file, "LO"); break;
1952 case LEU: fprintf (file, "HS"); break;
1953 case GT: fprintf (file, "L"); break;
1954 case LE: fprintf (file, "GE"); break;
1955 default:
9b52871c 1956 msp430_print_operand_raw (file, op);
e4a25868 1957 break;
1958 }
1959 return;
1960 case 'p': /* Bit position. 0 == 0x01, 3 = 0x08 etc. */
1961 gcc_assert (CONST_INT_P (op));
1962 fprintf (file, "#%d", 1 << INTVAL (op));
1963 return;
1964 case 'B':
1965 switch (GET_MODE (op))
1966 {
1967 case QImode: fprintf (file, ".B"); return;
1968 case HImode: fprintf (file, ".W"); return;
1969 case PSImode: fprintf (file, ".A"); return;
1970 case SImode: fprintf (file, ".A"); return;
1971 default:
1972 return;
1973 }
1974 case 'L': /* Low half. */
1975 switch (GET_CODE (op))
1976 {
1977 case MEM:
1978 op = adjust_address (op, Pmode, 0);
1979 break;
1980 case REG:
1981 break;
1982 case CONST_INT:
1983 op = GEN_INT (INTVAL (op) & 0xffff);
1984 letter = 0;
1985 break;
1986 default:
1987 /* If you get here, figure out a test case :-) */
1988 gcc_unreachable ();
1989 }
1990 break;
1991 case 'H': /* high half */
1992 switch (GET_CODE (op))
1993 {
1994 case MEM:
1995 op = adjust_address (op, Pmode, 2);
1996 break;
1997 case REG:
1998 op = gen_rtx_REG (Pmode, REGNO (op) + 1);
1999 break;
2000 case CONST_INT:
2001 op = GEN_INT (INTVAL (op) >> 16);
2002 letter = 0;
2003 break;
2004 default:
2005 /* If you get here, figure out a test case :-) */
2006 gcc_unreachable ();
2007 }
2008 break;
2009
2010 case 'X':
2011 /* This is used to turn, for example, an ADD opcode into an ADDX
2012 opcode when we're using 20-bit addresses. */
2013 if (TARGET_LARGE)
2014 fprintf (file, "X");
2015 /* We don't care which operand we use, but we want 'X' in the MD
2016 file, so we do it this way. */
2017 return;
2018
2019 case 'x':
2020 /* Similarly, but only for PSImodes. BIC, for example, needs this. */
2021 if (TARGET_LARGE && GET_MODE (op) == PSImode)
2022 fprintf (file, "X");
2023 return;
2024
2025 case 'A':
2026 /* Likewise, for BR -> BRA. */
2027 if (TARGET_LARGE)
2028 fprintf (file, "A");
2029 return;
62b2ccbe 2030
2031 case 'O':
2032 /* Computes the offset to the top of the stack for the current frame.
2033 This has to be done here rather than in, say, msp430_expand_builtin()
2034 because builtins are expanded before the frame layout is determined. */
2035 fprintf (file, "%d",
2036 msp430_initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM)
2037 - 2);
9b52871c 2038 return;
e4a25868 2039 }
2040
2041 switch (GET_CODE (op))
2042 {
2043 case REG:
9b52871c 2044 msp430_print_operand_raw (file, op);
e4a25868 2045 break;
2046
2047 case MEM:
2048 addr = XEXP (op, 0);
9b52871c 2049 msp430_print_operand_addr (file, addr);
e4a25868 2050 break;
2051
2052 case CONST_INT:
2053 case CONST:
2054 case SYMBOL_REF:
2055 case LABEL_REF:
2056 if (letter == 0)
2057 fprintf (file, "#");
9b52871c 2058 msp430_print_operand_raw (file, op);
e4a25868 2059 break;
2060
2061 case EQ: fprintf (file, "EQ"); break;
2062 case NE: fprintf (file, "NE"); break;
2063 case GEU: fprintf (file, "HS"); break;
2064 case LTU: fprintf (file, "LO"); break;
2065 case GE: fprintf (file, "GE"); break;
2066 case LT: fprintf (file, "L"); break;
2067
2068 default:
2069 print_rtl (file, op);
2070 break;
2071 }
e4a25868 2072}
2073
2074\f
2075/* Frame stuff. */
2076
2077rtx
2078msp430_return_addr_rtx (int count)
2079{
2080 int ra_size;
2081 if (count)
2082 return NULL_RTX;
2083
2084 ra_size = TARGET_LARGE ? 4 : 2;
2085 if (crtl->args.pretend_args_size)
2086 ra_size += 2;
2087
2088 return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (- ra_size)));
2089}
2090
2091rtx
2092msp430_incoming_return_addr_rtx (void)
2093{
2094 return gen_rtx_MEM (Pmode, stack_pointer_rtx);
2095}
2096\f
2097/* Instruction generation stuff. */
2098
2099/* Generate a sequence of instructions to sign-extend an HI
2100 value into an SI value. Handles the tricky case where
2101 we are overwriting the destination. */
2102
2103const char *
2104msp430x_extendhisi (rtx * operands)
2105{
2106 if (REGNO (operands[0]) == REGNO (operands[1]))
2107 /* Low word of dest == source word. */
2108 return "BIT.W #0x8000, %L0 { SUBC.W %H0, %H0 { INV.W %H0, %H0"; /* 8-bytes. */
2109
2110 if (! msp430x)
2111 /* Note: This sequence is approximately the same length as invoking a helper
2112 function to perform the sign-extension, as in:
2113
2114 MOV.W %1, %L0
2115 MOV.W %1, r12
2116 CALL __mspabi_srai_15
2117 MOV.W r12, %H0
2118
2119 but this version does not involve any function calls or using argument
2120 registers, so it reduces register pressure. */
2121 return "MOV.W %1, %L0 { BIT.W #0x8000, %L0 { SUBC.W %H0, %H0 { INV.W %H0, %H0"; /* 10-bytes. */
2122
2123 if (REGNO (operands[0]) + 1 == REGNO (operands[1]))
2124 /* High word of dest == source word. */
2125 return "MOV.W %1, %L0 { RPT #15 { RRAX.W %H0"; /* 6-bytes. */
2126
2127 /* No overlap between dest and source. */
2128 return "MOV.W %1, %L0 { MOV.W %1, %H0 { RPT #15 { RRAX.W %H0"; /* 8-bytes. */
2129}
2130
2131/* Likewise for logical right shifts. */
2132const char *
2133msp430x_logical_shift_right (rtx amount)
2134{
2135 /* The MSP430X's logical right shift instruction - RRUM - does
2136 not use an extension word, so we cannot encode a repeat count.
2137 Try various alternatives to work around this. If the count
2138 is in a register we are stuck, hence the assert. */
2139 gcc_assert (CONST_INT_P (amount));
2140
2141 if (INTVAL (amount) <= 0
2142 || INTVAL (amount) >= 16)
2143 return "# nop logical shift.";
2144
2145 if (INTVAL (amount) > 0
2146 && INTVAL (amount) < 5)
2147 return "rrum.w\t%2, %0"; /* Two bytes. */
2148
2149 if (INTVAL (amount) > 4
2150 && INTVAL (amount) < 9)
2151 return "rrum.w\t#4, %0 { rrum.w\t%Y2, %0 "; /* Four bytes. */
2152
2153 /* First we logically shift right by one. Now we know
2154 that the top bit is zero and we can use the arithmetic
2155 right shift instruction to perform the rest of the shift. */
2156 return "rrum.w\t#1, %0 { rpt\t%Z2 { rrax.w\t%0"; /* Six bytes. */
2157}
2158\f
2159struct gcc_target targetm = TARGET_INITIALIZER;
2160
2161#include "gt-msp430.h"