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