1 /* Subroutines used for code generation on TI MSP430 processors.
2 Copyright (C) 2012-2014 Free Software Foundation, Inc.
3 Contributed by Red Hat.
5 This file is part of GCC.
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)
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.
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/>. */
23 #include "coretypes.h"
26 #include "stor-layout.h"
30 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "conditions.h"
34 #include "insn-attr.h"
43 #include "insn-codes.h"
47 #include "diagnostic-core.h"
50 #include "dominance.h"
56 #include "cfgcleanup.h"
58 #include "basic-block.h"
64 #include "target-def.h"
65 #include "langhooks.h"
66 #include "msp430-protos.h"
72 static void msp430_compute_frame_info (void);
76 /* Run-time Target Specification. */
80 struct GTY(()) machine_function
82 /* If set, the rest of the fields have been computed. */
84 /* Which registers need to be saved in the pro/epilogue. */
85 int need_to_save
[FIRST_PSEUDO_REGISTER
];
87 /* These fields describe the frame layout... */
89 /* 2/4 bytes for saved PC */
93 int framesize_outgoing
;
97 /* How much we adjust the stack when returning from an exception
102 /* This is our init_machine_status, as set in
103 msp_option_override. */
104 static struct machine_function
*
105 msp430_init_machine_status (void)
107 struct machine_function
*m
;
109 m
= ggc_cleared_alloc
<machine_function
> ();
114 #undef TARGET_OPTION_OVERRIDE
115 #define TARGET_OPTION_OVERRIDE msp430_option_override
117 static const char * msp430_mcu_names
[] =
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"
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. */
180 msp430_mcu_name (void)
185 static char mcu_name
[64];
187 snprintf (mcu_name
, sizeof (mcu_name
) - 1, "__%s__", target_mcu
);
188 for (i
= strlen (mcu_name
); i
--;)
189 mcu_name
[i
] = TOUPPER (mcu_name
[i
]);
193 return msp430x
? "__MSP430XGENERIC__" : "__MSP430GENERIC__";
197 msp430_option_override (void)
199 init_machine_status
= msp430_init_machine_status
;
203 if (strcasecmp (target_cpu
, "msp430x") == 0)
205 else /* target_cpu == "msp430" - already handled by the front end. */
208 /* Note - the front end has already ensured at most
209 one of target_cpu and target_mcu will be set. */
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
219 for (i
= ARRAY_SIZE (msp430_mcu_names
); i
--;)
220 if (strcasecmp (msp430_mcu_names
[i
], target_mcu
) == 0)
225 /* It is not an error if we do not match the MCU name. There are
229 if (TARGET_LARGE
&& !msp430x
)
230 error ("-mlarge requires a 430X-compatible -mmcu=");
232 if (flag_exceptions
|| flag_non_call_exceptions
233 || flag_unwind_tables
|| flag_asynchronous_unwind_tables
)
234 flag_omit_frame_pointer
= false;
236 flag_omit_frame_pointer
= true;
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)
246 #undef TARGET_SCALAR_MODE_SUPPORTED_P
247 #define TARGET_SCALAR_MODE_SUPPORTED_P msp430_scalar_mode_supported_p
250 msp430_scalar_mode_supported_p (machine_mode m
)
252 if (m
== PSImode
&& msp430x
)
258 return default_scalar_mode_supported_p (m
);
265 #undef TARGET_MS_BITFIELD_LAYOUT_P
266 #define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p
269 msp430_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED
)
278 /* Implements HARD_REGNO_NREGS. MSP430X registers can hold a single
279 PSImode value, but not an SImode value. */
281 msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED
,
284 if (mode
== PSImode
&& msp430x
)
286 return ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
290 /* Implements HARD_REGNO_NREGS_HAS_PADDING. */
292 msp430_hard_regno_nregs_has_padding (int regno ATTRIBUTE_UNUSED
,
295 if (mode
== PSImode
&& msp430x
)
297 return ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
301 /* Implements HARD_REGNO_NREGS_WITH_PADDING. */
303 msp430_hard_regno_nregs_with_padding (int regno ATTRIBUTE_UNUSED
,
308 return msp430_hard_regno_nregs (regno
, mode
);
311 /* Implements HARD_REGNO_MODE_OK. */
313 msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED
,
316 return regno
<= (ARG_POINTER_REGNUM
- msp430_hard_regno_nregs (regno
, mode
));
319 /* Implements MODES_TIEABLE_P. */
321 msp430_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
323 if ((mode1
== PSImode
|| mode2
== SImode
)
324 || (mode1
== SImode
|| mode2
== PSImode
))
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
));
333 #undef TARGET_FRAME_POINTER_REQUIRED
334 #define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required
337 msp430_frame_pointer_required (void)
342 #undef TARGET_CAN_ELIMINATE
343 #define TARGET_CAN_ELIMINATE msp430_can_eliminate
346 msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED
,
347 const int to_reg ATTRIBUTE_UNUSED
)
352 /* Implements INITIAL_ELIMINATION_OFFSET. */
354 msp430_initial_elimination_offset (int from
, int to
)
356 int rv
= 0; /* As if arg to arg. */
358 msp430_compute_frame_info ();
362 case STACK_POINTER_REGNUM
:
363 rv
+= cfun
->machine
->framesize_outgoing
;
364 rv
+= cfun
->machine
->framesize_locals
;
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. */
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
:
392 /* Named Address Space support */
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
402 msp430_addr_space_pointer_mode (addr_space_t addrspace
)
407 case ADDR_SPACE_GENERIC
:
409 case ADDR_SPACE_NEAR
:
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
422 msp430_unwind_word_mode (void)
424 return TARGET_LARGE
? PSImode
: HImode
;
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
431 msp430_addr_space_subset_p (addr_space_t subset
, addr_space_t superset
)
433 if (subset
== superset
)
436 return (subset
!= ADDR_SPACE_FAR
&& superset
== ADDR_SPACE_FAR
);
439 #undef TARGET_ADDR_SPACE_CONVERT
440 #define TARGET_ADDR_SPACE_CONVERT msp430_addr_space_convert
441 /* Convert from one address space to another. */
443 msp430_addr_space_convert (rtx op
, tree from_type
, tree to_type
)
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
));
449 if (to_as
!= ADDR_SPACE_FAR
&& from_as
== ADDR_SPACE_FAR
)
451 /* This is unpredictable, as we're truncating off usable address
455 return gen_rtx_CONST (HImode
, op
);
457 result
= gen_reg_rtx (HImode
);
458 emit_insn (gen_truncpsihi2 (result
, op
));
461 else if (to_as
== ADDR_SPACE_FAR
&& from_as
!= ADDR_SPACE_FAR
)
463 /* This always works. */
466 return gen_rtx_CONST (PSImode
, op
);
468 result
= gen_reg_rtx (PSImode
);
469 emit_insn (gen_zero_extendhipsi2 (result
, op
));
476 /* Stack Layout and Calling Conventions. */
478 /* For each function, we list the gcc version and the TI version on
479 each line, where we're converting the function names. */
480 static char const * const special_convention_function_names
[] =
482 "__muldi3", "__mspabi_mpyll",
483 "__udivdi3", "__mspabi_divull",
484 "__umoddi3", "__mspabi_remull",
485 "__divdi3", "__mspabi_divlli",
486 "__moddi3", "__mspabi_remlli",
490 "__adddf3", "__mspabi_addd",
491 "__subdf3", "__mspabi_subd",
492 "__muldf3", "__mspabi_mpyd",
493 "__divdf3", "__mspabi_divd",
498 /* TRUE if the function passed is a "speical" function. Special
499 functions pass two DImode parameters in registers. */
501 msp430_special_register_convention_p (const char *name
)
505 for (i
= 0; special_convention_function_names
[i
]; i
++)
506 if (! strcmp (name
, special_convention_function_names
[i
]))
512 #undef TARGET_FUNCTION_VALUE_REGNO_P
513 #define TARGET_FUNCTION_VALUE_REGNO_P msp430_function_value_regno_p
516 msp430_function_value_regno_p (unsigned int regno
)
522 #undef TARGET_FUNCTION_VALUE
523 #define TARGET_FUNCTION_VALUE msp430_function_value
526 msp430_function_value (const_tree ret_type
,
527 const_tree fn_decl_or_type ATTRIBUTE_UNUSED
,
528 bool outgoing ATTRIBUTE_UNUSED
)
530 return gen_rtx_REG (TYPE_MODE (ret_type
), 12);
533 #undef TARGET_LIBCALL_VALUE
534 #define TARGET_LIBCALL_VALUE msp430_libcall_value
537 msp430_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
539 return gen_rtx_REG (mode
, 12);
542 /* Implements INIT_CUMULATIVE_ARGS. */
544 msp430_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
)
551 memset (ca
, 0, sizeof(*ca
));
556 fname
= IDENTIFIER_POINTER (DECL_NAME (fndecl
));
558 fname
= XSTR (libname
, 0);
562 if (fname
&& msp430_special_register_convention_p (fname
))
566 /* Helper function for argument passing; this function is the common
567 code that determines where an argument will be passed. */
569 msp430_evaluate_arg (cumulative_args_t cap
,
571 const_tree type ATTRIBUTE_UNUSED
,
574 CUMULATIVE_ARGS
*ca
= get_cumulative_args (cap
);
575 int nregs
= GET_MODE_SIZE (mode
);
587 nregs
= (nregs
+ 1) / 2;
591 /* Function is passed two DImode operands, in R8:R11 and
601 for (i
= 0; i
< 4; i
++)
602 if (! ca
->reg_used
[i
])
605 ca
->start_reg
= CA_FIRST_REG
+ i
;
610 for (i
= 0; i
< 3; i
++)
611 if (! ca
->reg_used
[i
] && ! ca
->reg_used
[i
+ 1])
614 ca
->start_reg
= CA_FIRST_REG
+ i
;
617 if (! ca
->reg_used
[3] && ca
->can_split
)
621 ca
->start_reg
= CA_FIRST_REG
+ 3;
628 if (! ca
->reg_used
[0]
629 && ! ca
->reg_used
[1]
630 && ! ca
->reg_used
[2]
631 && ! ca
->reg_used
[3])
634 ca
->start_reg
= CA_FIRST_REG
;
641 #undef TARGET_PROMOTE_PROTOTYPES
642 #define TARGET_PROMOTE_PROTOTYPES msp430_promote_prototypes
645 msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED
)
650 #undef TARGET_FUNCTION_ARG
651 #define TARGET_FUNCTION_ARG msp430_function_arg
654 msp430_function_arg (cumulative_args_t cap
,
659 CUMULATIVE_ARGS
*ca
= get_cumulative_args (cap
);
661 msp430_evaluate_arg (cap
, mode
, type
, named
);
664 return gen_rtx_REG (mode
, ca
->start_reg
);
669 #undef TARGET_ARG_PARTIAL_BYTES
670 #define TARGET_ARG_PARTIAL_BYTES msp430_arg_partial_bytes
673 msp430_arg_partial_bytes (cumulative_args_t cap
,
678 CUMULATIVE_ARGS
*ca
= get_cumulative_args (cap
);
680 msp430_evaluate_arg (cap
, mode
, type
, named
);
682 if (ca
->reg_count
&& ca
->mem_count
)
683 return ca
->reg_count
* UNITS_PER_WORD
;
688 #undef TARGET_PASS_BY_REFERENCE
689 #define TARGET_PASS_BY_REFERENCE msp430_pass_by_reference
692 msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED
,
695 bool named ATTRIBUTE_UNUSED
)
697 return (mode
== BLKmode
698 || (type
&& TREE_CODE (type
) == RECORD_TYPE
)
699 || (type
&& TREE_CODE (type
) == UNION_TYPE
));
702 #undef TARGET_CALLEE_COPIES
703 #define TARGET_CALLEE_COPIES msp430_callee_copies
706 msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED
,
707 machine_mode mode ATTRIBUTE_UNUSED
,
708 const_tree type ATTRIBUTE_UNUSED
,
709 bool named ATTRIBUTE_UNUSED
)
714 #undef TARGET_FUNCTION_ARG_ADVANCE
715 #define TARGET_FUNCTION_ARG_ADVANCE msp430_function_arg_advance
718 msp430_function_arg_advance (cumulative_args_t cap
,
723 CUMULATIVE_ARGS
*ca
= get_cumulative_args (cap
);
726 msp430_evaluate_arg (cap
, mode
, type
, named
);
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;
735 #undef TARGET_FUNCTION_ARG_BOUNDARY
736 #define TARGET_FUNCTION_ARG_BOUNDARY msp430_function_arg_boundary
739 msp430_function_arg_boundary (machine_mode mode
, const_tree type
)
742 && int_size_in_bytes (type
) > 1)
744 if (GET_MODE_BITSIZE (mode
) > 8)
749 #undef TARGET_RETURN_IN_MEMORY
750 #define TARGET_RETURN_IN_MEMORY msp430_return_in_memory
753 msp430_return_in_memory (const_tree ret_type
, const_tree fntype ATTRIBUTE_UNUSED
)
755 machine_mode mode
= TYPE_MODE (ret_type
);
758 || (fntype
&& TREE_CODE (TREE_TYPE (fntype
)) == RECORD_TYPE
)
759 || (fntype
&& TREE_CODE (TREE_TYPE (fntype
)) == UNION_TYPE
))
762 if (GET_MODE_SIZE (mode
) > 8)
768 #undef TARGET_GET_RAW_ARG_MODE
769 #define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode
772 msp430_get_raw_arg_mode (int regno
)
774 return (regno
== ARG_POINTER_REGNUM
) ? VOIDmode
: Pmode
;
777 #undef TARGET_GET_RAW_RESULT_MODE
778 #define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode
781 msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED
)
786 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
787 #define TARGET_GIMPLIFY_VA_ARG_EXPR msp430_gimplify_va_arg_expr
789 #include "gimplify.h"
790 #include "gimple-expr.h"
793 msp430_gimplify_va_arg_expr (tree valist
, tree type
, gimple_seq
*pre_p
,
796 tree addr
, t
, type_size
, rounded_size
, valist_tmp
;
797 unsigned HOST_WIDE_INT align
, boundary
;
800 indirect
= pass_by_reference (NULL
, TYPE_MODE (type
), type
, false);
802 type
= build_pointer_type (type
);
804 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
805 boundary
= targetm
.calls
.function_arg_boundary (TYPE_MODE (type
), type
);
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
811 if (boundary
> MAX_SUPPORTED_STACK_ALIGNMENT
)
812 boundary
= MAX_SUPPORTED_STACK_ALIGNMENT
;
814 boundary
/= BITS_PER_UNIT
;
816 /* Hoist the valist value into a temporary for the moment. */
817 valist_tmp
= get_initialized_tmp_var (valist
, pre_p
, NULL
);
819 /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
820 requires greater alignment, we must perform dynamic alignment. */
822 && !integer_zerop (TYPE_SIZE (type
)))
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
))
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
);
832 t
= build2 (MODIFY_EXPR
, TREE_TYPE (valist
), valist_tmp
,
833 fold_build2 (BIT_AND_EXPR
, TREE_TYPE (valist
),
835 build_int_cst (TREE_TYPE (valist
), -boundary
)));
836 gimplify_and_add (t
, pre_p
);
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
))
848 type
= build_variant_type_copy (type
);
849 TYPE_ALIGN (type
) = boundary
;
852 /* Compute the rounded size of the type. */
853 type_size
= size_in_bytes (type
);
854 rounded_size
= round_up (type_size
, align
);
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
);
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
);
867 addr
= fold_convert (build_pointer_type (type
), addr
);
870 addr
= build_va_arg_indirect_ref (addr
);
872 addr
= build_va_arg_indirect_ref (addr
);
877 /* Addressing Modes */
879 #undef TARGET_LEGITIMATE_ADDRESS_P
880 #define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p
883 reg_ok_for_addr (rtx r
, bool strict
)
887 if (strict
&& rn
>= FIRST_PSEUDO_REGISTER
)
888 rn
= reg_renumber
[rn
];
889 if (strict
&& 0 <= rn
&& rn
< FIRST_PSEUDO_REGISTER
)
897 msp430_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED
,
898 rtx x ATTRIBUTE_UNUSED
,
899 bool strict ATTRIBUTE_UNUSED
)
901 switch (GET_CODE (x
))
907 if (REG_P (XEXP (x
, 0)))
909 if (GET_MODE (x
) != GET_MODE (XEXP (x
, 0)))
911 if (!reg_ok_for_addr (XEXP (x
, 0), strict
))
913 switch (GET_CODE (XEXP (x
, 1)))
926 if (!reg_ok_for_addr (x
, strict
))
939 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
940 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P msp430_addr_space_legitimate_address_p
943 msp430_addr_space_legitimate_address_p (machine_mode mode
,
946 addr_space_t as ATTRIBUTE_UNUSED
)
948 return msp430_legitimate_address_p (mode
, x
, strict
);
951 #undef TARGET_ASM_INTEGER
952 #define TARGET_ASM_INTEGER msp430_asm_integer
954 msp430_asm_integer (rtx x
, unsigned int size
, int aligned_p
)
956 int c
= GET_CODE (x
);
958 if (size
== 3 && GET_MODE (x
) == PSImode
)
964 if (c
== SYMBOL_REF
|| c
== CONST
|| c
== LABEL_REF
|| c
== CONST_INT
)
966 fprintf (asm_out_file
, "\t.long\t");
967 output_addr_const (asm_out_file
, x
);
968 fputc ('\n', asm_out_file
);
973 return default_assemble_integer (x
, size
, aligned_p
);
976 #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
977 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA msp430_asm_output_addr_const_extra
979 msp430_asm_output_addr_const_extra (FILE *file ATTRIBUTE_UNUSED
, rtx x
)
985 #undef TARGET_LEGITIMATE_CONSTANT_P
986 #define TARGET_LEGITIMATE_CONSTANT_P msp430_legitimate_constant
989 msp430_legitimate_constant (machine_mode mode
, rtx x
)
991 return ! CONST_INT_P (x
)
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
996 || (INTVAL (x
) < (1 << 20) && INTVAL (x
) >= (-1 << 20));
1000 #undef TARGET_RTX_COSTS
1001 #define TARGET_RTX_COSTS msp430_rtx_costs
1003 static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED
,
1005 int outer_code ATTRIBUTE_UNUSED
,
1006 int opno ATTRIBUTE_UNUSED
,
1008 bool speed ATTRIBUTE_UNUSED
)
1013 if (GET_MODE (x
) == SImode
&& outer_code
== SET
)
1015 *total
= COSTS_N_INSNS (4);
1024 *total
= COSTS_N_INSNS (100);
1032 /* Function Entry and Exit */
1034 /* The MSP430 call frame looks like this:
1037 +--------------------+
1041 +--------------------+ <-- "arg pointer"
1043 | PC from call | (2 bytes for 430, 4 for TARGET_LARGE)
1045 +--------------------+
1046 | SR if this func has|
1047 | been called via an |
1049 +--------------------+ <-- SP before prologue, also AP
1051 | Saved Regs | (2 bytes per reg for 430, 4 per for TARGET_LARGE)
1053 +--------------------+ <-- "frame pointer"
1057 +--------------------+
1061 +--------------------+ <-- SP during function
1066 /* We use this to wrap all emitted insns in the prologue, so they get
1067 the "frame-related" (/f) flag set. */
1071 RTX_FRAME_RELATED_P (x
) = 1;
1075 /* This is the one spot that decides if a register is to be saved and
1076 restored in the prologue/epilogue. */
1078 msp430_preserve_reg_p (int regno
)
1080 /* PC, SP, SR, and the constant generator. */
1084 /* FIXME: add interrupt, EH, etc. */
1085 if (crtl
->calls_eh_return
)
1088 /* Shouldn't be more than the above, but just in case... */
1089 if (fixed_regs
[regno
])
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
);
1098 if (!call_used_regs
[regno
]
1099 && df_regs_ever_live_p (regno
))
1105 /* Compute all the frame-related fields in our machine_function
1108 msp430_compute_frame_info (void)
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
;
1117 for (i
= 0; i
< ARG_POINTER_REGNUM
; i
++)
1118 if (msp430_preserve_reg_p (i
))
1120 cfun
->machine
->need_to_save
[i
] = 1;
1121 cfun
->machine
->framesize_regs
+= (TARGET_LARGE
? 4 : 2);
1124 cfun
->machine
->need_to_save
[i
] = 0;
1126 if ((cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
) & 1)
1127 cfun
->machine
->framesize_locals
++;
1129 cfun
->machine
->framesize
= (cfun
->machine
->framesize_regs
1130 + cfun
->machine
->framesize_locals
1131 + cfun
->machine
->framesize_outgoing
);
1135 is_attr_func (const char * attr
)
1137 return lookup_attribute (attr
, DECL_ATTRIBUTES (current_function_decl
)) != NULL_TREE
;
1140 /* Returns true if the current function has the "interrupt" attribute. */
1143 msp430_is_interrupt_func (void)
1145 if (current_function_decl
== NULL
)
1147 return is_attr_func ("interrupt");
1151 is_wakeup_func (void)
1153 return msp430_is_interrupt_func () && is_attr_func ("wakeup");
1157 is_naked_func (void)
1159 return is_attr_func ("naked");
1163 is_reentrant_func (void)
1165 return is_attr_func ("reentrant");
1169 is_critical_func (void)
1171 return is_attr_func ("critical");
1174 #undef TARGET_ASM_FUNCTION_PROLOGUE
1175 #define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function
1178 msp430_start_function (FILE *outfile
, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED
)
1182 fprintf (outfile
, "; start of function\n");
1184 if (DECL_ATTRIBUTES (current_function_decl
) != NULL_TREE
)
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 ");
1195 if (is_wakeup_func ())
1196 fprintf (outfile
, "wakeup ");
1197 fprintf (outfile
, "\n");
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
));
1208 fprintf (outfile
, "; saved regs:");
1209 for (r
= 0; r
< ARG_POINTER_REGNUM
; r
++)
1210 if (cfun
->machine
->need_to_save
[r
])
1212 fprintf (outfile
, " %s", reg_names
[r
]);
1216 fprintf (outfile
, "(none)");
1217 fprintf (outfile
, "\n");
1220 /* Common code to change the stack pointer. */
1222 increment_stack (HOST_WIDE_INT amount
)
1225 rtx sp
= stack_pointer_rtx
;
1232 inc
= GEN_INT (- amount
);
1234 F (emit_insn (gen_subpsi3 (sp
, sp
, inc
)));
1236 F (emit_insn (gen_subhi3 (sp
, sp
, inc
)));
1240 inc
= GEN_INT (amount
);
1242 emit_insn (gen_addpsi3 (sp
, sp
, inc
));
1244 emit_insn (gen_addhi3 (sp
, sp
, inc
));
1248 /* Verify MSP430 specific attributes. */
1251 msp430_attr (tree
* node
,
1254 int flags ATTRIBUTE_UNUSED
,
1255 bool * no_add_attrs
)
1257 gcc_assert (DECL_P (* node
));
1261 tree value
= TREE_VALUE (args
);
1263 switch (TREE_CODE (value
))
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",
1277 if (wi::gtu_p (value
, 63))
1278 /* Allow the attribute to be added - the linker script
1279 being used may still recognise this value. */
1280 warning (OPT_Wattributes
,
1281 "numeric argument of %qE attribute must be in range 0..63",
1286 warning (OPT_Wattributes
,
1287 "argument of %qE attribute is not a string constant or number",
1289 *no_add_attrs
= true;
1294 if (TREE_CODE (* node
) != FUNCTION_DECL
)
1296 warning (OPT_Wattributes
,
1297 "%qE attribute only applies to functions",
1299 * no_add_attrs
= true;
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. */
1311 #undef TARGET_ATTRIBUTE_TABLE
1312 #define TARGET_ATTRIBUTE_TABLE msp430_attribute_table
1314 /* Table of MSP430-specific attributes. */
1315 const struct attribute_spec msp430_attribute_table
[] =
1317 /* Name min_len decl_req, fn_type_req, affects_type_identity
1318 max_len, type_req, decl_handler, type_handler. */
1319 { "interrupt", 0, 1, true, false, false, msp430_attr
, NULL
, false },
1320 { "naked", 0, 0, true, false, false, msp430_attr
, NULL
, false },
1321 { "reentrant", 0, 0, true, false, false, msp430_attr
, NULL
, false },
1322 { "critical", 0, 0, true, false, false, msp430_attr
, NULL
, false },
1323 { "wakeup", 0, 0, true, false, false, msp430_attr
, NULL
, false },
1324 { NULL
, 0, 0, false, false, false, NULL
, NULL
, false }
1328 msp430_start_function (FILE *file
, const char *name
, tree decl
)
1332 int_attr
= lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl
));
1333 if (int_attr
!= NULL_TREE
)
1335 tree intr_vector
= TREE_VALUE (int_attr
);
1337 if (intr_vector
!= NULL_TREE
)
1341 intr_vector
= TREE_VALUE (intr_vector
);
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
));
1354 switch_to_section (get_section (buf
, SECTION_CODE
, decl
));
1355 fputs ("\t.word\t", file
);
1356 assemble_name (file
, name
);
1362 switch_to_section (function_section (decl
));
1363 ASM_OUTPUT_FUNCTION_LABEL (file
, name
, decl
);
1367 msp430_function_section (tree decl
, enum node_frequency freq
, bool startup
, bool exit
)
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. */
1372 && lookup_attribute ("interrupt", DECL_ATTRIBUTES (decl
)))
1373 return get_section (".lowtext", SECTION_CODE
| SECTION_WRITE
, decl
);
1375 /* Otherwise, use the default function section. */
1376 return default_function_section (decl
, freq
, startup
, exit
);
1379 #undef TARGET_ASM_FUNCTION_SECTION
1380 #define TARGET_ASM_FUNCTION_SECTION msp430_function_section
1384 MSP430_BUILTIN_BIC_SR
,
1385 MSP430_BUILTIN_BIS_SR
,
1386 MSP430_BUILTIN_DELAY_CYCLES
,
1390 static GTY(()) tree msp430_builtins
[(int) MSP430_BUILTIN_max
];
1393 msp430_init_builtins (void)
1395 tree void_ftype_int
= build_function_type_list (void_type_node
, integer_type_node
, NULL
);
1396 tree void_ftype_longlong
= build_function_type_list (void_type_node
, long_long_integer_type_node
, NULL
);
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
);
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
);
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
);
1412 msp430_builtin_decl (unsigned code
, bool initialize ATTRIBUTE_UNUSED
)
1416 case MSP430_BUILTIN_BIC_SR
:
1417 case MSP430_BUILTIN_BIS_SR
:
1418 case MSP430_BUILTIN_DELAY_CYCLES
:
1419 return msp430_builtins
[code
];
1421 return error_mark_node
;
1425 /* These constants are really register reads, which are faster than
1426 regular constants. */
1428 cg_magic_constant (HOST_WIDE_INT c
)
1446 msp430_expand_delay_cycles (rtx arg
)
1448 HOST_WIDE_INT i
, c
, n
;
1449 /* extra cycles for MSP430X instructions */
1450 #define CYCX(M,X) (msp430x ? (X) : (M))
1452 if (GET_CODE (arg
) != CONST_INT
)
1454 error ("__delay_cycles() only takes constant arguments");
1460 if (HOST_BITS_PER_WIDE_INT
> 32)
1464 error ("__delay_cycles only takes non-negative cycle counts.");
1469 emit_insn (gen_delay_cycles_start (arg
));
1471 /* For 32-bit loops, there's 13(16) + 5(min(x,0x10000) + 6x cycles. */
1472 if (c
> 3 * 0xffff + CYCX (7, 10))
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))
1479 c
-= CYCX (14, 16) + 7 * 0x10000;
1482 if ((unsigned long long) i
> 0xffffffffULL
)
1484 error ("__delay_cycles is limited to 32-bit loop counts.");
1490 i
= (c
- CYCX (14, 16)) / 7;
1491 c
-= CYCX (14, 16) + i
* 7;
1494 if (cg_magic_constant (i
& 0xffff))
1496 if (cg_magic_constant ((i
>> 16) & 0xffff))
1500 emit_insn (gen_delay_cycles_32x (GEN_INT (i
), GEN_INT (n
- c
)));
1502 emit_insn (gen_delay_cycles_32 (GEN_INT (i
), GEN_INT (n
- c
)));
1505 /* For 16-bit loops, there's 7(10) + 3x cycles - so the max cycles is 0x30004(7). */
1509 i
= (c
- CYCX (7, 10)) / 3;
1510 c
-= CYCX (7, 10) + i
* 3;
1512 if (cg_magic_constant (i
))
1516 emit_insn (gen_delay_cycles_16x (GEN_INT (i
), GEN_INT (n
- c
)));
1518 emit_insn (gen_delay_cycles_16 (GEN_INT (i
), GEN_INT (n
- c
)));
1523 emit_insn (gen_delay_cycles_2 ());
1529 emit_insn (gen_delay_cycles_1 ());
1533 emit_insn (gen_delay_cycles_end (arg
));
1539 msp430_expand_builtin (tree exp
,
1540 rtx target ATTRIBUTE_UNUSED
,
1541 rtx subtarget ATTRIBUTE_UNUSED
,
1542 machine_mode mode ATTRIBUTE_UNUSED
,
1543 int ignore ATTRIBUTE_UNUSED
)
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));
1549 if (fcode
== MSP430_BUILTIN_DELAY_CYCLES
)
1550 return msp430_expand_delay_cycles (arg1
);
1552 if (! msp430_is_interrupt_func ())
1554 error ("MSP430 builtin functions only work inside interrupt handlers");
1558 if (! REG_P (arg1
) && ! CONSTANT_P (arg1
))
1559 arg1
= force_reg (mode
, arg1
);
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;
1566 internal_error ("bad builtin code");
1572 #undef TARGET_INIT_BUILTINS
1573 #define TARGET_INIT_BUILTINS msp430_init_builtins
1575 #undef TARGET_EXPAND_BUILTIN
1576 #define TARGET_EXPAND_BUILTIN msp430_expand_builtin
1578 #undef TARGET_BUILTIN_DECL
1579 #define TARGET_BUILTIN_DECL msp430_builtin_decl
1582 msp430_expand_prologue (void)
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
;
1593 if (is_naked_func ())
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)));
1601 emit_insn (gen_prologue_start_marker ());
1603 if (is_critical_func ())
1605 emit_insn (gen_push_intr_state ());
1606 emit_insn (gen_disable_interrupts ());
1608 else if (is_reentrant_func ())
1609 emit_insn (gen_disable_interrupts ());
1611 if (!cfun
->machine
->computed
)
1612 msp430_compute_frame_info ();
1614 if (flag_stack_usage_info
)
1615 current_function_static_stack_size
= cfun
->machine
->framesize
;
1617 if (crtl
->args
.pretend_args_size
)
1621 gcc_assert (crtl
->args
.pretend_args_size
== 2);
1623 p
= emit_insn (gen_grow_and_swap ());
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
);
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))),
1634 add_reg_note (p
, REG_CFA_OFFSET
, note
);
1638 for (i
= 15; i
>= 4; i
--)
1639 if (cfun
->machine
->need_to_save
[i
])
1644 for (seq
= i
- 1; seq
>= 4 && cfun
->machine
->need_to_save
[seq
]; seq
--)
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
),
1654 note
= gen_rtx_SEQUENCE (VOIDmode
, rtvec_alloc (count
+ 1));
1656 XVECEXP (note
, 0, 0)
1657 = F (gen_rtx_SET (VOIDmode
,
1659 gen_rtx_PLUS (Pmode
,
1661 GEN_INT (count
* (TARGET_LARGE
? -4 : -2)))));
1663 /* *sp-- = R[i-j] */
1667 for (j
= 0; j
< count
; j
++)
1670 int ofs
= (count
- j
- 1) * (TARGET_LARGE
? 4 : 2);
1673 addr
= gen_rtx_PLUS (Pmode
, sp
, GEN_INT (ofs
));
1675 addr
= stack_pointer_rtx
;
1677 XVECEXP (note
, 0, j
+ 1) =
1678 F (gen_rtx_SET (VOIDmode
,
1679 gen_rtx_MEM (Pmode
, addr
),
1680 gen_rtx_REG (Pmode
, i
- j
)) );
1683 add_reg_note (p
, REG_FRAME_RELATED_EXPR
, note
);
1687 F (emit_insn (gen_push (gen_rtx_REG (Pmode
, i
))));
1690 if (frame_pointer_needed
)
1691 F (emit_move_insn (gen_rtx_REG (Pmode
, FRAME_POINTER_REGNUM
), sp
));
1693 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1695 increment_stack (- fs
);
1697 emit_insn (gen_prologue_end_marker ());
1701 msp430_expand_epilogue (int is_eh
)
1707 if (is_naked_func ())
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)));
1715 if (cfun
->machine
->need_to_save
[10])
1717 /* Check for a helper function. */
1718 helper_n
= 7; /* For when the loop below never sees a match. */
1719 for (i
= 9; i
>= 4; i
--)
1720 if (!cfun
->machine
->need_to_save
[i
])
1724 if (cfun
->machine
->need_to_save
[i
])
1733 emit_insn (gen_epilogue_start_marker ());
1735 if (cfun
->decl
&& strcmp (IDENTIFIER_POINTER (DECL_NAME (cfun
->decl
)), "main") == 0)
1736 emit_insn (gen_msp430_refsym_need_exit ());
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)));
1746 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1748 increment_stack (fs
);
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
;
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
);
1767 for (i
= 4; i
<= 15; i
++)
1768 if (cfun
->machine
->need_to_save
[i
])
1772 for (seq
= i
+ 1; seq
<= 15 && cfun
->machine
->need_to_save
[seq
]; seq
++)
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),
1784 else if (i
== 11 - helper_n
1785 && ! msp430_is_interrupt_func ()
1786 && ! is_reentrant_func ()
1787 && ! is_critical_func ()
1788 && crtl
->args
.pretend_args_size
== 0
1789 /* Calling the helper takes as many bytes as the POP;RET sequence. */
1793 emit_insn (gen_epilogue_helper (GEN_INT (helper_n
)));
1797 emit_insn (gen_pop (gen_rtx_REG (Pmode
, i
)));
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
1805 emit_move_insn (stack_pointer_rtx
, gen_rtx_MEM (Pmode
, stack_pointer_rtx
));
1808 if (crtl
->args
.pretend_args_size
)
1809 emit_insn (gen_swap_and_shrink ());
1811 if (is_critical_func ())
1812 emit_insn (gen_pop_intr_state ());
1813 else if (is_reentrant_func ())
1814 emit_insn (gen_enable_interrupts ());
1816 emit_jump_insn (gen_msp_return ());
1819 /* Implements EH_RETURN_STACKADJ_RTX. Saved and used later in
1820 m32c_emit_eh_epilogue. */
1822 msp430_eh_return_stackadj_rtx (void)
1824 if (!cfun
->machine
->eh_stack_adjust
)
1828 sa
= gen_rtx_REG (Pmode
, 15);
1829 cfun
->machine
->eh_stack_adjust
= sa
;
1831 return cfun
->machine
->eh_stack_adjust
;
1834 /* This function is called before reload, to "fix" the stack in
1835 preparation for an EH return. */
1837 msp430_expand_eh_return (rtx eh_handler
)
1839 /* These are all Pmode */
1840 rtx ap
, sa
, ra
, tmp
;
1842 ap
= arg_pointer_rtx
;
1843 sa
= msp430_eh_return_stackadj_rtx ();
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
);
1853 #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
1854 #define TARGET_INIT_DWARF_REG_SIZES_EXTRA msp430_init_dwarf_reg_sizes_extra
1856 msp430_init_dwarf_reg_sizes_extra (tree address
)
1859 rtx addr
= expand_normal (address
);
1860 rtx mem
= gen_rtx_MEM (BLKmode
, addr
);
1865 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1867 unsigned int dnum
= DWARF_FRAME_REGNUM (i
);
1868 unsigned int rnum
= DWARF2_FRAME_REG_OUT (dnum
, 1);
1870 if (rnum
< DWARF_FRAME_REGISTERS
)
1872 HOST_WIDE_INT offset
= rnum
* GET_MODE_SIZE (QImode
);
1874 emit_move_insn (adjust_address (mem
, QImode
, offset
),
1875 gen_int_mode (4, QImode
));
1880 /* This is a list of MD patterns that implement fixed-count shifts. */
1886 rtx (*genfunc
)(rtx
,rtx
);
1888 const_shift_helpers
[] =
1890 #define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G }
1892 CSH ("slli", 1, 1, slli_1
),
1893 CSH ("slll", 1, 1, slll_1
),
1894 CSH ("slll", 2, 1, slll_2
),
1896 CSH ("srai", 1, 0, srai_1
),
1897 CSH ("sral", 1, 0, sral_1
),
1898 CSH ("sral", 2, 0, sral_2
),
1900 CSH ("srll", 1, 0, srll_1
),
1901 CSH ("srll", 2, 1, srll_2x
),
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
1911 msp430_expand_helper (rtx
*operands
, const char *helper_name
, bool const_variants
)
1914 char *helper_const
= NULL
;
1917 machine_mode arg0mode
= GET_MODE (operands
[0]);
1918 machine_mode arg1mode
= GET_MODE (operands
[1]);
1919 machine_mode arg2mode
= GET_MODE (operands
[2]);
1920 int have_430x
= msp430x
? 1 : 0;
1922 if (CONST_INT_P (operands
[2]))
1926 for (i
=0; const_shift_helpers
[i
].name
; i
++)
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
)
1932 emit_insn (const_shift_helpers
[i
].genfunc (operands
[0], operands
[1]));
1938 if (arg1mode
== VOIDmode
)
1939 arg1mode
= arg0mode
;
1940 if (arg2mode
== VOIDmode
)
1941 arg2mode
= arg0mode
;
1943 if (arg1mode
== SImode
)
1950 && CONST_INT_P (operands
[2])
1951 && INTVAL (operands
[2]) >= 1
1952 && INTVAL (operands
[2]) <= 15)
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
);
1957 snprintf (helper_const
, len
, "%s_%d", helper_name
, (int) INTVAL (operands
[2]));
1960 emit_move_insn (gen_rtx_REG (arg1mode
, 12),
1963 emit_move_insn (gen_rtx_REG (arg2mode
, arg2
),
1966 c
= gen_call_value_internal (gen_rtx_REG (arg0mode
, 12),
1967 gen_rtx_SYMBOL_REF (VOIDmode
, helper_const
? helper_const
: helper_name
),
1969 c
= emit_call_insn (c
);
1970 RTL_CONST_CALL_P (c
) = 1;
1973 use_regs (&f
, 12, arg1sz
);
1975 use_regs (&f
, arg2
, 1);
1976 add_function_usage_to (c
, f
);
1978 emit_move_insn (operands
[0],
1979 gen_rtx_REG (arg0mode
, 12));
1982 /* Called by cbranch<mode>4 to coerce operands into usable forms. */
1984 msp430_fixup_compare_operands (machine_mode my_mode
, rtx
* operands
)
1986 /* constants we're looking for, not constants which are allowed. */
1987 int const_op_idx
= 1;
1989 if (msp430_reversible_cmp_operator (operands
[0], VOIDmode
))
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
]);
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. */
2001 msp430_subreg (machine_mode mode
, rtx r
, machine_mode omode
, int byte
)
2005 if (GET_CODE (r
) == SUBREG
2006 && SUBREG_BYTE (r
) == 0)
2008 rtx ireg
= SUBREG_REG (r
);
2009 machine_mode imode
= GET_MODE (ireg
);
2011 /* special case for (HI (SI (PSI ...), 0)) */
2012 if (imode
== PSImode
2015 rv
= gen_rtx_SUBREG (mode
, ireg
, byte
);
2017 rv
= simplify_gen_subreg (mode
, ireg
, imode
, byte
);
2019 else if (GET_CODE (r
) == MEM
)
2020 rv
= adjust_address (r
, mode
, byte
);
2022 rv
= simplify_gen_subreg (mode
, r
, omode
, byte
);
2030 /* Called by movsi_x to generate the HImode operands. */
2032 msp430_split_movsi (rtx
*operands
)
2034 rtx op00
, op02
, op10
, op12
;
2036 op00
= msp430_subreg (HImode
, operands
[0], SImode
, 0);
2037 op02
= msp430_subreg (HImode
, operands
[0], SImode
, 2);
2039 if (GET_CODE (operands
[1]) == CONST
2040 || GET_CODE (operands
[1]) == SYMBOL_REF
)
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
);
2049 op10
= msp430_subreg (HImode
, operands
[1], SImode
, 0);
2050 op12
= msp430_subreg (HImode
, operands
[1], SImode
, 2);
2053 if (rtx_equal_p (operands
[0], operands
[1]))
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
))
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. */
2087 char const * const gcc_name
;
2088 char const * const ti_name
;
2090 helper_function_name_mappings
[] =
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" },
2120 /* Floating point comparisons. */
2121 /* GCC uses individual functions for each comparison, TI uses one
2122 compare <=> function. */
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 */
2135 /* Integer multiply, divide, remainder. */
2136 { "__mulhi3", "__mspabi_mpyi" },
2137 { "__mulsi3", "__mspabi_mpyl" },
2138 { "__muldi3", "__mspabi_mpyll" },
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?) */
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" },
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. */
2167 /* Returns true if the current MCU supports an F5xxx series
2168 hardware multiper. */
2171 msp430_use_f5_series_hwmult (void)
2173 static const char * cached_match
= NULL
;
2174 static bool cached_result
;
2176 if (msp430_hwmult_type
== F5SERIES
)
2179 if (target_mcu
== NULL
|| msp430_hwmult_type
!= AUTO
)
2182 if (target_mcu
== cached_match
)
2183 return cached_result
;
2185 cached_match
= target_mcu
;
2187 if (strncasecmp (target_mcu
, "msp430f5", 8) == 0)
2188 return cached_result
= true;
2190 static const char * known_f5_mult_mcus
[] =
2192 "cc430f5123", "cc430f5125", "cc430f5133",
2193 "cc430f5135", "cc430f5137", "cc430f5143",
2194 "cc430f5145", "cc430f5147", "cc430f6125",
2195 "cc430f6126", "cc430f6127", "cc430f6135",
2196 "cc430f6137", "cc430f6143", "cc430f6145",
2197 "cc430f6147", "msp430bt5190", "msp430sl5438a"
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;
2205 return cached_result
= false;
2208 /* Returns true if the current MCU has a second generation
2209 32-bit hardware multiplier. */
2212 use_32bit_hwmult (void)
2214 static const char * known_32bit_mult_mcus
[] =
2216 "msp430f4783", "msp430f4793", "msp430f4784",
2217 "msp430f4794", "msp430f47126", "msp430f47127",
2218 "msp430f47163", "msp430f47173", "msp430f47183",
2219 "msp430f47193", "msp430f47166", "msp430f47176",
2220 "msp430f47186", "msp430f47196", "msp430f47167",
2221 "msp430f47177", "msp430f47187", "msp430f47197"
2223 static const char * cached_match
= NULL
;
2224 static bool cached_result
;
2227 if (msp430_hwmult_type
== LARGE
)
2230 if (target_mcu
== NULL
|| msp430_hwmult_type
!= AUTO
)
2233 if (target_mcu
== cached_match
)
2234 return cached_result
;
2236 cached_match
= target_mcu
;
2237 for (i
= ARRAY_SIZE (known_32bit_mult_mcus
); i
--;)
2238 if (strcasecmp (target_mcu
, known_32bit_mult_mcus
[i
]) == 0)
2239 return cached_result
= true;
2241 return cached_result
= false;
2244 /* Returns true if the current MCU does not have a
2245 hardware multiplier of any kind. */
2248 msp430_no_hwmult (void)
2250 static const char * known_nomult_mcus
[] =
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"
2308 static const char * cached_match
= NULL
;
2309 static bool cached_result
;
2312 if (msp430_hwmult_type
== NONE
)
2315 if (target_mcu
== NULL
|| msp430_hwmult_type
!= AUTO
)
2318 if (target_mcu
== cached_match
)
2319 return cached_result
;
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;
2326 return cached_result
= false;
2329 /* This function does the same as the default, but it will replace GCC
2330 function names with the MSPABI-specified ones. */
2333 msp430_output_labelref (FILE *file
, const char *name
)
2337 for (i
= 0; helper_function_name_mappings
[i
].gcc_name
; i
++)
2338 if (strcmp (helper_function_name_mappings
[i
].gcc_name
, name
) == 0)
2340 name
= helper_function_name_mappings
[i
].ti_name
;
2344 /* If we have been given a specific MCU name then we may be
2345 able to make use of its hardware multiply capabilities. */
2346 if (msp430_hwmult_type
!= NONE
)
2348 if (strcmp ("__mspabi_mpyi", name
) == 0)
2350 if (msp430_use_f5_series_hwmult ())
2351 name
= "__mulhi2_f5";
2352 else if (! msp430_no_hwmult ())
2355 else if (strcmp ("__mspabi_mpyl", name
) == 0)
2357 if (msp430_use_f5_series_hwmult ())
2358 name
= "__mulsi2_f5";
2359 else if (use_32bit_hwmult ())
2360 name
= "__mulsi2_hw32";
2361 else if (! msp430_no_hwmult ())
2369 /* Common code for msp430_print_operand... */
2372 msp430_print_operand_raw (FILE * file
, rtx op
)
2376 switch (GET_CODE (op
))
2379 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
2385 fprintf (file
, "%#" HOST_WIDE_INT_PRINT
"x", i
);
2387 fprintf (file
, "%" HOST_WIDE_INT_PRINT
"d", i
);
2395 output_addr_const (file
, op
);
2399 print_rtl (file
, op
);
2404 #undef TARGET_PRINT_OPERAND_ADDRESS
2405 #define TARGET_PRINT_OPERAND_ADDRESS msp430_print_operand_addr
2407 /* Output to stdio stream FILE the assembler syntax for an
2408 instruction operand that is a memory reference whose address
2412 msp430_print_operand_addr (FILE * file
, rtx addr
)
2414 switch (GET_CODE (addr
))
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))]);
2423 fprintf (file
, "@");
2430 fprintf (file
, "&");
2437 msp430_print_operand_raw (file
, addr
);
2440 #undef TARGET_PRINT_OPERAND
2441 #define TARGET_PRINT_OPERAND msp430_print_operand
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)
2449 J an integer without a # prefix
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
2457 b .B or .W or .A, depending upon the mode
2459 r inverse of condition code
2460 x like X but only for pointers. */
2463 msp430_print_operand (FILE * file
, rtx op
, int letter
)
2467 /* We can't use c, n, a, or l. */
2471 gcc_assert (CONST_INT_P (op
));
2472 /* Print the constant value, less one. */
2473 fprintf (file
, "#%ld", INTVAL (op
) - 1);
2476 gcc_assert (CONST_INT_P (op
));
2477 /* Print the constant value, less four. */
2478 fprintf (file
, "#%ld", INTVAL (op
) - 4);
2481 if (GET_CODE (op
) == CONST_INT
)
2483 /* Inverse of constants */
2484 int i
= INTVAL (op
);
2485 fprintf (file
, "%d", ~i
);
2490 case 'r': /* Conditional jump where the condition is reversed. */
2491 switch (GET_CODE (op
))
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;
2505 msp430_print_operand_raw (file
, op
);
2509 case 'R': /* Conditional jump where the operands are reversed. */
2510 switch (GET_CODE (op
))
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;
2517 msp430_print_operand_raw (file
, op
);
2521 case 'p': /* Bit position. 0 == 0x01, 3 = 0x08 etc. */
2522 gcc_assert (CONST_INT_P (op
));
2523 fprintf (file
, "#%d", 1 << INTVAL (op
));
2526 switch (GET_MODE (op
))
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;
2536 case 'L': /* Low half. */
2537 switch (GET_CODE (op
))
2540 op
= adjust_address (op
, Pmode
, 0);
2545 op
= GEN_INT (INTVAL (op
) & 0xffff);
2549 /* If you get here, figure out a test case :-) */
2554 case 'H': /* high half */
2555 switch (GET_CODE (op
))
2558 op
= adjust_address (op
, Pmode
, 2);
2561 op
= gen_rtx_REG (Pmode
, REGNO (op
) + 1);
2564 op
= GEN_INT (INTVAL (op
) >> 16);
2568 /* If you get here, figure out a test case :-) */
2573 switch (GET_CODE (op
))
2576 op
= adjust_address (op
, Pmode
, 3);
2579 op
= gen_rtx_REG (Pmode
, REGNO (op
) + 2);
2582 op
= GEN_INT ((long long) INTVAL (op
) >> 32);
2586 /* If you get here, figure out a test case :-) */
2591 switch (GET_CODE (op
))
2594 op
= adjust_address (op
, Pmode
, 4);
2597 op
= gen_rtx_REG (Pmode
, REGNO (op
) + 3);
2600 op
= GEN_INT ((long long) INTVAL (op
) >> 48);
2604 /* If you get here, figure out a test case :-) */
2610 /* This is used to turn, for example, an ADD opcode into an ADDX
2611 opcode when we're using 20-bit addresses. */
2612 if (TARGET_LARGE
|| GET_MODE (op
) == PSImode
)
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. */
2619 /* Similarly, but only for PSImodes. BIC, for example, needs this. */
2620 if (GET_MODE (op
) == PSImode
)
2621 fprintf (file
, "X");
2625 /* Likewise, for BR -> BRA. */
2627 fprintf (file
, "A");
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
)
2636 - (TARGET_LARGE
? 4 : 2));
2640 gcc_assert (GET_CODE (op
) == CONST_INT
);
2644 output_operand_lossage ("invalid operand prefix");
2648 switch (GET_CODE (op
))
2651 msp430_print_operand_raw (file
, op
);
2655 addr
= XEXP (op
, 0);
2656 msp430_print_operand_addr (file
, addr
);
2660 if (GET_CODE (XEXP (op
, 0)) == ZERO_EXTRACT
)
2663 switch (INTVAL (XEXP (op
, 2)))
2666 fprintf (file
, "#lo (");
2667 msp430_print_operand_raw (file
, XEXP (op
, 0));
2668 fprintf (file
, ")");
2672 fprintf (file
, "#hi (");
2673 msp430_print_operand_raw (file
, XEXP (op
, 0));
2674 fprintf (file
, ")");
2678 output_operand_lossage ("invalid zero extract");
2688 fprintf (file
, "#");
2689 msp430_print_operand_raw (file
, op
);
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;
2700 print_rtl (file
, op
);
2709 msp430_return_addr_rtx (int count
)
2715 ra_size
= TARGET_LARGE
? 4 : 2;
2716 if (crtl
->args
.pretend_args_size
)
2719 return gen_rtx_MEM (Pmode
, gen_rtx_PLUS (Pmode
, arg_pointer_rtx
, GEN_INT (- ra_size
)));
2723 msp430_incoming_return_addr_rtx (void)
2725 return gen_rtx_MEM (Pmode
, stack_pointer_rtx
);
2728 /* Instruction generation stuff. */
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. */
2735 msp430x_extendhisi (rtx
* operands
)
2737 if (REGNO (operands
[0]) == REGNO (operands
[1]))
2738 /* Low word of dest == source word. */
2739 return "BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; /* 8-bytes. */
2742 /* Note: This sequence is approximately the same length as invoking a helper
2743 function to perform the sign-extension, as in:
2747 CALL __mspabi_srai_15
2750 but this version does not involve any function calls or using argument
2751 registers, so it reduces register pressure. */
2752 return "MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; /* 10-bytes. */
2754 if (REGNO (operands
[0]) + 1 == REGNO (operands
[1]))
2755 /* High word of dest == source word. */
2756 return "MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0"; /* 6-bytes. */
2758 /* No overlap between dest and source. */
2759 return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; /* 8-bytes. */
2762 /* Likewise for logical right shifts. */
2764 msp430x_logical_shift_right (rtx amount
)
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
));
2772 if (INTVAL (amount
) <= 0
2773 || INTVAL (amount
) >= 16)
2774 return "# nop logical shift.";
2776 if (INTVAL (amount
) > 0
2777 && INTVAL (amount
) < 5)
2778 return "rrum.w\t%2, %0"; /* Two bytes. */
2780 if (INTVAL (amount
) > 4
2781 && INTVAL (amount
) < 9)
2782 return "rrum.w\t#4, %0 { rrum.w\t%Y2, %0 "; /* Four bytes. */
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. */
2790 struct gcc_target targetm
= TARGET_INITIALIZER
;
2792 #include "gt-msp430.h"