]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/msp430/msp430.c
genattrtab.c (write_header): Include hash-set.h...
[thirdparty/gcc.git] / gcc / config / msp430 / msp430.c
CommitLineData
f6a83b4a 1/* Subroutines used for code generation on TI MSP430 processors.
5624e564 2 Copyright (C) 2012-2015 Free Software Foundation, Inc.
f6a83b4a
DD
3 Contributed by Red Hat.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
40e23961
MC
25#include "hash-set.h"
26#include "machmode.h"
27#include "vec.h"
28#include "double-int.h"
29#include "input.h"
30#include "alias.h"
31#include "symtab.h"
32#include "wide-int.h"
33#include "inchash.h"
f6a83b4a 34#include "tree.h"
40e23961 35#include "fold-const.h"
d8a2d370
DN
36#include "stor-layout.h"
37#include "calls.h"
f6a83b4a
DD
38#include "rtl.h"
39#include "regs.h"
40#include "hard-reg-set.h"
41#include "insn-config.h"
42#include "conditions.h"
43#include "output.h"
44#include "insn-attr.h"
45#include "flags.h"
83685514 46#include "input.h"
f6a83b4a
DD
47#include "function.h"
48#include "expr.h"
b0710fe1 49#include "insn-codes.h"
f6a83b4a
DD
50#include "optabs.h"
51#include "libfuncs.h"
52#include "recog.h"
53#include "diagnostic-core.h"
54#include "toplev.h"
55#include "reload.h"
60393bbc
AM
56#include "dominance.h"
57#include "cfg.h"
58#include "cfgrtl.h"
59#include "cfganal.h"
60#include "lcm.h"
61#include "cfgbuild.h"
62#include "cfgcleanup.h"
63#include "predict.h"
64#include "basic-block.h"
f6a83b4a
DD
65#include "df.h"
66#include "ggc.h"
67#include "tm_p.h"
68#include "debug.h"
69#include "target.h"
70#include "target-def.h"
71#include "langhooks.h"
72#include "msp430-protos.h"
73#include "dumpfile.h"
74#include "opts.h"
9b2b7279 75#include "builtins.h"
f6a83b4a
DD
76\f
77
78static void msp430_compute_frame_info (void);
79
80\f
81
c6f709ec 82/* Run-time Target Specification. */
f6a83b4a 83
c6f709ec 84bool msp430x = true;
f6a83b4a
DD
85
86struct GTY(()) machine_function
87{
88 /* If set, the rest of the fields have been computed. */
89 int computed;
90 /* Which registers need to be saved in the pro/epilogue. */
91 int need_to_save [FIRST_PSEUDO_REGISTER];
92
93 /* These fields describe the frame layout... */
94 /* arg pointer */
95 /* 2/4 bytes for saved PC */
96 int framesize_regs;
97 /* frame pointer */
98 int framesize_locals;
99 int framesize_outgoing;
100 /* stack pointer */
101 int framesize;
102
103 /* How much we adjust the stack when returning from an exception
104 handler. */
105 rtx eh_stack_adjust;
106};
107
108/* This is our init_machine_status, as set in
109 msp_option_override. */
110static struct machine_function *
111msp430_init_machine_status (void)
112{
113 struct machine_function *m;
114
766090c2 115 m = ggc_cleared_alloc<machine_function> ();
f6a83b4a
DD
116
117 return m;
118}
119
f6a83b4a
DD
120#undef TARGET_OPTION_OVERRIDE
121#define TARGET_OPTION_OVERRIDE msp430_option_override
122
c6f709ec
NC
123static const char * msp430_mcu_names [] =
124{
125"msp430afe221", "msp430afe222", "msp430afe223", "msp430afe231",
126"msp430afe232", "msp430afe233", "msp430afe251", "msp430afe252",
127"msp430afe253", "msp430c091", "msp430c092", "msp430c111",
128"msp430c1111", "msp430c112", "msp430c1121", "msp430c1331",
129"msp430c1351", "msp430c311s", "msp430c312", "msp430c313",
130"msp430c314", "msp430c315", "msp430c323", "msp430c325",
131"msp430c336", "msp430c337", "msp430c412", "msp430c413",
132"msp430e112", "msp430e313", "msp430e315", "msp430e325",
133"msp430e337", "msp430f110", "msp430f1101", "msp430f1101a",
134"msp430f1111", "msp430f1111a", "msp430f112", "msp430f1121",
135"msp430f1121a", "msp430f1122", "msp430f1132", "msp430f122",
136"msp430f1222", "msp430f123", "msp430f1232", "msp430f133",
137"msp430f135", "msp430f147", "msp430f1471", "msp430f148",
138"msp430f1481", "msp430f149", "msp430f1491", "msp430f155",
139"msp430f156", "msp430f157", "msp430f1610", "msp430f1611",
140"msp430f1612", "msp430f167", "msp430f168", "msp430f169",
141"msp430f2001", "msp430f2002", "msp430f2003", "msp430f2011",
142"msp430f2012", "msp430f2013", "msp430f2101", "msp430f2111",
143"msp430f2112", "msp430f2121", "msp430f2122", "msp430f2131",
144"msp430f2132", "msp430f2232", "msp430f2234", "msp430f2252",
145"msp430f2254", "msp430f2272", "msp430f2274", "msp430f233",
146"msp430f2330", "msp430f235", "msp430f2350", "msp430f2370",
147"msp430f2410", "msp430f247", "msp430f2471", "msp430f248",
148"msp430f2481", "msp430f249", "msp430f2491", "msp430f412",
149"msp430f413", "msp430f4132", "msp430f415", "msp430f4152",
150"msp430f417", "msp430f423", "msp430f423a", "msp430f425",
151"msp430f4250", "msp430f425a", "msp430f4260", "msp430f427",
152"msp430f4270", "msp430f427a", "msp430f435", "msp430f4351",
153"msp430f436", "msp430f4361", "msp430f437", "msp430f4371",
154"msp430f438", "msp430f439", "msp430f447", "msp430f448",
155"msp430f4481", "msp430f449", "msp430f4491", "msp430f477",
156"msp430f478", "msp430f4783", "msp430f4784", "msp430f479",
157"msp430f4793", "msp430f4794", "msp430fe423", "msp430fe4232",
158"msp430fe423a", "msp430fe4242", "msp430fe425", "msp430fe4252",
159"msp430fe425a", "msp430fe427", "msp430fe4272", "msp430fe427a",
160"msp430fg4250", "msp430fg4260", "msp430fg4270", "msp430fg437",
161"msp430fg438", "msp430fg439", "msp430fg477", "msp430fg478",
162"msp430fg479", "msp430fw423", "msp430fw425", "msp430fw427",
163"msp430fw428", "msp430fw429", "msp430g2001", "msp430g2101",
164"msp430g2102", "msp430g2111", "msp430g2112", "msp430g2113",
165"msp430g2121", "msp430g2131", "msp430g2132", "msp430g2152",
166"msp430g2153", "msp430g2201", "msp430g2202", "msp430g2203",
167"msp430g2210", "msp430g2211", "msp430g2212", "msp430g2213",
168"msp430g2221", "msp430g2230", "msp430g2231", "msp430g2232",
169"msp430g2233", "msp430g2252", "msp430g2253", "msp430g2302",
170"msp430g2303", "msp430g2312", "msp430g2313", "msp430g2332",
171"msp430g2333", "msp430g2352", "msp430g2353", "msp430g2402",
172"msp430g2403", "msp430g2412", "msp430g2413", "msp430g2432",
173"msp430g2433", "msp430g2444", "msp430g2452", "msp430g2453",
174"msp430g2513", "msp430g2533", "msp430g2544", "msp430g2553",
175"msp430g2744", "msp430g2755", "msp430g2855", "msp430g2955",
176"msp430i2020", "msp430i2021", "msp430i2030", "msp430i2031",
177"msp430i2040", "msp430i2041", "msp430l092", "msp430p112",
178"msp430p313", "msp430p315", "msp430p315s", "msp430p325",
179"msp430p337", "msp430tch5e"
4494fbc9 180};
50cfbf99
NC
181
182/* Generate a C preprocessor symbol based upon the MCU selected by the user.
183 If a specific MCU has not been selected then return a generic symbol instead. */
184
185const char *
186msp430_mcu_name (void)
187{
d4f283a1 188 if (target_mcu)
50cfbf99
NC
189 {
190 unsigned int i;
191 static char mcu_name [64];
192
d4f283a1 193 snprintf (mcu_name, sizeof (mcu_name) - 1, "__%s__", target_mcu);
50cfbf99
NC
194 for (i = strlen (mcu_name); i--;)
195 mcu_name[i] = TOUPPER (mcu_name[i]);
196 return mcu_name;
197 }
a005b5be 198
50cfbf99
NC
199 return msp430x ? "__MSP430XGENERIC__" : "__MSP430GENERIC__";
200}
201
f6a83b4a
DD
202static void
203msp430_option_override (void)
204{
205 init_machine_status = msp430_init_machine_status;
206
4494fbc9 207 if (target_cpu)
d4f283a1 208 {
f7961364 209 if (strcasecmp (target_cpu, "msp430x") == 0)
d4f283a1 210 msp430x = true;
f7961364 211 else /* target_cpu == "msp430" - already handled by the front end. */
c6f709ec 212 msp430x = false;
d4f283a1 213 }
f7961364
NC
214 /* Note - the front end has already ensured at most
215 one of target_cpu and target_mcu will be set. */
216 else if (target_mcu)
4494fbc9 217 {
c6f709ec 218 int i;
4494fbc9 219
c6f709ec
NC
220 /* If we are given an MCU name, we assume that it supports 430X.
221 Then we check to see if it is one of the known MCUs that only
222 supports 430. */
223 msp430x = true;
224
f7961364
NC
225 for (i = ARRAY_SIZE (msp430_mcu_names); i--;)
226 if (strcasecmp (msp430_mcu_names[i], target_mcu) == 0)
227 {
228 msp430x = false;
229 break;
230 }
c6f709ec
NC
231 /* It is not an error if we do not match the MCU name. There are
232 hundreds of them. */
4494fbc9 233 }
f6a83b4a
DD
234
235 if (TARGET_LARGE && !msp430x)
cad055a4 236 error ("-mlarge requires a 430X-compatible -mmcu=");
f6a83b4a
DD
237
238 if (flag_exceptions || flag_non_call_exceptions
239 || flag_unwind_tables || flag_asynchronous_unwind_tables)
240 flag_omit_frame_pointer = false;
241 else
242 flag_omit_frame_pointer = true;
243
244 /* This is a hack to work around a problem with the newlib build
245 mechanism. Newlib always appends CFLAGS to the end of the GCC
246 command line and always sets -O2 in CFLAGS. Thus it is not
247 possible to build newlib with -Os enabled. Until now... */
248 if (TARGET_OPT_SPACE && optimize < 3)
249 optimize_size = 1;
250}
251
c32ab325
DD
252#undef TARGET_SCALAR_MODE_SUPPORTED_P
253#define TARGET_SCALAR_MODE_SUPPORTED_P msp430_scalar_mode_supported_p
254
255static bool
ef4bddc2 256msp430_scalar_mode_supported_p (machine_mode m)
c32ab325
DD
257{
258 if (m == PSImode && msp430x)
259 return true;
260#if 0
261 if (m == TImode)
262 return true;
263#endif
264 return default_scalar_mode_supported_p (m);
265}
266
f6a83b4a
DD
267\f
268
269/* Storage Layout */
270
271#undef TARGET_MS_BITFIELD_LAYOUT_P
272#define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p
273
274bool
275msp430_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED)
276{
277 return false;
278}
279
280\f
281
282/* Register Usage */
283
284/* Implements HARD_REGNO_NREGS. MSP430X registers can hold a single
285 PSImode value, but not an SImode value. */
286int
287msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED,
ef4bddc2 288 machine_mode mode)
f6a83b4a
DD
289{
290 if (mode == PSImode && msp430x)
291 return 1;
292 return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
293 / UNITS_PER_WORD);
294}
295
c32ab325
DD
296/* Implements HARD_REGNO_NREGS_HAS_PADDING. */
297int
298msp430_hard_regno_nregs_has_padding (int regno ATTRIBUTE_UNUSED,
ef4bddc2 299 machine_mode mode)
c32ab325
DD
300{
301 if (mode == PSImode && msp430x)
302 return 1;
303 return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
304 / UNITS_PER_WORD);
305}
306
307/* Implements HARD_REGNO_NREGS_WITH_PADDING. */
308int
309msp430_hard_regno_nregs_with_padding (int regno ATTRIBUTE_UNUSED,
ef4bddc2 310 machine_mode mode)
c32ab325
DD
311{
312 if (mode == PSImode)
313 return 2;
314 return msp430_hard_regno_nregs (regno, mode);
315}
316
f6a83b4a
DD
317/* Implements HARD_REGNO_MODE_OK. */
318int
319msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED,
ef4bddc2 320 machine_mode mode)
f6a83b4a
DD
321{
322 return regno <= (ARG_POINTER_REGNUM - msp430_hard_regno_nregs (regno, mode));
323}
324
325/* Implements MODES_TIEABLE_P. */
326bool
ef4bddc2 327msp430_modes_tieable_p (machine_mode mode1, machine_mode mode2)
f6a83b4a
DD
328{
329 if ((mode1 == PSImode || mode2 == SImode)
330 || (mode1 == SImode || mode2 == PSImode))
331 return false;
332
333 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
334 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
335 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
336 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
337}
338
339#undef TARGET_FRAME_POINTER_REQUIRED
340#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required
341
342static bool
343msp430_frame_pointer_required (void)
344{
345 return false;
346}
347
348#undef TARGET_CAN_ELIMINATE
349#define TARGET_CAN_ELIMINATE msp430_can_eliminate
350
351static bool
352msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED,
353 const int to_reg ATTRIBUTE_UNUSED)
354{
355 return true;
356}
357
358/* Implements INITIAL_ELIMINATION_OFFSET. */
359int
cad055a4 360msp430_initial_elimination_offset (int from, int to)
f6a83b4a 361{
cad055a4 362 int rv = 0; /* As if arg to arg. */
f6a83b4a
DD
363
364 msp430_compute_frame_info ();
365
366 switch (to)
367 {
368 case STACK_POINTER_REGNUM:
369 rv += cfun->machine->framesize_outgoing;
370 rv += cfun->machine->framesize_locals;
371 /* Fall through. */
372 case FRAME_POINTER_REGNUM:
373 rv += cfun->machine->framesize_regs;
374 /* Allow for the saved return address. */
375 rv += (TARGET_LARGE ? 4 : 2);
376 /* NB/ No need to allow for crtl->args.pretend_args_size.
377 GCC does that for us. */
378 break;
379 default:
380 gcc_unreachable ();
381 }
382
383 switch (from)
384 {
385 case FRAME_POINTER_REGNUM:
386 /* Allow for the fall through above. */
387 rv -= (TARGET_LARGE ? 4 : 2);
388 rv -= cfun->machine->framesize_regs;
389 case ARG_POINTER_REGNUM:
390 break;
391 default:
392 gcc_unreachable ();
393 }
394
395 return rv;
396}
397\f
398/* Named Address Space support */
399
400
401/* Return the appropriate mode for a named address pointer. */
402#undef TARGET_ADDR_SPACE_POINTER_MODE
403#define TARGET_ADDR_SPACE_POINTER_MODE msp430_addr_space_pointer_mode
404#undef TARGET_ADDR_SPACE_ADDRESS_MODE
405#define TARGET_ADDR_SPACE_ADDRESS_MODE msp430_addr_space_pointer_mode
406
ef4bddc2 407static machine_mode
f6a83b4a
DD
408msp430_addr_space_pointer_mode (addr_space_t addrspace)
409{
410 switch (addrspace)
411 {
412 default:
413 case ADDR_SPACE_GENERIC:
414 return Pmode;
415 case ADDR_SPACE_NEAR:
416 return HImode;
417 case ADDR_SPACE_FAR:
418 return PSImode;
419 }
420}
421
422/* Function pointers are stored in unwind_word sized
423 variables, so make sure that unwind_word is big enough. */
424#undef TARGET_UNWIND_WORD_MODE
425#define TARGET_UNWIND_WORD_MODE msp430_unwind_word_mode
426
ef4bddc2 427static machine_mode
f6a83b4a
DD
428msp430_unwind_word_mode (void)
429{
c32ab325 430 return TARGET_LARGE ? PSImode : HImode;
f6a83b4a
DD
431}
432
433/* Determine if one named address space is a subset of another. */
434#undef TARGET_ADDR_SPACE_SUBSET_P
435#define TARGET_ADDR_SPACE_SUBSET_P msp430_addr_space_subset_p
436static bool
437msp430_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
438{
439 if (subset == superset)
440 return true;
441 else
442 return (subset != ADDR_SPACE_FAR && superset == ADDR_SPACE_FAR);
443}
444
445#undef TARGET_ADDR_SPACE_CONVERT
446#define TARGET_ADDR_SPACE_CONVERT msp430_addr_space_convert
447/* Convert from one address space to another. */
448static rtx
449msp430_addr_space_convert (rtx op, tree from_type, tree to_type)
450{
451 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
452 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
453 rtx result;
454
455 if (to_as != ADDR_SPACE_FAR && from_as == ADDR_SPACE_FAR)
456 {
457 /* This is unpredictable, as we're truncating off usable address
458 bits. */
459
460 if (CONSTANT_P (op))
461 return gen_rtx_CONST (HImode, op);
462
463 result = gen_reg_rtx (HImode);
464 emit_insn (gen_truncpsihi2 (result, op));
465 return result;
466 }
467 else if (to_as == ADDR_SPACE_FAR && from_as != ADDR_SPACE_FAR)
468 {
469 /* This always works. */
470
471 if (CONSTANT_P (op))
472 return gen_rtx_CONST (PSImode, op);
473
474 result = gen_reg_rtx (PSImode);
475 emit_insn (gen_zero_extendhipsi2 (result, op));
476 return result;
477 }
478 else
479 gcc_unreachable ();
480}
481\f
482/* Stack Layout and Calling Conventions. */
483
484/* For each function, we list the gcc version and the TI version on
485 each line, where we're converting the function names. */
486static char const * const special_convention_function_names [] =
487{
488 "__muldi3", "__mspabi_mpyll",
489 "__udivdi3", "__mspabi_divull",
490 "__umoddi3", "__mspabi_remull",
491 "__divdi3", "__mspabi_divlli",
492 "__moddi3", "__mspabi_remlli",
493 "__mspabi_srall",
494 "__mspabi_srlll",
495 "__mspabi_sllll",
496 "__adddf3", "__mspabi_addd",
497 "__subdf3", "__mspabi_subd",
498 "__muldf3", "__mspabi_mpyd",
499 "__divdf3", "__mspabi_divd",
500 "__mspabi_cmpd",
501 NULL
502};
503
504/* TRUE if the function passed is a "speical" function. Special
505 functions pass two DImode parameters in registers. */
506static bool
507msp430_special_register_convention_p (const char *name)
508{
509 int i;
510
511 for (i = 0; special_convention_function_names [i]; i++)
512 if (! strcmp (name, special_convention_function_names [i]))
513 return true;
514
515 return false;
516}
517
518#undef TARGET_FUNCTION_VALUE_REGNO_P
519#define TARGET_FUNCTION_VALUE_REGNO_P msp430_function_value_regno_p
520
521bool
522msp430_function_value_regno_p (unsigned int regno)
523{
524 return regno == 12;
525}
526
527
528#undef TARGET_FUNCTION_VALUE
529#define TARGET_FUNCTION_VALUE msp430_function_value
530
531rtx
532msp430_function_value (const_tree ret_type,
533 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
534 bool outgoing ATTRIBUTE_UNUSED)
535{
536 return gen_rtx_REG (TYPE_MODE (ret_type), 12);
537}
538
539#undef TARGET_LIBCALL_VALUE
540#define TARGET_LIBCALL_VALUE msp430_libcall_value
541
542rtx
ef4bddc2 543msp430_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
f6a83b4a
DD
544{
545 return gen_rtx_REG (mode, 12);
546}
547
548/* Implements INIT_CUMULATIVE_ARGS. */
549void
550msp430_init_cumulative_args (CUMULATIVE_ARGS *ca,
551 tree fntype ATTRIBUTE_UNUSED,
552 rtx libname ATTRIBUTE_UNUSED,
553 tree fndecl ATTRIBUTE_UNUSED,
554 int n_named_args ATTRIBUTE_UNUSED)
555{
556 const char *fname;
557 memset (ca, 0, sizeof(*ca));
558
559 ca->can_split = 1;
560
561 if (fndecl)
562 fname = IDENTIFIER_POINTER (DECL_NAME (fndecl));
563 else if (libname)
564 fname = XSTR (libname, 0);
565 else
566 fname = NULL;
567
568 if (fname && msp430_special_register_convention_p (fname))
569 ca->special_p = 1;
570}
571
572/* Helper function for argument passing; this function is the common
573 code that determines where an argument will be passed. */
574static void
575msp430_evaluate_arg (cumulative_args_t cap,
ef4bddc2 576 machine_mode mode,
f6a83b4a
DD
577 const_tree type ATTRIBUTE_UNUSED,
578 bool named)
579{
580 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
581 int nregs = GET_MODE_SIZE (mode);
582 int i;
583
584 ca->reg_count = 0;
585 ca->mem_count = 0;
586
587 if (!named)
588 return;
589
590 if (mode == PSImode)
591 nregs = 1;
592 else
593 nregs = (nregs + 1) / 2;
594
595 if (ca->special_p)
596 {
597 /* Function is passed two DImode operands, in R8:R11 and
598 R12:15. */
599 ca->start_reg = 8;
600 ca->reg_count = 4;
601 return;
602 }
603
604 switch (nregs)
605 {
606 case 1:
607 for (i = 0; i < 4; i++)
608 if (! ca->reg_used [i])
609 {
610 ca->reg_count = 1;
611 ca->start_reg = CA_FIRST_REG + i;
612 return;
613 }
614 break;
615 case 2:
616 for (i = 0; i < 3; i++)
617 if (! ca->reg_used [i] && ! ca->reg_used [i + 1])
618 {
619 ca->reg_count = 2;
620 ca->start_reg = CA_FIRST_REG + i;
621 return;
622 }
623 if (! ca->reg_used [3] && ca->can_split)
624 {
625 ca->reg_count = 1;
626 ca->mem_count = 2;
627 ca->start_reg = CA_FIRST_REG + 3;
628 return;
629 }
630 break;
631 case 3:
632 case 4:
633 ca->can_split = 0;
634 if (! ca->reg_used [0]
635 && ! ca->reg_used [1]
636 && ! ca->reg_used [2]
637 && ! ca->reg_used [3])
638 {
639 ca->reg_count = 4;
640 ca->start_reg = CA_FIRST_REG;
641 return;
642 }
643 break;
644 }
645}
646
647#undef TARGET_PROMOTE_PROTOTYPES
648#define TARGET_PROMOTE_PROTOTYPES msp430_promote_prototypes
649
650bool
651msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
652{
653 return false;
654}
655
656#undef TARGET_FUNCTION_ARG
657#define TARGET_FUNCTION_ARG msp430_function_arg
658
659rtx
660msp430_function_arg (cumulative_args_t cap,
ef4bddc2 661 machine_mode mode,
f6a83b4a
DD
662 const_tree type,
663 bool named)
664{
665 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
666
667 msp430_evaluate_arg (cap, mode, type, named);
668
669 if (ca->reg_count)
670 return gen_rtx_REG (mode, ca->start_reg);
671
672 return 0;
673}
674
675#undef TARGET_ARG_PARTIAL_BYTES
676#define TARGET_ARG_PARTIAL_BYTES msp430_arg_partial_bytes
677
678int
679msp430_arg_partial_bytes (cumulative_args_t cap,
ef4bddc2 680 machine_mode mode,
f6a83b4a
DD
681 tree type,
682 bool named)
683{
684 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
685
686 msp430_evaluate_arg (cap, mode, type, named);
687
688 if (ca->reg_count && ca->mem_count)
689 return ca->reg_count * UNITS_PER_WORD;
690
691 return 0;
692}
693
694#undef TARGET_PASS_BY_REFERENCE
695#define TARGET_PASS_BY_REFERENCE msp430_pass_by_reference
696
697static bool
698msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED,
ef4bddc2 699 machine_mode mode,
f6a83b4a
DD
700 const_tree type,
701 bool named ATTRIBUTE_UNUSED)
702{
703 return (mode == BLKmode
704 || (type && TREE_CODE (type) == RECORD_TYPE)
705 || (type && TREE_CODE (type) == UNION_TYPE));
706}
707
708#undef TARGET_CALLEE_COPIES
709#define TARGET_CALLEE_COPIES msp430_callee_copies
710
711static bool
712msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED,
ef4bddc2 713 machine_mode mode ATTRIBUTE_UNUSED,
f6a83b4a
DD
714 const_tree type ATTRIBUTE_UNUSED,
715 bool named ATTRIBUTE_UNUSED)
716{
717 return true;
718}
719
720#undef TARGET_FUNCTION_ARG_ADVANCE
721#define TARGET_FUNCTION_ARG_ADVANCE msp430_function_arg_advance
722
723void
724msp430_function_arg_advance (cumulative_args_t cap,
ef4bddc2 725 machine_mode mode,
f6a83b4a
DD
726 const_tree type,
727 bool named)
728{
729 CUMULATIVE_ARGS *ca = get_cumulative_args (cap);
730 int i;
731
732 msp430_evaluate_arg (cap, mode, type, named);
733
734 if (ca->start_reg >= CA_FIRST_REG)
735 for (i = 0; i < ca->reg_count; i ++)
736 ca->reg_used [i + ca->start_reg - CA_FIRST_REG] = 1;
737
738 ca->special_p = 0;
739}
740
741#undef TARGET_FUNCTION_ARG_BOUNDARY
742#define TARGET_FUNCTION_ARG_BOUNDARY msp430_function_arg_boundary
743
744static unsigned int
ef4bddc2 745msp430_function_arg_boundary (machine_mode mode, const_tree type)
f6a83b4a
DD
746{
747 if (mode == BLKmode
748 && int_size_in_bytes (type) > 1)
749 return 16;
750 if (GET_MODE_BITSIZE (mode) > 8)
751 return 16;
752 return 8;
753}
754
755#undef TARGET_RETURN_IN_MEMORY
756#define TARGET_RETURN_IN_MEMORY msp430_return_in_memory
757
758static bool
759msp430_return_in_memory (const_tree ret_type, const_tree fntype ATTRIBUTE_UNUSED)
760{
ef4bddc2 761 machine_mode mode = TYPE_MODE (ret_type);
f6a83b4a
DD
762
763 if (mode == BLKmode
764 || (fntype && TREE_CODE (TREE_TYPE (fntype)) == RECORD_TYPE)
765 || (fntype && TREE_CODE (TREE_TYPE (fntype)) == UNION_TYPE))
766 return true;
767
768 if (GET_MODE_SIZE (mode) > 8)
769 return true;
770
771 return false;
772}
773
774#undef TARGET_GET_RAW_ARG_MODE
775#define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode
776
ef4bddc2 777static machine_mode
f6a83b4a
DD
778msp430_get_raw_arg_mode (int regno)
779{
780 return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode;
781}
782
783#undef TARGET_GET_RAW_RESULT_MODE
784#define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode
785
ef4bddc2 786static machine_mode
f6a83b4a
DD
787msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED)
788{
789 return Pmode;
790}
467fc67c
NC
791
792#undef TARGET_GIMPLIFY_VA_ARG_EXPR
793#define TARGET_GIMPLIFY_VA_ARG_EXPR msp430_gimplify_va_arg_expr
794
795#include "gimplify.h"
796#include "gimple-expr.h"
797
798static tree
799msp430_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
800 gimple_seq *post_p)
801{
802 tree addr, t, type_size, rounded_size, valist_tmp;
803 unsigned HOST_WIDE_INT align, boundary;
804 bool indirect;
805
806 indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
807 if (indirect)
808 type = build_pointer_type (type);
809
810 align = PARM_BOUNDARY / BITS_PER_UNIT;
811 boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
812
813 /* When we align parameter on stack for caller, if the parameter
814 alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
815 aligned at MAX_SUPPORTED_STACK_ALIGNMENT. We will match callee
816 here with caller. */
817 if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
818 boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
819
820 boundary /= BITS_PER_UNIT;
821
822 /* Hoist the valist value into a temporary for the moment. */
823 valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
824
825 /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
826 requires greater alignment, we must perform dynamic alignment. */
827 if (boundary > align
828 && !integer_zerop (TYPE_SIZE (type)))
829 {
830 /* FIXME: This is where this function diverts from targhooks.c:
831 std_gimplify_va_arg_expr(). It works, but I do not know why... */
832 if (! POINTER_TYPE_P (type))
833 {
834 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
835 fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
836 gimplify_and_add (t, pre_p);
837
838 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
839 fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
840 valist_tmp,
841 build_int_cst (TREE_TYPE (valist), -boundary)));
842 gimplify_and_add (t, pre_p);
843 }
844 }
845 else
846 boundary = align;
847
848 /* If the actual alignment is less than the alignment of the type,
849 adjust the type accordingly so that we don't assume strict alignment
850 when dereferencing the pointer. */
851 boundary *= BITS_PER_UNIT;
852 if (boundary < TYPE_ALIGN (type))
853 {
854 type = build_variant_type_copy (type);
855 TYPE_ALIGN (type) = boundary;
856 }
857
858 /* Compute the rounded size of the type. */
859 type_size = size_in_bytes (type);
860 rounded_size = round_up (type_size, align);
861
862 /* Reduce rounded_size so it's sharable with the postqueue. */
863 gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
864
865 /* Get AP. */
866 addr = valist_tmp;
867
868 /* Compute new value for AP. */
869 t = fold_build_pointer_plus (valist_tmp, rounded_size);
870 t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
871 gimplify_and_add (t, pre_p);
872
873 addr = fold_convert (build_pointer_type (type), addr);
874
875 if (indirect)
876 addr = build_va_arg_indirect_ref (addr);
877
878 addr = build_va_arg_indirect_ref (addr);
879
880 return addr;
881}
f6a83b4a
DD
882\f
883/* Addressing Modes */
884
885#undef TARGET_LEGITIMATE_ADDRESS_P
886#define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p
887
888static bool
889reg_ok_for_addr (rtx r, bool strict)
890{
891 int rn = REGNO (r);
892
893 if (strict && rn >= FIRST_PSEUDO_REGISTER)
894 rn = reg_renumber [rn];
895 if (strict && 0 <= rn && rn < FIRST_PSEUDO_REGISTER)
896 return true;
897 if (!strict)
898 return true;
899 return false;
900}
901
902bool
ef4bddc2 903msp430_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
f6a83b4a
DD
904 rtx x ATTRIBUTE_UNUSED,
905 bool strict ATTRIBUTE_UNUSED)
906{
907 switch (GET_CODE (x))
908 {
909 case MEM:
910 return false;
911
912 case PLUS:
913 if (REG_P (XEXP (x, 0)))
914 {
915 if (GET_MODE (x) != GET_MODE (XEXP (x, 0)))
916 return false;
917 if (!reg_ok_for_addr (XEXP (x, 0), strict))
918 return false;
919 switch (GET_CODE (XEXP (x, 1)))
920 {
921 case CONST:
922 case SYMBOL_REF:
923 case CONST_INT:
924 return true;
925 default:
926 return false;
927 }
928 }
929 return false;
930
931 case REG:
932 if (!reg_ok_for_addr (x, strict))
933 return false;
934 /* else... */
935 case CONST:
936 case SYMBOL_REF:
937 case CONST_INT:
938 return true;
939
940 default:
941 return false;
942 }
943}
944
c32ab325
DD
945#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
946#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P msp430_addr_space_legitimate_address_p
947
948bool
ef4bddc2 949msp430_addr_space_legitimate_address_p (machine_mode mode,
c32ab325
DD
950 rtx x,
951 bool strict,
952 addr_space_t as ATTRIBUTE_UNUSED)
953{
954 return msp430_legitimate_address_p (mode, x, strict);
955}
956
957#undef TARGET_ASM_INTEGER
958#define TARGET_ASM_INTEGER msp430_asm_integer
959static bool
960msp430_asm_integer (rtx x, unsigned int size, int aligned_p)
961{
962 int c = GET_CODE (x);
963
964 if (size == 3 && GET_MODE (x) == PSImode)
965 size = 4;
966
967 switch (size)
968 {
969 case 4:
970 if (c == SYMBOL_REF || c == CONST || c == LABEL_REF || c == CONST_INT)
971 {
972 fprintf (asm_out_file, "\t.long\t");
973 output_addr_const (asm_out_file, x);
974 fputc ('\n', asm_out_file);
975 return true;
976 }
977 break;
978 }
979 return default_assemble_integer (x, size, aligned_p);
980}
981
982#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
983#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA msp430_asm_output_addr_const_extra
984static bool
53fea787 985msp430_asm_output_addr_const_extra (FILE *file ATTRIBUTE_UNUSED, rtx x)
c32ab325
DD
986{
987 debug_rtx(x);
988 return false;
989}
990
f6a83b4a
DD
991#undef TARGET_LEGITIMATE_CONSTANT_P
992#define TARGET_LEGITIMATE_CONSTANT_P msp430_legitimate_constant
993
994static bool
ef4bddc2 995msp430_legitimate_constant (machine_mode mode, rtx x)
f6a83b4a
DD
996{
997 return ! CONST_INT_P (x)
998 || mode != PSImode
999 /* GCC does not know the width of the PSImode, so make
1000 sure that it does not try to use a constant value that
1001 is out of range. */
1002 || (INTVAL (x) < (1 << 20) && INTVAL (x) >= (-1 << 20));
1003}
1004
1005\f
1006#undef TARGET_RTX_COSTS
1007#define TARGET_RTX_COSTS msp430_rtx_costs
1008
1009static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED,
1010 int code,
1011 int outer_code ATTRIBUTE_UNUSED,
1012 int opno ATTRIBUTE_UNUSED,
1013 int * total,
1014 bool speed ATTRIBUTE_UNUSED)
1015{
1016 switch (code)
1017 {
1018 case SIGN_EXTEND:
1019 if (GET_MODE (x) == SImode && outer_code == SET)
1020 {
1021 *total = COSTS_N_INSNS (4);
1022 return true;
1023 }
1024 break;
1025 case ASHIFT:
1026 case ASHIFTRT:
1027 case LSHIFTRT:
1028 if (!msp430x)
1029 {
1030 *total = COSTS_N_INSNS (100);
1031 return true;
1032 }
1033 break;
1034 }
1035 return false;
1036}
1037\f
1038/* Function Entry and Exit */
1039
1040/* The MSP430 call frame looks like this:
1041
1042 <higher addresses>
1043 +--------------------+
1044 | |
1045 | Stack Arguments |
1046 | |
1047 +--------------------+ <-- "arg pointer"
1048 | |
1049 | PC from call | (2 bytes for 430, 4 for TARGET_LARGE)
1050 | |
cad055a4
NC
1051 +--------------------+
1052 | SR if this func has|
1053 | been called via an |
1054 | interrupt. |
f6a83b4a
DD
1055 +--------------------+ <-- SP before prologue, also AP
1056 | |
1057 | Saved Regs | (2 bytes per reg for 430, 4 per for TARGET_LARGE)
1058 | |
1059 +--------------------+ <-- "frame pointer"
1060 | |
1061 | Locals |
1062 | |
1063 +--------------------+
1064 | |
1065 | Outgoing Args |
1066 | |
1067 +--------------------+ <-- SP during function
1068 <lower addresses>
1069
1070*/
1071
1072/* We use this to wrap all emitted insns in the prologue, so they get
1073 the "frame-related" (/f) flag set. */
1074static rtx
1075F (rtx x)
1076{
1077 RTX_FRAME_RELATED_P (x) = 1;
1078 return x;
1079}
1080
1081/* This is the one spot that decides if a register is to be saved and
1082 restored in the prologue/epilogue. */
1083static bool
1084msp430_preserve_reg_p (int regno)
1085{
1086 /* PC, SP, SR, and the constant generator. */
1087 if (regno <= 3)
1088 return false;
1089
1090 /* FIXME: add interrupt, EH, etc. */
1091 if (crtl->calls_eh_return)
1092 return true;
1093
1094 /* Shouldn't be more than the above, but just in case... */
1095 if (fixed_regs [regno])
1096 return false;
1097
cad055a4
NC
1098 /* Interrupt handlers save all registers they use, even
1099 ones which are call saved. If they call other functions
1100 then *every* register is saved. */
1101 if (msp430_is_interrupt_func ())
1102 return ! crtl->is_leaf || df_regs_ever_live_p (regno);
1103
f6a83b4a
DD
1104 if (!call_used_regs [regno]
1105 && df_regs_ever_live_p (regno))
1106 return true;
1107
1108 return false;
1109}
1110
1111/* Compute all the frame-related fields in our machine_function
1112 structure. */
1113static void
1114msp430_compute_frame_info (void)
1115{
1116 int i;
1117
1118 cfun->machine->computed = 1;
1119 cfun->machine->framesize_regs = 0;
1120 cfun->machine->framesize_locals = get_frame_size ();
1121 cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
1122
cad055a4 1123 for (i = 0; i < ARG_POINTER_REGNUM; i ++)
f6a83b4a
DD
1124 if (msp430_preserve_reg_p (i))
1125 {
1126 cfun->machine->need_to_save [i] = 1;
1127 cfun->machine->framesize_regs += (TARGET_LARGE ? 4 : 2);
1128 }
1129 else
1130 cfun->machine->need_to_save [i] = 0;
1131
1132 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
1133 cfun->machine->framesize_locals ++;
1134
1135 cfun->machine->framesize = (cfun->machine->framesize_regs
1136 + cfun->machine->framesize_locals
1137 + cfun->machine->framesize_outgoing);
1138}
1139
cad055a4
NC
1140static inline bool
1141is_attr_func (const char * attr)
1142{
1143 return lookup_attribute (attr, DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE;
1144}
1145
1146/* Returns true if the current function has the "interrupt" attribute. */
1147
1148bool
1149msp430_is_interrupt_func (void)
1150{
c6f709ec
NC
1151 if (current_function_decl == NULL)
1152 return false;
cad055a4
NC
1153 return is_attr_func ("interrupt");
1154}
1155
a005b5be
NC
1156static bool
1157is_wakeup_func (void)
1158{
1159 return msp430_is_interrupt_func () && is_attr_func ("wakeup");
1160}
1161
cad055a4
NC
1162static inline bool
1163is_naked_func (void)
1164{
1165 return is_attr_func ("naked");
1166}
1167
1168static inline bool
1169is_reentrant_func (void)
1170{
1171 return is_attr_func ("reentrant");
1172}
1173
1174static inline bool
1175is_critical_func (void)
1176{
1177 return is_attr_func ("critical");
1178}
1179
f6a83b4a
DD
1180#undef TARGET_ASM_FUNCTION_PROLOGUE
1181#define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function
1182
1183static void
1184msp430_start_function (FILE *outfile, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
1185{
1186 int r, n;
1187
1188 fprintf (outfile, "; start of function\n");
cad055a4
NC
1189
1190 if (DECL_ATTRIBUTES (current_function_decl) != NULL_TREE)
1191 {
1192 fprintf (outfile, "; attributes: ");
1193 if (is_naked_func ())
1194 fprintf (outfile, "naked ");
1195 if (msp430_is_interrupt_func ())
1196 fprintf (outfile, "interrupt ");
1197 if (is_reentrant_func ())
1198 fprintf (outfile, "reentrant ");
1199 if (is_critical_func ())
1200 fprintf (outfile, "critical ");
a005b5be
NC
1201 if (is_wakeup_func ())
1202 fprintf (outfile, "wakeup ");
cad055a4
NC
1203 fprintf (outfile, "\n");
1204 }
1205
f6a83b4a
DD
1206 fprintf (outfile, "; framesize_regs: %d\n", cfun->machine->framesize_regs);
1207 fprintf (outfile, "; framesize_locals: %d\n", cfun->machine->framesize_locals);
1208 fprintf (outfile, "; framesize_outgoing: %d\n", cfun->machine->framesize_outgoing);
1209 fprintf (outfile, "; framesize: %d\n", cfun->machine->framesize);
1210 fprintf (outfile, "; elim ap -> fp %d\n", msp430_initial_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM));
1211 fprintf (outfile, "; elim fp -> sp %d\n", msp430_initial_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM));
1212
1213 n = 0;
1214 fprintf (outfile, "; saved regs:");
cad055a4 1215 for (r = 0; r < ARG_POINTER_REGNUM; r++)
f6a83b4a
DD
1216 if (cfun->machine->need_to_save [r])
1217 {
1218 fprintf (outfile, " %s", reg_names [r]);
1219 n = 1;
1220 }
1221 if (n == 0)
1222 fprintf (outfile, "(none)");
1223 fprintf (outfile, "\n");
1224}
1225
1226/* Common code to change the stack pointer. */
1227static void
1228increment_stack (HOST_WIDE_INT amount)
1229{
1230 rtx inc;
1231 rtx sp = stack_pointer_rtx;
1232
1233 if (amount == 0)
1234 return;
1235
1236 if (amount < 0)
1237 {
1238 inc = GEN_INT (- amount);
1239 if (TARGET_LARGE)
1240 F (emit_insn (gen_subpsi3 (sp, sp, inc)));
1241 else
1242 F (emit_insn (gen_subhi3 (sp, sp, inc)));
1243 }
1244 else
1245 {
1246 inc = GEN_INT (amount);
1247 if (TARGET_LARGE)
1248 emit_insn (gen_addpsi3 (sp, sp, inc));
1249 else
1250 emit_insn (gen_addhi3 (sp, sp, inc));
1251 }
1252}
1253
cad055a4
NC
1254/* Verify MSP430 specific attributes. */
1255
1256static tree
1257msp430_attr (tree * node,
1258 tree name,
1259 tree args,
1260 int flags ATTRIBUTE_UNUSED,
1261 bool * no_add_attrs)
1262{
1263 gcc_assert (DECL_P (* node));
1264
1265 if (args != NULL)
1266 {
1267 tree value = TREE_VALUE (args);
1268
1269 switch (TREE_CODE (value))
1270 {
1271 case STRING_CST:
1272 if ( strcmp (TREE_STRING_POINTER (value), "reset")
1273 && strcmp (TREE_STRING_POINTER (value), "nmi")
1274 && strcmp (TREE_STRING_POINTER (value), "watchdog"))
1275 /* Allow the attribute to be added - the linker script
1276 being used may still recognise this name. */
1277 warning (OPT_Wattributes,
1278 "unrecognised interrupt vector argument of %qE attribute",
1279 name);
1280 break;
1281
1282 case INTEGER_CST:
807e902e 1283 if (wi::gtu_p (value, 63))
cad055a4
NC
1284 /* Allow the attribute to be added - the linker script
1285 being used may still recognise this value. */
1286 warning (OPT_Wattributes,
d4f283a1 1287 "numeric argument of %qE attribute must be in range 0..63",
cad055a4
NC
1288 name);
1289 break;
1290
1291 default:
1292 warning (OPT_Wattributes,
1293 "argument of %qE attribute is not a string constant or number",
1294 name);
1295 *no_add_attrs = true;
1296 break;
1297 }
1298 }
1299
1300 if (TREE_CODE (* node) != FUNCTION_DECL)
1301 {
1302 warning (OPT_Wattributes,
1303 "%qE attribute only applies to functions",
1304 name);
1305 * no_add_attrs = true;
1306 }
1307
1308 /* FIXME: We ought to check that the interrupt handler
1309 attribute has been applied to a void function. */
1310 /* FIXME: We should check that reentrant and critical
1311 functions are not naked and that critical functions
1312 are not reentrant. */
1313
1314 return NULL_TREE;
1315}
1316
1317#undef TARGET_ATTRIBUTE_TABLE
1318#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table
1319
1320/* Table of MSP430-specific attributes. */
1321const struct attribute_spec msp430_attribute_table[] =
1322{
1323 /* Name min_len decl_req, fn_type_req, affects_type_identity
1324 max_len, type_req, handler. */
1325 { "interrupt", 0, 1, true, false, false, msp430_attr, false },
1326 { "naked", 0, 0, true, false, false, msp430_attr, false },
1327 { "reentrant", 0, 0, true, false, false, msp430_attr, false },
1328 { "critical", 0, 0, true, false, false, msp430_attr, false },
a005b5be 1329 { "wakeup", 0, 0, true, false, false, msp430_attr, false },
cad055a4
NC
1330 { NULL, 0, 0, false, false, false, NULL, false }
1331};
1332
1333void
1334msp430_start_function (FILE *file, const char *name, tree decl)
1335{
1336 tree int_attr;
1337
1338 int_attr = lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl));
1339 if (int_attr != NULL_TREE)
1340 {
1341 tree intr_vector = TREE_VALUE (int_attr);
1342
1343 if (intr_vector != NULL_TREE)
1344 {
1345 char buf[101];
1346
1347 intr_vector = TREE_VALUE (intr_vector);
1348
1349 /* The interrupt attribute has a vector value. Turn this into a
1350 section name, switch to that section and put the address of
1351 the current function into that vector slot. Note msp430_attr()
1352 has already verified the vector name for us. */
1353 if (TREE_CODE (intr_vector) == STRING_CST)
1354 sprintf (buf, "__interrupt_vector_%.80s",
1355 TREE_STRING_POINTER (intr_vector));
1356 else /* TREE_CODE (intr_vector) == INTEGER_CST */
1357 sprintf (buf, "__interrupt_vector_%u",
1358 (unsigned int) TREE_INT_CST_LOW (intr_vector));
1359
1360 switch_to_section (get_section (buf, SECTION_CODE, decl));
1361 fputs ("\t.word\t", file);
1362 assemble_name (file, name);
1363 fputc ('\n', file);
1364 fputc ('\t', file);
1365 }
1366 }
1367
1368 switch_to_section (function_section (decl));
1369 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
1370}
1371
1372static section *
1373msp430_function_section (tree decl, enum node_frequency freq, bool startup, bool exit)
1374{
1375 /* In large mode we must make sure that interrupt handlers are put into
1376 low memory as the vector table only accepts 16-bit addresses. */
1377 if (TARGET_LARGE
1378 && lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl)))
1379 return get_section (".lowtext", SECTION_CODE | SECTION_WRITE , decl);
1380
1381 /* Otherwise, use the default function section. */
1382 return default_function_section (decl, freq, startup, exit);
1383}
1384
1385#undef TARGET_ASM_FUNCTION_SECTION
1386#define TARGET_ASM_FUNCTION_SECTION msp430_function_section
1387
1388enum msp430_builtin
1389{
1390 MSP430_BUILTIN_BIC_SR,
1391 MSP430_BUILTIN_BIS_SR,
5f35dde5 1392 MSP430_BUILTIN_DELAY_CYCLES,
cad055a4
NC
1393 MSP430_BUILTIN_max
1394};
1395
1396static GTY(()) tree msp430_builtins [(int) MSP430_BUILTIN_max];
1397
1398static void
1399msp430_init_builtins (void)
1400{
1401 tree void_ftype_int = build_function_type_list (void_type_node, integer_type_node, NULL);
5f35dde5 1402 tree void_ftype_longlong = build_function_type_list (void_type_node, long_long_integer_type_node, NULL);
cad055a4
NC
1403
1404 msp430_builtins[MSP430_BUILTIN_BIC_SR] =
1405 add_builtin_function ( "__bic_SR_register_on_exit", void_ftype_int,
1406 MSP430_BUILTIN_BIC_SR, BUILT_IN_MD, NULL, NULL_TREE);
1407
1408 msp430_builtins[MSP430_BUILTIN_BIS_SR] =
1409 add_builtin_function ( "__bis_SR_register_on_exit", void_ftype_int,
1410 MSP430_BUILTIN_BIS_SR, BUILT_IN_MD, NULL, NULL_TREE);
5f35dde5
DD
1411
1412 msp430_builtins[MSP430_BUILTIN_DELAY_CYCLES] =
1413 add_builtin_function ( "__delay_cycles", void_ftype_longlong,
1414 MSP430_BUILTIN_DELAY_CYCLES, BUILT_IN_MD, NULL, NULL_TREE);
cad055a4
NC
1415}
1416
1417static tree
1418msp430_builtin_decl (unsigned code, bool initialize ATTRIBUTE_UNUSED)
1419{
1420 switch (code)
1421 {
1422 case MSP430_BUILTIN_BIC_SR:
1423 case MSP430_BUILTIN_BIS_SR:
5f35dde5 1424 case MSP430_BUILTIN_DELAY_CYCLES:
cad055a4
NC
1425 return msp430_builtins[code];
1426 default:
1427 return error_mark_node;
1428 }
1429}
1430
5f35dde5
DD
1431/* These constants are really register reads, which are faster than
1432 regular constants. */
1433static int
1434cg_magic_constant (HOST_WIDE_INT c)
1435{
1436 switch (c)
1437 {
1438 case 0xffff:
1439 case -1:
1440 case 0:
1441 case 1:
1442 case 2:
1443 case 4:
1444 case 8:
1445 return 1;
1446 default:
1447 return 0;
1448 }
1449}
1450
1451static rtx
1452msp430_expand_delay_cycles (rtx arg)
1453{
1454 HOST_WIDE_INT i, c, n;
1455 /* extra cycles for MSP430X instructions */
1456#define CYCX(M,X) (msp430x ? (X) : (M))
1457
1458 if (GET_CODE (arg) != CONST_INT)
1459 {
1460 error ("__delay_cycles() only takes constant arguments");
1461 return NULL_RTX;
1462 }
1463
1464 c = INTVAL (arg);
1465
1466 if (HOST_BITS_PER_WIDE_INT > 32)
1467 {
1468 if (c < 0)
1469 {
1470 error ("__delay_cycles only takes non-negative cycle counts.");
1471 return NULL_RTX;
1472 }
1473 }
1474
1475 emit_insn (gen_delay_cycles_start (arg));
1476
1477 /* For 32-bit loops, there's 13(16) + 5(min(x,0x10000) + 6x cycles. */
1478 if (c > 3 * 0xffff + CYCX (7, 10))
1479 {
1480 n = c;
1481 /* There's 4 cycles in the short (i>0xffff) loop and 7 in the long (x<=0xffff) loop */
1482 if (c >= 0x10000 * 7 + CYCX (14, 16))
1483 {
1484 i = 0x10000;
1485 c -= CYCX (14, 16) + 7 * 0x10000;
1486 i += c / 4;
1487 c %= 4;
1488 if ((unsigned long long) i > 0xffffffffULL)
1489 {
1490 error ("__delay_cycles is limited to 32-bit loop counts.");
1491 return NULL_RTX;
1492 }
1493 }
1494 else
1495 {
1496 i = (c - CYCX (14, 16)) / 7;
1497 c -= CYCX (14, 16) + i * 7;
1498 }
1499
1500 if (cg_magic_constant (i & 0xffff))
1501 c ++;
1502 if (cg_magic_constant ((i >> 16) & 0xffff))
1503 c ++;
1504
1505 if (msp430x)
1506 emit_insn (gen_delay_cycles_32x (GEN_INT (i), GEN_INT (n - c)));
1507 else
1508 emit_insn (gen_delay_cycles_32 (GEN_INT (i), GEN_INT (n - c)));
1509 }
1510
1511 /* For 16-bit loops, there's 7(10) + 3x cycles - so the max cycles is 0x30004(7). */
1512 if (c > 12)
1513 {
1514 n = c;
1515 i = (c - CYCX (7, 10)) / 3;
1516 c -= CYCX (7, 10) + i * 3;
1517
1518 if (cg_magic_constant (i))
1519 c ++;
1520
1521 if (msp430x)
1522 emit_insn (gen_delay_cycles_16x (GEN_INT (i), GEN_INT (n - c)));
1523 else
1524 emit_insn (gen_delay_cycles_16 (GEN_INT (i), GEN_INT (n - c)));
1525 }
1526
1527 while (c > 1)
1528 {
1529 emit_insn (gen_delay_cycles_2 ());
1530 c -= 2;
1531 }
1532
1533 if (c)
1534 {
1535 emit_insn (gen_delay_cycles_1 ());
1536 c -= 1;
1537 }
1538
1539 emit_insn (gen_delay_cycles_end (arg));
1540
1541 return NULL_RTX;
1542}
1543
cad055a4
NC
1544static rtx
1545msp430_expand_builtin (tree exp,
1546 rtx target ATTRIBUTE_UNUSED,
1547 rtx subtarget ATTRIBUTE_UNUSED,
ef4bddc2 1548 machine_mode mode ATTRIBUTE_UNUSED,
cad055a4
NC
1549 int ignore ATTRIBUTE_UNUSED)
1550{
1551 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
1552 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
1553 rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
1554
5f35dde5
DD
1555 if (fcode == MSP430_BUILTIN_DELAY_CYCLES)
1556 return msp430_expand_delay_cycles (arg1);
1557
cad055a4
NC
1558 if (! msp430_is_interrupt_func ())
1559 {
1560 error ("MSP430 builtin functions only work inside interrupt handlers");
1561 return NULL_RTX;
1562 }
1563
1564 if (! REG_P (arg1) && ! CONSTANT_P (arg1))
1565 arg1 = force_reg (mode, arg1);
1566
1567 switch (fcode)
1568 {
1569 case MSP430_BUILTIN_BIC_SR: emit_insn (gen_bic_SR (arg1)); break;
1570 case MSP430_BUILTIN_BIS_SR: emit_insn (gen_bis_SR (arg1)); break;
1571 default:
1572 internal_error ("bad builtin code");
1573 break;
1574 }
1575 return NULL_RTX;
1576}
1577
1578#undef TARGET_INIT_BUILTINS
1579#define TARGET_INIT_BUILTINS msp430_init_builtins
1580
1581#undef TARGET_EXPAND_BUILTIN
1582#define TARGET_EXPAND_BUILTIN msp430_expand_builtin
1583
1584#undef TARGET_BUILTIN_DECL
1585#define TARGET_BUILTIN_DECL msp430_builtin_decl
1586
f6a83b4a
DD
1587void
1588msp430_expand_prologue (void)
1589{
1590 int i, j;
1591 int fs;
1592 /* Always use stack_pointer_rtx instead of calling
1593 rtx_gen_REG ourselves. Code elsewhere in GCC assumes
1594 that there is a single rtx representing the stack pointer,
1595 namely stack_pointer_rtx, and uses == to recognize it. */
1596 rtx sp = stack_pointer_rtx;
1597 rtx p;
1598
cad055a4 1599 if (is_naked_func ())
f642a8b7
NC
1600 {
1601 /* We must generate some RTX as thread_prologue_and_epilogue_insns()
1602 examines the output of the gen_prologue() function. */
1603 emit_insn (gen_rtx_CLOBBER (VOIDmode, GEN_INT (0)));
1604 return;
1605 }
cad055a4 1606
f6a83b4a
DD
1607 emit_insn (gen_prologue_start_marker ());
1608
cad055a4
NC
1609 if (is_critical_func ())
1610 {
1611 emit_insn (gen_push_intr_state ());
1612 emit_insn (gen_disable_interrupts ());
1613 }
1614 else if (is_reentrant_func ())
1615 emit_insn (gen_disable_interrupts ());
1616
f6a83b4a
DD
1617 if (!cfun->machine->computed)
1618 msp430_compute_frame_info ();
1619
1620 if (flag_stack_usage_info)
1621 current_function_static_stack_size = cfun->machine->framesize;
c6f709ec 1622
f6a83b4a
DD
1623 if (crtl->args.pretend_args_size)
1624 {
1625 rtx note;
1626
1627 gcc_assert (crtl->args.pretend_args_size == 2);
c6f709ec 1628
f6a83b4a
DD
1629 p = emit_insn (gen_grow_and_swap ());
1630
1631 /* Document the stack decrement... */
1632 note = F (gen_rtx_SET (Pmode, stack_pointer_rtx,
1633 gen_rtx_MINUS (Pmode, stack_pointer_rtx, GEN_INT (2))));
1634 add_reg_note (p, REG_FRAME_RELATED_EXPR, note);
1635
1636 /* ...and the establishment of a new location for the return address. */
1637 note = F (gen_rtx_SET (Pmode, gen_rtx_MEM (Pmode,
1638 gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-2))),
1639 pc_rtx));
1640 add_reg_note (p, REG_CFA_OFFSET, note);
1641 F (p);
1642 }
1643
1644 for (i = 15; i >= 4; i--)
1645 if (cfun->machine->need_to_save [i])
1646 {
1647 int seq, count;
1648 rtx note;
1649
1650 for (seq = i - 1; seq >= 4 && cfun->machine->need_to_save[seq]; seq --)
1651 ;
1652 count = i - seq;
1653
1654 if (msp430x)
1655 {
1656 /* Note: with TARGET_LARGE we still use PUSHM as PUSHX.A is two bytes bigger. */
1657 p = F (emit_insn (gen_pushm (gen_rtx_REG (Pmode, i),
1658 GEN_INT (count))));
1659
1660 note = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
1661
1662 XVECEXP (note, 0, 0)
1663 = F (gen_rtx_SET (VOIDmode,
1664 stack_pointer_rtx,
1665 gen_rtx_PLUS (Pmode,
1666 stack_pointer_rtx,
1667 GEN_INT (count * (TARGET_LARGE ? -4 : -2)))));
1668
1669 /* *sp-- = R[i-j] */
1670 /* sp+N R10
1671 ...
1672 sp R4 */
1673 for (j = 0; j < count; j ++)
1674 {
1675 rtx addr;
1676 int ofs = (count - j - 1) * (TARGET_LARGE ? 4 : 2);
1677
1678 if (ofs)
1679 addr = gen_rtx_PLUS (Pmode, sp, GEN_INT (ofs));
1680 else
1681 addr = stack_pointer_rtx;
1682
c6f709ec 1683 XVECEXP (note, 0, j + 1) =
f6a83b4a
DD
1684 F (gen_rtx_SET (VOIDmode,
1685 gen_rtx_MEM (Pmode, addr),
1686 gen_rtx_REG (Pmode, i - j)) );
1687 }
1688
1689 add_reg_note (p, REG_FRAME_RELATED_EXPR, note);
1690 i -= count - 1;
1691 }
1692 else
1693 F (emit_insn (gen_push (gen_rtx_REG (Pmode, i))));
1694 }
1695
1696 if (frame_pointer_needed)
1697 F (emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM), sp));
1698
1699 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1700
1701 increment_stack (- fs);
1702
1703 emit_insn (gen_prologue_end_marker ());
1704}
1705
1706void
1707msp430_expand_epilogue (int is_eh)
1708{
1709 int i;
1710 int fs;
1711 int helper_n = 0;
1712
cad055a4 1713 if (is_naked_func ())
f642a8b7
NC
1714 {
1715 /* We must generate some RTX as thread_prologue_and_epilogue_insns()
1716 examines the output of the gen_epilogue() function. */
1717 emit_insn (gen_rtx_CLOBBER (VOIDmode, GEN_INT (0)));
1718 return;
1719 }
cad055a4 1720
f6a83b4a
DD
1721 if (cfun->machine->need_to_save [10])
1722 {
1723 /* Check for a helper function. */
40ada30a 1724 helper_n = 7; /* For when the loop below never sees a match. */
f6a83b4a
DD
1725 for (i = 9; i >= 4; i--)
1726 if (!cfun->machine->need_to_save [i])
1727 {
1728 helper_n = 10 - i;
1729 for (; i >= 4; i--)
1730 if (cfun->machine->need_to_save [i])
1731 {
1732 helper_n = 0;
1733 break;
1734 }
1735 break;
1736 }
1737 }
1738
1739 emit_insn (gen_epilogue_start_marker ());
1740
4f50b9ff
DD
1741 if (cfun->decl && strcmp (IDENTIFIER_POINTER (DECL_NAME (cfun->decl)), "main") == 0)
1742 emit_insn (gen_msp430_refsym_need_exit ());
1743
a005b5be
NC
1744 if (is_wakeup_func ())
1745 /* Clear the SCG1, SCG0, OSCOFF and CPUOFF bits in the saved copy of the
1746 status register current residing on the stack. When this function
1747 executes its RETI instruction the SR will be updated with this saved
1748 value, thus ensuring that the processor is woken up from any low power
1749 state in which it may be residing. */
1750 emit_insn (gen_bic_SR (GEN_INT (0xf0)));
1751
f6a83b4a
DD
1752 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1753
1754 increment_stack (fs);
1755
1756 if (is_eh)
1757 {
1758 /* We need to add the right "SP" register save just after the
1759 regular ones, so that when we pop it off we're in the EH
1760 return frame, not this one. This overwrites our own return
1761 address, but we're not going to be returning anyway. */
1762 rtx r12 = gen_rtx_REG (Pmode, 12);
1763 rtx (*addPmode)(rtx, rtx, rtx) = TARGET_LARGE ? gen_addpsi3 : gen_addhi3;
1764
1765 /* R12 will hold the new SP. */
1766 i = cfun->machine->framesize_regs;
1767 emit_move_insn (r12, stack_pointer_rtx);
1768 emit_insn (addPmode (r12, r12, EH_RETURN_STACKADJ_RTX));
1769 emit_insn (addPmode (r12, r12, GEN_INT (i)));
1770 emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (Pmode, stack_pointer_rtx, i)), r12);
1771 }
1772
1773 for (i = 4; i <= 15; i++)
1774 if (cfun->machine->need_to_save [i])
1775 {
1776 int seq, count;
1777
1778 for (seq = i + 1; seq <= 15 && cfun->machine->need_to_save[seq]; seq ++)
1779 ;
1780 count = seq - i;
1781
1782 if (msp430x)
1783 {
d4f283a1
NC
1784 /* Note: With TARGET_LARGE we still use
1785 POPM as POPX.A is two bytes bigger. */
1786 emit_insn (gen_popm (stack_pointer_rtx, GEN_INT (seq - 1),
f6a83b4a
DD
1787 GEN_INT (count)));
1788 i += count - 1;
1789 }
1790 else if (i == 11 - helper_n
cad055a4
NC
1791 && ! msp430_is_interrupt_func ()
1792 && ! is_reentrant_func ()
1793 && ! is_critical_func ()
f6a83b4a
DD
1794 && crtl->args.pretend_args_size == 0
1795 /* Calling the helper takes as many bytes as the POP;RET sequence. */
40ada30a 1796 && helper_n > 1
f6a83b4a
DD
1797 && !is_eh)
1798 {
1799 emit_insn (gen_epilogue_helper (GEN_INT (helper_n)));
1800 return;
1801 }
1802 else
1803 emit_insn (gen_pop (gen_rtx_REG (Pmode, i)));
1804 }
1805
1806 if (is_eh)
1807 {
1808 /* Also pop SP, which puts us into the EH return frame. Except
1809 that you can't "pop" sp, you have to just load it off the
1810 stack. */
1811 emit_move_insn (stack_pointer_rtx, gen_rtx_MEM (Pmode, stack_pointer_rtx));
1812 }
1813
1814 if (crtl->args.pretend_args_size)
1815 emit_insn (gen_swap_and_shrink ());
cad055a4
NC
1816
1817 if (is_critical_func ())
1818 emit_insn (gen_pop_intr_state ());
1819 else if (is_reentrant_func ())
1820 emit_insn (gen_enable_interrupts ());
1821
f6a83b4a
DD
1822 emit_jump_insn (gen_msp_return ());
1823}
1824
1825/* Implements EH_RETURN_STACKADJ_RTX. Saved and used later in
1826 m32c_emit_eh_epilogue. */
1827rtx
1828msp430_eh_return_stackadj_rtx (void)
1829{
1830 if (!cfun->machine->eh_stack_adjust)
1831 {
1832 rtx sa;
1833
1834 sa = gen_rtx_REG (Pmode, 15);
1835 cfun->machine->eh_stack_adjust = sa;
1836 }
1837 return cfun->machine->eh_stack_adjust;
1838}
1839
1840/* This function is called before reload, to "fix" the stack in
1841 preparation for an EH return. */
1842void
1843msp430_expand_eh_return (rtx eh_handler)
1844{
1845 /* These are all Pmode */
1846 rtx ap, sa, ra, tmp;
1847
1848 ap = arg_pointer_rtx;
1849 sa = msp430_eh_return_stackadj_rtx ();
1850 ra = eh_handler;
1851
1852 tmp = ap;
1853 tmp = gen_rtx_PLUS (Pmode, ap, sa);
1854 tmp = plus_constant (Pmode, tmp, TARGET_LARGE ? -4 : -2);
1855 tmp = gen_rtx_MEM (Pmode, tmp);
1856 emit_move_insn (tmp, ra);
1857}
1858
c32ab325
DD
1859#undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
1860#define TARGET_INIT_DWARF_REG_SIZES_EXTRA msp430_init_dwarf_reg_sizes_extra
1861void
1862msp430_init_dwarf_reg_sizes_extra (tree address)
1863{
1864 int i;
1865 rtx addr = expand_normal (address);
1866 rtx mem = gen_rtx_MEM (BLKmode, addr);
1867
1868 if (!msp430x)
1869 return;
1870
1871 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1872 {
1873 unsigned int dnum = DWARF_FRAME_REGNUM (i);
1874 unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
1875
1876 if (rnum < DWARF_FRAME_REGISTERS)
1877 {
1878 HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (QImode);
1879
1880 emit_move_insn (adjust_address (mem, QImode, offset),
1881 gen_int_mode (4, QImode));
1882 }
1883 }
1884}
1885
f6a83b4a 1886/* This is a list of MD patterns that implement fixed-count shifts. */
cad055a4
NC
1887static struct
1888{
f6a83b4a
DD
1889 const char *name;
1890 int count;
1891 int need_430x;
1892 rtx (*genfunc)(rtx,rtx);
cad055a4
NC
1893}
1894 const_shift_helpers[] =
1895{
f6a83b4a
DD
1896#define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }
1897
1898 CSH ("slli", 1, 1, slli_1),
1899 CSH ("slll", 1, 1, slll_1),
1900 CSH ("slll", 2, 1, slll_2),
1901
1902 CSH ("srai", 1, 0, srai_1),
1903 CSH ("sral", 1, 0, sral_1),
1904 CSH ("sral", 2, 0, sral_2),
1905
1906 CSH ("srll", 1, 0, srll_1),
1907 CSH ("srll", 2, 1, srll_2x),
1908 { 0, 0, 0, 0 }
1909#undef CSH
1910};
1911
1912/* The MSP430 ABI defines a number of helper functions that should be
1913 used for, for example, 32-bit shifts. This function is called to
1914 emit such a function, using the table above to optimize some
1915 cases. */
1916void
1917msp430_expand_helper (rtx *operands, const char *helper_name, bool const_variants)
1918{
1919 rtx c, f;
1920 char *helper_const = NULL;
1921 int arg2 = 13;
1922 int arg1sz = 1;
ef4bddc2
RS
1923 machine_mode arg0mode = GET_MODE (operands[0]);
1924 machine_mode arg1mode = GET_MODE (operands[1]);
1925 machine_mode arg2mode = GET_MODE (operands[2]);
f6a83b4a
DD
1926 int have_430x = msp430x ? 1 : 0;
1927
1928 if (CONST_INT_P (operands[2]))
1929 {
1930 int i;
1931
1932 for (i=0; const_shift_helpers[i].name; i++)
1933 {
1934 if (const_shift_helpers[i].need_430x <= have_430x
1935 && strcmp (helper_name, const_shift_helpers[i].name) == 0
1936 && INTVAL (operands[2]) == const_shift_helpers[i].count)
1937 {
1938 emit_insn (const_shift_helpers[i].genfunc (operands[0], operands[1]));
1939 return;
1940 }
1941 }
1942 }
1943
1944 if (arg1mode == VOIDmode)
1945 arg1mode = arg0mode;
1946 if (arg2mode == VOIDmode)
1947 arg2mode = arg0mode;
1948
1949 if (arg1mode == SImode)
1950 {
1951 arg2 = 14;
1952 arg1sz = 2;
1953 }
1954
1955 if (const_variants
1956 && CONST_INT_P (operands[2])
1957 && INTVAL (operands[2]) >= 1
1958 && INTVAL (operands[2]) <= 15)
1959 {
1960 /* Note that the INTVAL is limited in value and length by the conditional above. */
1961 int len = strlen (helper_name) + 4;
1962 helper_const = (char *) xmalloc (len);
40ada30a 1963 snprintf (helper_const, len, "%s_%d", helper_name, (int) INTVAL (operands[2]));
f6a83b4a
DD
1964 }
1965
1966 emit_move_insn (gen_rtx_REG (arg1mode, 12),
1967 operands[1]);
1968 if (!helper_const)
1969 emit_move_insn (gen_rtx_REG (arg2mode, arg2),
1970 operands[2]);
1971
1972 c = gen_call_value_internal (gen_rtx_REG (arg0mode, 12),
1973 gen_rtx_SYMBOL_REF (VOIDmode, helper_const ? helper_const : helper_name),
1974 GEN_INT (0));
1975 c = emit_call_insn (c);
1976 RTL_CONST_CALL_P (c) = 1;
1977
1978 f = 0;
1979 use_regs (&f, 12, arg1sz);
1980 if (!helper_const)
1981 use_regs (&f, arg2, 1);
1982 add_function_usage_to (c, f);
1983
1984 emit_move_insn (operands[0],
1985 gen_rtx_REG (arg0mode, 12));
1986}
1987
1988/* Called by cbranch<mode>4 to coerce operands into usable forms. */
1989void
ef4bddc2 1990msp430_fixup_compare_operands (machine_mode my_mode, rtx * operands)
f6a83b4a
DD
1991{
1992 /* constants we're looking for, not constants which are allowed. */
1993 int const_op_idx = 1;
1994
1995 if (msp430_reversible_cmp_operator (operands[0], VOIDmode))
1996 const_op_idx = 2;
1997
1998 if (GET_CODE (operands[const_op_idx]) != REG
1999 && GET_CODE (operands[const_op_idx]) != MEM)
2000 operands[const_op_idx] = copy_to_mode_reg (my_mode, operands[const_op_idx]);
2001}
2002
2003/* Simplify_gen_subreg() doesn't handle memory references the way we
2004 need it to below, so we use this function for when we must get a
2005 valid subreg in a "natural" state. */
2006rtx
ef4bddc2 2007msp430_subreg (machine_mode mode, rtx r, machine_mode omode, int byte)
f6a83b4a
DD
2008{
2009 rtx rv;
2010
2011 if (GET_CODE (r) == SUBREG
2012 && SUBREG_BYTE (r) == 0)
2013 {
2014 rtx ireg = SUBREG_REG (r);
ef4bddc2 2015 machine_mode imode = GET_MODE (ireg);
f6a83b4a
DD
2016
2017 /* special case for (HI (SI (PSI ...), 0)) */
2018 if (imode == PSImode
2019 && mode == HImode
2020 && byte == 0)
2021 rv = gen_rtx_SUBREG (mode, ireg, byte);
2022 else
2023 rv = simplify_gen_subreg (mode, ireg, imode, byte);
2024 }
2025 else if (GET_CODE (r) == MEM)
2026 rv = adjust_address (r, mode, byte);
2027 else
2028 rv = simplify_gen_subreg (mode, r, omode, byte);
2029
2030 if (!rv)
2031 gcc_unreachable ();
2032
2033 return rv;
2034}
2035
2036/* Called by movsi_x to generate the HImode operands. */
2037void
2038msp430_split_movsi (rtx *operands)
2039{
2040 rtx op00, op02, op10, op12;
2041
2042 op00 = msp430_subreg (HImode, operands[0], SImode, 0);
2043 op02 = msp430_subreg (HImode, operands[0], SImode, 2);
2044
2045 if (GET_CODE (operands[1]) == CONST
2046 || GET_CODE (operands[1]) == SYMBOL_REF)
2047 {
2048 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
2049 op10 = gen_rtx_CONST (HImode, op10);
2050 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
2051 op12 = gen_rtx_CONST (HImode, op12);
2052 }
2053 else
2054 {
2055 op10 = msp430_subreg (HImode, operands[1], SImode, 0);
2056 op12 = msp430_subreg (HImode, operands[1], SImode, 2);
2057 }
2058
2059 if (rtx_equal_p (operands[0], operands[1]))
2060 {
2061 operands[2] = op02;
2062 operands[4] = op12;
2063 operands[3] = op00;
2064 operands[5] = op10;
2065 }
2066 else if (rtx_equal_p (op00, op12)
2067 /* Catch the case where we are loading (rN, rN+1) from mem (rN). */
2068 || (REG_P (op00) && reg_mentioned_p (op00, op10))
2069 /* Or storing (rN) into mem (rN). */
2070 || (REG_P (op10) && reg_mentioned_p (op10, op00))
2071 )
2072 {
2073 operands[2] = op02;
2074 operands[4] = op12;
2075 operands[3] = op00;
2076 operands[5] = op10;
2077 }
2078 else
2079 {
2080 operands[2] = op00;
2081 operands[4] = op10;
2082 operands[3] = op02;
2083 operands[5] = op12;
2084 }
2085}
2086
2087\f
f6a83b4a
DD
2088/* The MSPABI specifies the names of various helper functions, many of
2089 which are compatible with GCC's helpers. This table maps the GCC
2090 name to the MSPABI name. */
2091static const struct
2092{
2093 char const * const gcc_name;
2094 char const * const ti_name;
2095}
2096 helper_function_name_mappings [] =
2097{
2098 /* Floating point to/from integer conversions. */
2099 { "__truncdfsf2", "__mspabi_cvtdf" },
2100 { "__extendsfdf2", "__mspabi_cvtfd" },
2101 { "__fixdfhi", "__mspabi_fixdi" },
2102 { "__fixdfsi", "__mspabi_fixdli" },
2103 { "__fixdfdi", "__mspabi_fixdlli" },
2104 { "__fixunsdfhi", "__mspabi_fixdu" },
2105 { "__fixunsdfsi", "__mspabi_fixdul" },
2106 { "__fixunsdfdi", "__mspabi_fixdull" },
2107 { "__fixsfhi", "__mspabi_fixfi" },
2108 { "__fixsfsi", "__mspabi_fixfli" },
2109 { "__fixsfdi", "__mspabi_fixflli" },
2110 { "__fixunsfhi", "__mspabi_fixfu" },
2111 { "__fixunsfsi", "__mspabi_fixful" },
2112 { "__fixunsfdi", "__mspabi_fixfull" },
2113 { "__floathisf", "__mspabi_fltif" },
2114 { "__floatsisf", "__mspabi_fltlif" },
2115 { "__floatdisf", "__mspabi_fltllif" },
2116 { "__floathidf", "__mspabi_fltid" },
2117 { "__floatsidf", "__mspabi_fltlid" },
2118 { "__floatdidf", "__mspabi_fltllid" },
2119 { "__floatunhisf", "__mspabi_fltuf" },
2120 { "__floatunsisf", "__mspabi_fltulf" },
2121 { "__floatundisf", "__mspabi_fltullf" },
2122 { "__floatunhidf", "__mspabi_fltud" },
2123 { "__floatunsidf", "__mspabi_fltuld" },
2124 { "__floatundidf", "__mspabi_fltulld" },
2125
2126 /* Floating point comparisons. */
2127 /* GCC uses individual functions for each comparison, TI uses one
2128 compare <=> function. */
2129
2130 /* Floating point arithmatic */
2131 { "__adddf3", "__mspabi_addd" },
2132 { "__addsf3", "__mspabi_addf" },
2133 { "__divdf3", "__mspabi_divd" },
2134 { "__divsf3", "__mspabi_divf" },
2135 { "__muldf3", "__mspabi_mpyd" },
2136 { "__mulsf3", "__mspabi_mpyf" },
2137 { "__subdf3", "__mspabi_subd" },
2138 { "__subsf3", "__mspabi_subf" },
2139 /* GCC does not use helper functions for negation */
2140
2141 /* Integer multiply, divide, remainder. */
f6a83b4a
DD
2142 { "__mulhi3", "__mspabi_mpyi" },
2143 { "__mulsi3", "__mspabi_mpyl" },
2144 { "__muldi3", "__mspabi_mpyll" },
2145#if 0
2146 /* Clarify signed vs unsigned first. */
2147 { "__mulhisi3", "__mspabi_mpysl" }, /* gcc doesn't use widening multiply (yet?) */
2148 { "__mulsidi3", "__mspabi_mpysll" }, /* gcc doesn't use widening multiply (yet?) */
2149#endif
2150
2151 { "__divhi3", "__mspabi_divi" },
2152 { "__divsi3", "__mspabi_divli" },
2153 { "__divdi3", "__mspabi_divlli" },
2154 { "__udivhi3", "__mspabi_divu" },
2155 { "__udivsi3", "__mspabi_divlu" },
2156 { "__udivdi3", "__mspabi_divllu" },
2157 { "__modhi3", "__mspabi_remi" },
2158 { "__modsi3", "__mspabi_remli" },
2159 { "__moddi3", "__mspabi_remlli" },
2160 { "__umodhi3", "__mspabi_remu" },
2161 { "__umodsi3", "__mspabi_remul" },
2162 { "__umoddi3", "__mspabi_remull" },
2163
2164 /* Bitwise operations. */
2165 /* Rotation - no rotation support yet. */
2166 /* Logical left shift - gcc already does these itself. */
2167 /* Arithmetic left shift - gcc already does these itself. */
2168 /* Arithmetic right shift - gcc already does these itself. */
2169
2170 { NULL, NULL }
2171};
2172
f642a8b7
NC
2173/* Returns true if the current MCU supports an F5xxx series
2174 hardware multiper. */
2175
c6f709ec 2176bool
f7961364 2177msp430_use_f5_series_hwmult (void)
c6f709ec 2178{
f642a8b7
NC
2179 static const char * cached_match = NULL;
2180 static bool cached_result;
2181
f7961364
NC
2182 if (msp430_hwmult_type == F5SERIES)
2183 return true;
2184
2185 if (target_mcu == NULL || msp430_hwmult_type != AUTO)
c6f709ec 2186 return false;
f7961364 2187
f642a8b7
NC
2188 if (target_mcu == cached_match)
2189 return cached_result;
2190
2191 cached_match = target_mcu;
2192
2193 if (strncasecmp (target_mcu, "msp430f5", 8) == 0)
2194 return cached_result = true;
2195
2196 static const char * known_f5_mult_mcus [] =
2197 {
2198 "cc430f5123", "cc430f5125", "cc430f5133",
2199 "cc430f5135", "cc430f5137", "cc430f5143",
2200 "cc430f5145", "cc430f5147", "cc430f6125",
2201 "cc430f6126", "cc430f6127", "cc430f6135",
2202 "cc430f6137", "cc430f6143", "cc430f6145",
2203 "cc430f6147", "msp430bt5190", "msp430sl5438a"
2204 };
2205 int i;
2206
2207 for (i = ARRAY_SIZE (known_f5_mult_mcus); i--;)
2208 if (strcasecmp (target_mcu, known_f5_mult_mcus[i]) == 0)
2209 return cached_result = true;
2210
2211 return cached_result = false;
c6f709ec
NC
2212}
2213
f642a8b7
NC
2214/* Returns true if the current MCU has a second generation
2215 32-bit hardware multiplier. */
2216
c6f709ec 2217static bool
f7961364 2218use_32bit_hwmult (void)
c6f709ec
NC
2219{
2220 static const char * known_32bit_mult_mcus [] =
2221 {
2222 "msp430f4783", "msp430f4793", "msp430f4784",
2223 "msp430f4794", "msp430f47126", "msp430f47127",
2224 "msp430f47163", "msp430f47173", "msp430f47183",
2225 "msp430f47193", "msp430f47166", "msp430f47176",
2226 "msp430f47186", "msp430f47196", "msp430f47167",
2227 "msp430f47177", "msp430f47187", "msp430f47197"
2228 };
f642a8b7
NC
2229 static const char * cached_match = NULL;
2230 static bool cached_result;
c6f709ec 2231 int i;
f7961364
NC
2232
2233 if (msp430_hwmult_type == LARGE)
2234 return true;
2235
2236 if (target_mcu == NULL || msp430_hwmult_type != AUTO)
c6f709ec
NC
2237 return false;
2238
f642a8b7
NC
2239 if (target_mcu == cached_match)
2240 return cached_result;
2241
2242 cached_match = target_mcu;
c6f709ec
NC
2243 for (i = ARRAY_SIZE (known_32bit_mult_mcus); i--;)
2244 if (strcasecmp (target_mcu, known_32bit_mult_mcus[i]) == 0)
f642a8b7 2245 return cached_result = true;
c6f709ec 2246
f642a8b7
NC
2247 return cached_result = false;
2248}
2249
2250/* Returns true if the current MCU does not have a
2251 hardware multiplier of any kind. */
2252
2253static bool
2254msp430_no_hwmult (void)
2255{
2256 static const char * known_nomult_mcus [] =
2257 {
2258 "msp430c091", "msp430c092", "msp430c111",
2259 "msp430c1111", "msp430c112", "msp430c1121",
2260 "msp430c1331", "msp430c1351", "msp430c311s",
2261 "msp430c312", "msp430c313", "msp430c314",
2262 "msp430c315", "msp430c323", "msp430c325",
2263 "msp430c412", "msp430c413", "msp430e112",
2264 "msp430e313", "msp430e315", "msp430e325",
2265 "msp430f110", "msp430f1101", "msp430f1101a",
2266 "msp430f1111", "msp430f1111a", "msp430f112",
2267 "msp430f1121", "msp430f1121a", "msp430f1122",
2268 "msp430f1132", "msp430f122", "msp430f1222",
2269 "msp430f123", "msp430f1232", "msp430f133",
2270 "msp430f135", "msp430f155", "msp430f156",
2271 "msp430f157", "msp430f2001", "msp430f2002",
2272 "msp430f2003", "msp430f2011", "msp430f2012",
2273 "msp430f2013", "msp430f2101", "msp430f2111",
2274 "msp430f2112", "msp430f2121", "msp430f2122",
2275 "msp430f2131", "msp430f2132", "msp430f2232",
2276 "msp430f2234", "msp430f2252", "msp430f2254",
2277 "msp430f2272", "msp430f2274", "msp430f412",
2278 "msp430f413", "msp430f4132", "msp430f415",
2279 "msp430f4152", "msp430f417", "msp430f4250",
2280 "msp430f4260", "msp430f4270", "msp430f435",
2281 "msp430f4351", "msp430f436", "msp430f4361",
2282 "msp430f437", "msp430f4371", "msp430f438",
2283 "msp430f439", "msp430f477", "msp430f478",
2284 "msp430f479", "msp430fe423", "msp430fe4232",
2285 "msp430fe423a", "msp430fe4242", "msp430fe425",
2286 "msp430fe4252", "msp430fe425a", "msp430fe427",
2287 "msp430fe4272", "msp430fe427a", "msp430fg4250",
2288 "msp430fg4260", "msp430fg4270", "msp430fg437",
2289 "msp430fg438", "msp430fg439", "msp430fg477",
2290 "msp430fg478", "msp430fg479", "msp430fr2032",
2291 "msp430fr2033", "msp430fr4131", "msp430fr4132",
2292 "msp430fr4133", "msp430fw423", "msp430fw425",
2293 "msp430fw427", "msp430fw428", "msp430fw429",
2294 "msp430g2001", "msp430g2101", "msp430g2102",
2295 "msp430g2111", "msp430g2112", "msp430g2113",
2296 "msp430g2121", "msp430g2131", "msp430g2132",
2297 "msp430g2152", "msp430g2153", "msp430g2201",
2298 "msp430g2202", "msp430g2203", "msp430g2210",
2299 "msp430g2211", "msp430g2212", "msp430g2213",
2300 "msp430g2221", "msp430g2230", "msp430g2231",
2301 "msp430g2232", "msp430g2233", "msp430g2252",
2302 "msp430g2253", "msp430g2302", "msp430g2303",
2303 "msp430g2312", "msp430g2313", "msp430g2332",
2304 "msp430g2333", "msp430g2352", "msp430g2353",
2305 "msp430g2402", "msp430g2403", "msp430g2412",
2306 "msp430g2413", "msp430g2432", "msp430g2433",
2307 "msp430g2444", "msp430g2452", "msp430g2453",
2308 "msp430g2513", "msp430g2533", "msp430g2544",
2309 "msp430g2553", "msp430g2744", "msp430g2755",
2310 "msp430g2855", "msp430g2955", "msp430l092",
2311 "msp430p112", "msp430p313", "msp430p315",
2312 "msp430p315s", "msp430p325", "msp430tch5e"
2313 };
2314 static const char * cached_match = NULL;
2315 static bool cached_result;
2316 int i;
2317
2318 if (msp430_hwmult_type == NONE)
2319 return true;
2320
2321 if (target_mcu == NULL || msp430_hwmult_type != AUTO)
2322 return false;
2323
2324 if (target_mcu == cached_match)
2325 return cached_result;
2326
2327 cached_match = target_mcu;
2328 for (i = ARRAY_SIZE (known_nomult_mcus); i--;)
2329 if (strcasecmp (target_mcu, known_nomult_mcus[i]) == 0)
2330 return cached_result = true;
2331
2332 return cached_result = false;
c6f709ec
NC
2333}
2334
f6a83b4a
DD
2335/* This function does the same as the default, but it will replace GCC
2336 function names with the MSPABI-specified ones. */
f642a8b7 2337
f6a83b4a
DD
2338void
2339msp430_output_labelref (FILE *file, const char *name)
2340{
2341 int i;
2342
2343 for (i = 0; helper_function_name_mappings [i].gcc_name; i++)
c6f709ec 2344 if (strcmp (helper_function_name_mappings [i].gcc_name, name) == 0)
f6a83b4a 2345 {
c6f709ec
NC
2346 name = helper_function_name_mappings [i].ti_name;
2347 break;
f6a83b4a
DD
2348 }
2349
c6f709ec
NC
2350 /* If we have been given a specific MCU name then we may be
2351 able to make use of its hardware multiply capabilities. */
f7961364 2352 if (msp430_hwmult_type != NONE)
c6f709ec
NC
2353 {
2354 if (strcmp ("__mspabi_mpyi", name) == 0)
2355 {
f7961364 2356 if (msp430_use_f5_series_hwmult ())
c6f709ec 2357 name = "__mulhi2_f5";
f642a8b7 2358 else if (! msp430_no_hwmult ())
c6f709ec
NC
2359 name = "__mulhi2";
2360 }
2361 else if (strcmp ("__mspabi_mpyl", name) == 0)
2362 {
f7961364 2363 if (msp430_use_f5_series_hwmult ())
c6f709ec 2364 name = "__mulsi2_f5";
f7961364 2365 else if (use_32bit_hwmult ())
c6f709ec 2366 name = "__mulsi2_hw32";
f642a8b7 2367 else if (! msp430_no_hwmult ())
c6f709ec
NC
2368 name = "__mulsi2";
2369 }
2370 }
2371
f6a83b4a
DD
2372 fputs (name, file);
2373}
2374
40ada30a 2375/* Common code for msp430_print_operand... */
f6a83b4a 2376
f6a83b4a 2377static void
40ada30a 2378msp430_print_operand_raw (FILE * file, rtx op)
f6a83b4a 2379{
a005b5be 2380 HOST_WIDE_INT i;
f6a83b4a
DD
2381
2382 switch (GET_CODE (op))
2383 {
2384 case REG:
2385 fprintf (file, "%s", reg_names [REGNO (op)]);
2386 break;
2387
2388 case CONST_INT:
2389 i = INTVAL (op);
2390 if (TARGET_ASM_HEX)
a005b5be 2391 fprintf (file, "%#" HOST_WIDE_INT_PRINT "x", i);
f6a83b4a 2392 else
a005b5be 2393 fprintf (file, "%" HOST_WIDE_INT_PRINT "d", i);
f6a83b4a
DD
2394 break;
2395
2396 case CONST:
2397 case PLUS:
2398 case MINUS:
2399 case SYMBOL_REF:
2400 case LABEL_REF:
2401 output_addr_const (file, op);
2402 break;
2403
2404 default:
2405 print_rtl (file, op);
2406 break;
2407 }
2408}
2409
40ada30a
NC
2410#undef TARGET_PRINT_OPERAND_ADDRESS
2411#define TARGET_PRINT_OPERAND_ADDRESS msp430_print_operand_addr
2412
2413/* Output to stdio stream FILE the assembler syntax for an
2414 instruction operand that is a memory reference whose address
2415 is ADDR. */
2416
2417static void
2418msp430_print_operand_addr (FILE * file, rtx addr)
2419{
2420 switch (GET_CODE (addr))
2421 {
2422 case PLUS:
2423 msp430_print_operand_raw (file, XEXP (addr, 1));
2424 gcc_assert (REG_P (XEXP (addr, 0)));
2425 fprintf (file, "(%s)", reg_names [REGNO (XEXP (addr, 0))]);
2426 return;
2427
2428 case REG:
2429 fprintf (file, "@");
2430 break;
2431
2432 case CONST:
2433 case CONST_INT:
2434 case SYMBOL_REF:
2435 case LABEL_REF:
2436 fprintf (file, "&");
2437 break;
2438
2439 default:
2440 break;
2441 }
2442
2443 msp430_print_operand_raw (file, addr);
2444}
2445
2446#undef TARGET_PRINT_OPERAND
2447#define TARGET_PRINT_OPERAND msp430_print_operand
2448
51ac3042
NC
2449/* A low 16-bits of int/lower of register pair
2450 B high 16-bits of int/higher of register pair
2451 C bits 32-47 of a 64-bit value/reg 3 of a DImode value
2452 D bits 48-63 of a 64-bit value/reg 4 of a DImode value
2453 H like %B (for backwards compatibility)
2454 I inverse of value
fb28dac0 2455 J an integer without a # prefix
51ac3042
NC
2456 L like %A (for backwards compatibility)
2457 O offset of the top of the stack
2458 Q like X but generates an A postfix
2459 R inverse of condition code, unsigned.
2460 X X instruction postfix in large mode
2461 Y value - 4
2462 Z value - 1
2463 b .B or .W or .A, depending upon the mode
2464 p bit position
2465 r inverse of condition code
2466 x like X but only for pointers. */
2467
f6a83b4a
DD
2468static void
2469msp430_print_operand (FILE * file, rtx op, int letter)
2470{
2471 rtx addr;
2472
2473 /* We can't use c, n, a, or l. */
2474 switch (letter)
2475 {
2476 case 'Z':
2477 gcc_assert (CONST_INT_P (op));
2478 /* Print the constant value, less one. */
2479 fprintf (file, "#%ld", INTVAL (op) - 1);
2480 return;
2481 case 'Y':
2482 gcc_assert (CONST_INT_P (op));
2483 /* Print the constant value, less four. */
2484 fprintf (file, "#%ld", INTVAL (op) - 4);
2485 return;
f6a83b4a
DD
2486 case 'I':
2487 if (GET_CODE (op) == CONST_INT)
2488 {
2489 /* Inverse of constants */
2490 int i = INTVAL (op);
2491 fprintf (file, "%d", ~i);
2492 return;
2493 }
2494 op = XEXP (op, 0);
2495 break;
2496 case 'r': /* Conditional jump where the condition is reversed. */
2497 switch (GET_CODE (op))
2498 {
2499 case EQ: fprintf (file, "NE"); break;
2500 case NE: fprintf (file, "EQ"); break;
2501 case GEU: fprintf (file, "LO"); break;
2502 case LTU: fprintf (file, "HS"); break;
2503 case GE: fprintf (file, "L"); break;
2504 case LT: fprintf (file, "GE"); break;
2505 /* Assume these have reversed operands. */
2506 case GTU: fprintf (file, "HS"); break;
2507 case LEU: fprintf (file, "LO"); break;
2508 case GT: fprintf (file, "GE"); break;
2509 case LE: fprintf (file, "L"); break;
2510 default:
40ada30a 2511 msp430_print_operand_raw (file, op);
f6a83b4a
DD
2512 break;
2513 }
2514 return;
2515 case 'R': /* Conditional jump where the operands are reversed. */
2516 switch (GET_CODE (op))
2517 {
2518 case GTU: fprintf (file, "LO"); break;
2519 case LEU: fprintf (file, "HS"); break;
2520 case GT: fprintf (file, "L"); break;
2521 case LE: fprintf (file, "GE"); break;
2522 default:
40ada30a 2523 msp430_print_operand_raw (file, op);
f6a83b4a
DD
2524 break;
2525 }
2526 return;
2527 case 'p': /* Bit position. 0 == 0x01, 3 = 0x08 etc. */
2528 gcc_assert (CONST_INT_P (op));
2529 fprintf (file, "#%d", 1 << INTVAL (op));
2530 return;
51ac3042 2531 case 'b':
f6a83b4a
DD
2532 switch (GET_MODE (op))
2533 {
2534 case QImode: fprintf (file, ".B"); return;
2535 case HImode: fprintf (file, ".W"); return;
2536 case PSImode: fprintf (file, ".A"); return;
2537 case SImode: fprintf (file, ".A"); return;
2538 default:
2539 return;
2540 }
51ac3042 2541 case 'A':
f6a83b4a
DD
2542 case 'L': /* Low half. */
2543 switch (GET_CODE (op))
2544 {
2545 case MEM:
2546 op = adjust_address (op, Pmode, 0);
2547 break;
2548 case REG:
2549 break;
2550 case CONST_INT:
2551 op = GEN_INT (INTVAL (op) & 0xffff);
2552 letter = 0;
2553 break;
2554 default:
2555 /* If you get here, figure out a test case :-) */
2556 gcc_unreachable ();
2557 }
2558 break;
51ac3042 2559 case 'B':
f6a83b4a
DD
2560 case 'H': /* high half */
2561 switch (GET_CODE (op))
2562 {
2563 case MEM:
2564 op = adjust_address (op, Pmode, 2);
2565 break;
2566 case REG:
2567 op = gen_rtx_REG (Pmode, REGNO (op) + 1);
2568 break;
2569 case CONST_INT:
2570 op = GEN_INT (INTVAL (op) >> 16);
2571 letter = 0;
2572 break;
2573 default:
2574 /* If you get here, figure out a test case :-) */
2575 gcc_unreachable ();
2576 }
2577 break;
51ac3042
NC
2578 case 'C':
2579 switch (GET_CODE (op))
2580 {
2581 case MEM:
2582 op = adjust_address (op, Pmode, 3);
2583 break;
2584 case REG:
2585 op = gen_rtx_REG (Pmode, REGNO (op) + 2);
2586 break;
2587 case CONST_INT:
c6f709ec 2588 op = GEN_INT ((long long) INTVAL (op) >> 32);
51ac3042
NC
2589 letter = 0;
2590 break;
2591 default:
2592 /* If you get here, figure out a test case :-) */
2593 gcc_unreachable ();
2594 }
2595 break;
2596 case 'D':
2597 switch (GET_CODE (op))
2598 {
2599 case MEM:
2600 op = adjust_address (op, Pmode, 4);
2601 break;
2602 case REG:
2603 op = gen_rtx_REG (Pmode, REGNO (op) + 3);
2604 break;
2605 case CONST_INT:
c6f709ec 2606 op = GEN_INT ((long long) INTVAL (op) >> 48);
51ac3042
NC
2607 letter = 0;
2608 break;
2609 default:
2610 /* If you get here, figure out a test case :-) */
2611 gcc_unreachable ();
2612 }
2613 break;
f6a83b4a
DD
2614
2615 case 'X':
2616 /* This is used to turn, for example, an ADD opcode into an ADDX
2617 opcode when we're using 20-bit addresses. */
c32ab325 2618 if (TARGET_LARGE || GET_MODE (op) == PSImode)
f6a83b4a
DD
2619 fprintf (file, "X");
2620 /* We don't care which operand we use, but we want 'X' in the MD
2621 file, so we do it this way. */
2622 return;
2623
2624 case 'x':
2625 /* Similarly, but only for PSImodes. BIC, for example, needs this. */
5cbc4e2a 2626 if (GET_MODE (op) == PSImode)
f6a83b4a
DD
2627 fprintf (file, "X");
2628 return;
2629
51ac3042 2630 case 'Q':
f6a83b4a
DD
2631 /* Likewise, for BR -> BRA. */
2632 if (TARGET_LARGE)
2633 fprintf (file, "A");
2634 return;
cad055a4
NC
2635
2636 case 'O':
2637 /* Computes the offset to the top of the stack for the current frame.
2638 This has to be done here rather than in, say, msp430_expand_builtin()
2639 because builtins are expanded before the frame layout is determined. */
2640 fprintf (file, "%d",
2641 msp430_initial_elimination_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM)
d77f7b19 2642 - (TARGET_LARGE ? 4 : 2));
40ada30a 2643 return;
51ac3042 2644
fb28dac0
DD
2645 case 'J':
2646 gcc_assert (GET_CODE (op) == CONST_INT);
51ac3042
NC
2647 case 0:
2648 break;
2649 default:
2650 output_operand_lossage ("invalid operand prefix");
2651 return;
f6a83b4a
DD
2652 }
2653
2654 switch (GET_CODE (op))
2655 {
2656 case REG:
40ada30a 2657 msp430_print_operand_raw (file, op);
f6a83b4a
DD
2658 break;
2659
2660 case MEM:
2661 addr = XEXP (op, 0);
40ada30a 2662 msp430_print_operand_addr (file, addr);
f6a83b4a
DD
2663 break;
2664
f6a83b4a 2665 case CONST:
467fc67c
NC
2666 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT)
2667 {
2668 op = XEXP (op, 0);
2669 switch (INTVAL (XEXP (op, 2)))
2670 {
2671 case 0:
2672 fprintf (file, "#lo (");
2673 msp430_print_operand_raw (file, XEXP (op, 0));
2674 fprintf (file, ")");
2675 break;
2676
2677 case 16:
2678 fprintf (file, "#hi (");
2679 msp430_print_operand_raw (file, XEXP (op, 0));
2680 fprintf (file, ")");
2681 break;
2682
2683 default:
2684 output_operand_lossage ("invalid zero extract");
2685 break;
2686 }
2687 break;
2688 }
2689 /* Fall through. */
2690 case CONST_INT:
f6a83b4a
DD
2691 case SYMBOL_REF:
2692 case LABEL_REF:
2693 if (letter == 0)
2694 fprintf (file, "#");
40ada30a 2695 msp430_print_operand_raw (file, op);
f6a83b4a
DD
2696 break;
2697
2698 case EQ: fprintf (file, "EQ"); break;
2699 case NE: fprintf (file, "NE"); break;
2700 case GEU: fprintf (file, "HS"); break;
2701 case LTU: fprintf (file, "LO"); break;
2702 case GE: fprintf (file, "GE"); break;
2703 case LT: fprintf (file, "L"); break;
2704
2705 default:
2706 print_rtl (file, op);
2707 break;
2708 }
f6a83b4a
DD
2709}
2710
2711\f
2712/* Frame stuff. */
2713
2714rtx
2715msp430_return_addr_rtx (int count)
2716{
2717 int ra_size;
2718 if (count)
2719 return NULL_RTX;
2720
2721 ra_size = TARGET_LARGE ? 4 : 2;
2722 if (crtl->args.pretend_args_size)
2723 ra_size += 2;
2724
2725 return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (- ra_size)));
2726}
2727
2728rtx
2729msp430_incoming_return_addr_rtx (void)
2730{
2731 return gen_rtx_MEM (Pmode, stack_pointer_rtx);
2732}
2733\f
2734/* Instruction generation stuff. */
2735
2736/* Generate a sequence of instructions to sign-extend an HI
2737 value into an SI value. Handles the tricky case where
2738 we are overwriting the destination. */
2739
2740const char *
2741msp430x_extendhisi (rtx * operands)
2742{
2743 if (REGNO (operands[0]) == REGNO (operands[1]))
2744 /* Low word of dest == source word. */
d4f283a1 2745 return "BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; /* 8-bytes. */
f6a83b4a
DD
2746
2747 if (! msp430x)
2748 /* Note: This sequence is approximately the same length as invoking a helper
2749 function to perform the sign-extension, as in:
c6f709ec 2750
f6a83b4a
DD
2751 MOV.W %1, %L0
2752 MOV.W %1, r12
2753 CALL __mspabi_srai_15
2754 MOV.W r12, %H0
2755
2756 but this version does not involve any function calls or using argument
2757 registers, so it reduces register pressure. */
d4f283a1 2758 return "MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; /* 10-bytes. */
c6f709ec 2759
f6a83b4a
DD
2760 if (REGNO (operands[0]) + 1 == REGNO (operands[1]))
2761 /* High word of dest == source word. */
d4f283a1 2762 return "MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0"; /* 6-bytes. */
f6a83b4a
DD
2763
2764 /* No overlap between dest and source. */
d4f283a1 2765 return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; /* 8-bytes. */
f6a83b4a
DD
2766}
2767
2768/* Likewise for logical right shifts. */
2769const char *
2770msp430x_logical_shift_right (rtx amount)
2771{
2772 /* The MSP430X's logical right shift instruction - RRUM - does
2773 not use an extension word, so we cannot encode a repeat count.
2774 Try various alternatives to work around this. If the count
2775 is in a register we are stuck, hence the assert. */
2776 gcc_assert (CONST_INT_P (amount));
2777
2778 if (INTVAL (amount) <= 0
2779 || INTVAL (amount) >= 16)
2780 return "# nop logical shift.";
2781
c6f709ec 2782 if (INTVAL (amount) > 0
f6a83b4a
DD
2783 && INTVAL (amount) < 5)
2784 return "rrum.w\t%2, %0"; /* Two bytes. */
2785
c6f709ec 2786 if (INTVAL (amount) > 4
f6a83b4a
DD
2787 && INTVAL (amount) < 9)
2788 return "rrum.w\t#4, %0 { rrum.w\t%Y2, %0 "; /* Four bytes. */
2789
2790 /* First we logically shift right by one. Now we know
2791 that the top bit is zero and we can use the arithmetic
2792 right shift instruction to perform the rest of the shift. */
2793 return "rrum.w\t#1, %0 { rpt\t%Z2 { rrax.w\t%0"; /* Six bytes. */
2794}
2795\f
2796struct gcc_target targetm = TARGET_INITIALIZER;
2797
2798#include "gt-msp430.h"