Copyright 2000-2012 Free Software Foundation, Inc. The material in this patch is a derivative work of the gcc package, and is subject to licensing and copyright of its parent package. This patch adds/enhances support for the Texas Instruments MSP430 family of microcontrollers to GNU gcc. The material incorporated is maintained in a git repository hosted at: git://mspgcc.git.sourceforge.net/gitroot/mspgcc/gcc This patch incorporates changes between: upstream/release/gcc-4.7.0 (3bd4897be46b07fb7c32a920c32713f313123a2a) and gcc-4_7/gcc-4.7.0 (d4223f9ad984820cc1139621a9552d0285f4205e) To build, obtain the upstream release distribution from: ftp://ftp.gnu.org/pub/gnu/gcc/gcc-4.7.0/gcc-4.7.0.tar.bz2 Unpack the distribution, apply the patch, and build. (Note: The example commands are in Bourne-shell syntax.) tar xjf gcc-4.7.0.tar.bz2 ( cd gcc-4.7.0 ; patch -p1 < ../msp430-gcc-4.7.0-20120911.patch ) mkdir -p BUILD/gcc cd BUILD/gcc ../../gcc-4.7.0/configure \ --target=msp430 \ --enable-languages=c,c++ \ --prefix=/usr/local/msp430 \ 2>&1 | tee co make 2>&1 | tee mo make install 2>&1 | tee moi For support please use the mspgcc-users mailing list. You can subscribe at https://lists.sourceforge.net/lists/listinfo/mspgcc-users. Once subscribed, you can post by email to mspgcc-users@lists.sourceforge.net. To report bugs, please file a tracker ticket on SourceForge at https://sourceforge.net/tracker/?group_id=42303&atid=432701 Log of relevant changes: 47f3bbe [2012-09-11 09:14:43 -0500] Update DEV-PHASE for release 51db7cb [2012-09-11 09:14:05 -0500] Update for release 37e318e [2012-09-10 17:08:04 -0500] SF 3559978 broken volatile peephole optimization d74f307 [2012-09-10 15:36:30 -0500] SF 3562647 lack of memory model results in wrong data region e1a7bb5 [2012-09-10 12:37:00 -0500] SF 3562063 delay_cycles wrong when optimization disabled 6acad2c [2012-09-10 11:10:27 -0500] SF 3554285 ICE: defining a far declared array w/o far cd8d8b5 [2012-09-10 07:59:24 -0500] SF 3554291 refine FRAM ISR fix 58c8933 [2012-07-16 14:31:37 -0500] Update DEV-PHASE for release fb2facd [2012-07-16 14:30:41 -0500] Update for release b1dc3cd [2012-07-15 06:25:05 -0500] SF 3544338 large memory model induction variable optimization broken 0594213 [2012-07-12 14:32:16 -0500] SF 3540953 fram applications overwrite bsl/jtag passwords 9584b95 [2012-07-09 15:19:38 -0500] Stub __even_in_range intrinsic dec1bc2 [2012-07-09 14:36:43 -0500] Pre-check expectations of MEM_VOLATILE_P a7873c4 [2012-07-07 12:39:02 -0500] SF 3541056 inefficient access through 20-bit pointers 3de8c1b [2012-07-07 11:59:25 -0500] Fix region selected for function rodata 9e935a26 [2012-07-06 14:10:02 -0500] SF 3539829 long argument performance degraded compared to mspgcc4 dfb6de7 [2012-07-06 10:30:53 -0500] SF 3539033 AND optimization to BIC not optimal 85e86a1 [2012-07-04 13:58:03 -0500] SF 3540458 optimize peripheral address size 5b1196c [2012-07-04 12:12:56 -0500] Detect conflicting type attributes e5dce1b [2012-07-04 12:01:26 -0500] Refactor replacement of type node when attribute added 85808f3 [2012-06-27 17:13:53 -0500] Update DEV-PHASE for release 83b5607 [2012-06-21 08:32:30 -0500] Anticipatory patch for PR middle-end/38756 f8d8515 [2012-03-07 14:31:40 +0000] 2012-03-07 Richard Guenther 5472342 [2012-06-20 14:00:03 -0500] Refine ivopts fix for SF 3534450 large problems with large memory model 11dc40d [2012-03-12 13:04:43 +0000] 2012-03-12 Richard Guenther 2162011 [2012-06-20 10:58:25 -0500] SF 3534574 invalid data written to packed structure with int20_t field 59f94d6 [2012-06-27 17:11:38 -0500] Update for release e70026b [2012-06-22 13:53:16 -0500] SF 3537200 detect incompatible object files a88c967 [2012-06-20 10:20:01 -0500] Clean up formatting of multi-line macros 87dce53 [2012-06-18 15:34:57 -0500] Update DEV-PHASE for release 40811eb [2012-06-17 09:51:32 -0500] SF 3534450 large problems with large memory model 8058057 [2012-06-18 15:32:47 -0500] Update for release 1e4dc41 [2012-06-18 12:00:08 -0500] Inhibit @progbits on region-qualified base and named BSS sections 9a2c151 [2012-06-17 12:58:48 -0500] Avoid placement of writable memory in non-existent far RAM 5da5dd8 [2012-06-16 16:45:46 -0500] SF 3534425 region mismatch with -f*-sections 5296774 [2012-06-16 16:29:16 -0500] SF 3534323 check that c16 on function forces near placement 52454c2 [2012-06-06 07:14:02 -0500] Update DEV-PHASE for release 90cdd55 [2012-05-20 08:23:27 -0500] Upstream content change supporting move to elfos.h 5f04738 [2012-06-05 18:06:36 -0500] Add hooks for non-standard SIZE_TYPE and PTRDIFF_TYPE ffb61fc [2012-06-05 15:48:07 -0500] stor-layout: accept exact MODE_PARTIAL_INT match 03e6eb6 [2012-06-04 09:04:24 -0500] Correct/note potential misuse of GET_MODE_BITSIZE 8f71be3 [2012-05-30 11:50:03 -0500] Backport upstream precision patch 1eee7ac [2012-05-20 14:22:58 -0500] Add hook TARGET_ASM_DECL_MERGEABLE_RODATA_PREFIX 803171c [2012-05-20 12:11:20 -0500] Add hook TARGET_ASM_VARIABLE_SECTION 8d75405 [2012-06-06 07:08:24 -0500] Update for release 6b61c03 [2012-06-06 06:29:02 -0500] Inhibit output of non-identifier locals 41fe016 [2012-06-05 18:07:26 -0500] Use hooks to define non-standard size_t and ptrdiff_t for msp430 -ma20 5388334 [2012-06-05 15:44:29 -0500] Correct bias eliminating argp 8b1c1eb [2012-06-05 12:35:46 -0500] Clean up push/pop expanders to support 20-bit stack pointer d67fc91 [2012-06-05 12:10:46 -0500] Add predicates validating SP mode e41b504 [2012-06-05 06:20:35 -0500] Avoid improper reads from 4-byte memory into PSI bb52596 [2012-06-04 19:04:43 -0500] Restore forced placement if interrupts in near region under CPUX f816b44 [2012-06-04 17:38:55 -0500] Permit const_int offset from register as A20 indexed memory operands 6405c5b [2012-06-04 17:20:22 -0500] Correct section for -md20 readonly data 53eaa9a [2012-06-02 13:25:56 -0500] Inhibit reference to far writable sections c5ae3927 [2012-06-02 10:31:45 -0500] Add -mcode-region and -mdata-region options 51906e9 [2012-06-01 07:42:57 -0500] Update constants to avoid word overflow 86b4c1e [2012-05-31 18:27:52 -0500] Add memory model option 3f83aba [2012-05-31 14:15:51 -0500] Switch to option enumerations ba9dabb [2012-05-30 17:52:41 -0500] Ensure interrupts default to near text section ba5df59 [2012-05-30 17:51:56 -0500] SF 3530932 unable to link with 20-bit symbols in debug sections e935583 [2012-05-30 16:40:30 -0500] Add %@ to asm output template 74a64d0 [2012-05-30 13:50:09 -0500] Add -ma16/mc16/md16 to override -ma20/mc20/md20 089e276 [2012-05-30 12:36:41 -0500] Potentially treat PSImode as a MODE_INT instead of a MODE_PARTIAL_INT a4539d6 [2012-05-30 12:05:47 -0500] Strip out unreferenced prologue/epilogue sequences d5d15e5 [2012-05-29 21:25:55 -0500] Simplify negation insn e9e8afb [2012-05-29 20:50:35 -0500] Simplify register management a56ed4a [2012-05-29 12:10:55 -0500] Another step to requiring PSImode for far pointers 4b154f9 [2012-05-29 11:18:03 -0500] Add a16 and recognize a16/a20 on pointer types e6546a19c [2012-05-28 20:34:18 -0500] Restore function-specific sections for strings and jump tables b08b9d8 [2012-05-28 12:47:07 -0500] Place text sections in appropriate region 7cf7628 [2012-05-22 11:53:16 -0500] Ensure sections express the desired region 81b946b [2012-05-22 10:34:25 -0500] Factor out categorize_decl_for_section 82606a5 [2012-05-22 10:04:35 -0500] Make explicit that relocs are not supported e5b9b29 [2012-05-22 09:50:59 -0500] Nothing filters for COMMON with near/far attrs 7d887a8 [2012-05-21 14:04:44 -0500] Clean up section selection 57bb4b6 [2012-05-21 13:55:14 -0500] Correct variable section to use relevant address space information 74dd1f2 [2012-05-20 16:47:43 -0500] Hook in control over unique and variable sections f42daed [2012-05-20 14:41:55 -0500] Use default_elf_select_section as template for msp430_select_section 9cfdbbb [2012-05-20 11:45:09 -0500] Move towards complete control of section assignment a80545e [2012-05-20 11:44:38 -0500] Remove unused feature (will use switchable sections for bss) 4e20a9e [2012-05-20 09:49:07 -0500] Update control flow insns to add required A20 validations 4f5abbc [2012-05-20 09:26:39 -0500] Accommodate 20-bit registers in profile register saver a3184ab [2012-05-20 08:31:39 -0500] Defer to shared elfos.h for asm-related features 09afb7f [2012-05-20 00:16:13 -0500] Clean up fprintf a456cb0 [2012-05-19 23:43:44 -0500] Eliminate special definition of ASM_OUTPUT_LABEL 2914a0e [2012-05-19 23:39:55 -0500] Eliminate special definition of globalize_label 35246a5 [2012-05-19 23:24:02 -0500] Use standard size calculation for functions 9b8d199 [2012-05-19 23:03:16 -0500] Add missing costs for PSI moves b8f9ac4 [2012-05-19 23:00:42 -0500] Eliminate illogical IS_ASM_LOGICAL_LINE_SEPARATOR 4615bbd [2012-05-19 22:59:08 -0500] Eliminate cloned string output, re-use elfos implementation 60fb91c [2012-05-19 22:39:23 -0500] Remove unreferenced variable 7cad4e9 [2012-05-19 22:39:09 -0500] Place function definitions in Target Macros section order b1d2b43 [2012-05-19 12:47:40 -0500] Hook in section definitions 3d5ae09 [2012-05-19 12:22:10 -0500] Hook in near/far/attributes 262194b [2012-05-18 12:28:38 -0500] Update output templates to support D20 operands 00295b2 [2012-05-18 16:47:09 -0500] Jump vector elements are the same mode as function pointers 3c19bb6 [2012-05-18 09:28:35 -0500] Check for overflow in snprintf 919f3a1 [2012-05-18 07:27:11 -0500] Check that pointer modes are as expected 0d9fa88 [2012-05-18 07:26:18 -0500] Start generating -md20 multilibs c014f4b [2012-05-17 17:17:32 -0500] Document alternative PSI definition and support it in code. ee89bf7 [2012-05-17 16:41:56 -0500] First stage toward forcing use of PSI alone as a large pointer type b03d6bf [2012-05-17 16:41:32 -0500] Correct RTL to note status register is always HImode 7dd82aa [2012-05-17 09:21:47 -0500] Update use of sp to accommodate wide pointers bbddf11 [2012-05-16 11:55:08 -0500] Recognize variant insn based on pointer size 609aa21 [2012-05-16 11:53:50 -0500] Use genericized expanders when operating on Pmode values d255d09 [2012-05-16 11:52:08 -0500] Accept SImode (=ptr_mode, vice Pmode) as valid for pointers 4bb8063 [2012-05-16 10:31:06 -0500] Share type mode calculations, and use HImode for c16 93f6ce9 [2012-05-14 20:04:18 -0500] Update DEV-PHASE for release 822bc1e [2012-04-30 12:59:17 -0500] Add pointer_mode and address_mode to mem_attrs ac85f5a [2012-04-30 10:57:02 -0500] Add hooks to override pointer and address modes based on type trees. 5f4ab69 [2012-04-30 18:44:31 -0500] Remove gratuitous passing of function through memory_address 94215a2 [2012-04-26 14:20:39 +0000] Back-port upstream fix for PR middle-end/52940 9bc61d1 [2012-04-26 11:52:28 -0500] Revert "Anticipatory patch for PR middle-end/52940" e83c38a [2012-04-27 07:25:30 -0500] Back-port upstream fix for PR c/51527 and PR middle-end/53103 e127602 [2012-04-24 14:48:07 -0500] Anticipatory patch for PR middle-end/53104 57f54ee [2012-05-14 20:03:46 -0500] Revert "Anticipatory patch for PR middle-end/53103" a94ef9d [2012-05-14 20:03:41 -0500] Revert "Anticipatory patch for PR middle-end/53104" 3172e71 [2012-05-14 19:48:59 -0500] Update for release bd70d32 [2012-05-14 18:11:18 -0500] Run everything through indent cd3c885 [2012-05-14 11:26:38 -0500] fix -Wformat-security issue dcb0ec7 [2012-05-14 11:23:59 -0500] SF 3514303 fix popmhi2 cc attr eecc868 [2012-05-13 20:18:36 -0500] Prevent bogus truncation from SI to PSI a19b694 [2012-05-12 14:52:41 -0500] Accept post-increment source for movpsi d2f5b16 [2012-05-05 15:01:30 -0500] Use type-specific attributes to determine SR20 and C20 symbol flags and modes 5578c1c [2012-05-05 13:23:49 -0500] Convert c20 and c16 to type attributes de6e54d [2012-05-04 04:56:30 -0500] Refactor attributes d8e54aa [2012-05-04 04:49:17 -0500] Cleanup build warnings 393ff98 [2012-05-03 08:46:02 -0500] Implement core of -md20 and -ma20 144b514 [2012-05-03 08:42:36 -0500] Avoid errors extending 20-bit symbolic address 8f405f2 [2012-05-01 03:53:27 -0500] Use target hooks for type-specific pointer modes 65cc562 [2012-05-01 04:35:13 -0500] Add target switch -misr20 1802b2a [2012-05-01 04:11:42 -0500] Stop filtering warnings on mis-use of a20 attribute d02eb40 [2012-04-30 08:32:10 -0500] Refactor to share attribute name match between modules 63dd0b2 [2012-04-29 11:36:55 -0500] Treat PSImode as fully supported for scalar operations d7a2602 [2012-04-29 11:09:05 -0500] First pass at c20 support 1b404d1 [2012-04-27 03:40:38 -0500] Define remaining (unimplemented) CPUX target options d000415 [2012-04-28 11:01:46 -0500] Avoid adding inconsistent attributes to function declarations 4fb46b9 [2012-04-28 10:12:09 -0500] Prepare to move fndecl attribute validation to handler 4a21ef9 [2012-04-27 03:27:54 -0500] Rename preprocessor flags identifying CPUX target options 5ff0c47 [2012-04-25 03:36:18 -0500] Update DEV-PHASE for release 150e88f [2012-04-24 14:48:07 -0500] Anticipatory patch for PR middle-end/53104 086a2c8 [2012-04-24 13:54:22 -0500] Anticipatory patch for PR middle-end/53103 519cc89 [2012-04-11 18:10:41 -0500] Anticipatory patch for PR middle-end/52940 770d836 [2012-04-09 17:29:18 -0500] Anticipatory patch for PR middle-end/52919 cdf7d6e [2012-04-03 16:44:16 -0500] Anticipatory patch for PR middle-end/52856 cffacc3 [2012-04-25 02:31:46 -0500] Update for release fcf6556 [2012-04-23 17:40:08 -0500] Support extend from psi, and truncate to/from psi c9c18ad [2012-04-24 13:56:32 -0500] Support zero-extend load byte into PSI as well as HI reg a0a3396 [2012-04-10 17:29:34 -0500] SF 3512818 rework rotate to use 430x repeat feature fccc558 [2012-04-09 20:12:20 -0500] Support shift to PREC-1 for PSImode 1e49a19 [2012-04-11 11:14:37 -0500] Add CPUX repeated instruction support 13e444c [2012-04-08 11:42:29 -0500] Support saving 20-bit registers within functions fad4a26 [2012-04-03 12:35:29 -0500] Partially working support for a20 comparisons 2e42b9f [2012-04-03 09:36:53 -0500] Correct instruction lengths for extended instructions f67b68c [2012-04-03 08:11:05 -0500] Incomplete support for passing a20 args around in functions 64b825f [2012-04-02 17:59:55 -0500] Add PSImode as 20-bit integer via __a20__ attribute on long int 926fe46 [2012-04-02 14:55:47 -0500] Uniformly use TARGET_CPUX when mcu has CPUX support 6571a61 [2012-04-07 11:50:15 -0500] Update DEV-PHASE for release 95a2622 [2012-04-07 10:34:53 -0500] Update for release e33bad7 [2012-04-06 08:36:12 -0500] Update for release 6511e76 [2012-03-30 18:49:30 -0500] Update for release 58b91df [2012-03-30 10:22:34 -0500] SF 3513285 add CPU/MPY defines to internal cpp set 2eac54bc [2012-03-30 10:08:03 -0500] Provide __interrupt support independently from iomacros.h c18fd6a [2012-03-30 17:24:57 -0500] Update DEV-PHASE for internal sync c59a077 [2012-03-28 14:49:26 +0000] PR middle-end/52691 * tree-ssa-ccp.c (optimize_stdarg_builtin): Optimize __builtin_va_start to __builtin_next_arg if the latter is builtin_decl_explicit_p rather than when it is not. 0c9d62f [2012-03-30 17:20:21 -0500] Revert "Anticipatory patch for PR tree-optimization/52691" 4550ab3 [2012-03-29 08:42:14 -0500] Pass operands into output template function 039f1c3 [2012-03-29 07:37:27 -0500] Avoid llo when operand format does not include shift specifier c1b3bb5 [2012-03-28 13:16:57 -0500] SF 3512484 clean up legacy hwmul noise fe3aae7 [2012-03-29 11:00:53 -0500] Eliminate unnecessary expand for mov 4dfd98a [2012-03-29 09:37:55 -0500] Eliminate unnecessary define_expand for add/sub 8bfff7e [2012-03-28 12:32:23 -0500] Use mode iterator for mov expansion 64c7a91 [2012-03-27 17:02:38 -0500] Remove unreferenced trunc instructions efa43d4 [2012-03-30 10:22:34 -0500] SF 3513285 add CPU/MPY defines to internal cpp set f5106c0 [2012-03-30 10:08:03 -0500] Provide __interrupt support independently from iomacros.h ed2e57b [2012-03-27 08:53:56 -0500] Switch to CONSTANT_ADDRESS_P in legitimate address 3fcfecf [2012-03-26 15:28:44 -0500] Run through indent eea74e6 [2012-03-25 11:24:51 -0500] Review target macros for 4.7.x 3ce5169 [2012-03-26 11:02:37 -0500] Eliminate unused target options e6ef70c [2012-03-23 15:48:20 -0500] Regenerate 99da20c [2012-03-21 16:00:08 -0500] Add msp430 target support to GCC 677b6cf [2012-03-23 15:45:20 -0500] Revert "Add msp430 target support to GCC" 2427f09 [2012-03-23 15:45:10 -0500] Revert "Regenerate" 7d1c7b6 [2012-03-23 15:42:44 -0500] Revert "Support move of libgcc and crt to libgcc" 56f24f5 [2012-03-23 13:26:34 -0500] Update DEV-PHASE through 4dc4ff4 2dd99f2 [2012-03-23 13:26:10 -0500] Support move of libgcc and crt to libgcc ebfaebe [2012-03-05 20:20:40 -0600] Move libgcc and crt to libgcc 3c90b40 [2012-03-23 13:09:48 -0500] Update DEV-PHASE for pre-9213d2e f3fc6cc [2012-03-22 18:21:18 -0500] testsuite/sf3428439: update to match generated code fbd0e79 [2012-03-23 13:01:57 -0500] Update DEV-PHASE through b9a1687 42e5cc0 [2012-03-23 13:01:35 -0500] Anticipatory patch for PR tree-optimization/52691 9f3d586 [2012-03-23 12:10:56 -0500] Update DEV-PHASE for pre-b9a1687 37e7c5f [2012-03-23 11:21:30 -0500] Update DEV-PHASE through 20d892d 9821065 [2012-03-22 18:01:11 -0500] add opno to rtx_costs 9d665c6 [2012-03-23 11:17:53 -0500] Update DEV-PHASE for pre-20d892d ad0b2f7 [2012-03-23 11:14:53 -0500] Update DEV-PHASE through 39cba15 a4abf04 [2012-03-22 17:40:21 -0500] Replace CUMULATIVE_ARGS* argument type with cumulative_args_t 15eba91 [2012-03-23 10:51:11 -0500] Update DEV-PHASE for pre-39cba15 94a56fd [2012-03-23 10:47:56 -0500] Update DEV-PHASE through 218e3e4 4bf36af [2012-03-22 17:11:23 -0500] msp430-common.c: add 255626a [2012-03-23 10:44:15 -0500] Update DEV-PHASE for pre-218e3e4 51e4b02 [2012-03-23 10:43:57 -0500] Revert "SF 3412886 pre-patch pr50213/tree-optimization" 89b2abd [2012-03-23 10:36:37 -0500] Update DEV-PHASE through ca31636 7587dfe [2012-03-05 14:50:07 -0600] Remove poisoned LEGITIMATE_CONSTANT_P cd27ff3 [2012-03-23 10:33:27 -0500] Update DEV-PHASE for pre-ca31636 a1256b5 [2012-03-22 16:39:28 -0500] Revert "testsuite: update to match current generated code" 4e03c49 [2012-03-23 10:30:01 -0500] Update DEV-PHASE through fa8d6f0 f7b198a [2012-03-05 14:52:47 -0600] Rename ASM_OUTPUT_BSS 4b00e59 [2012-03-23 10:23:36 -0500] Update DEV-PHASE for pre-fa8d6f0 ac9876f [2012-03-22 16:20:52 -0500] testsuite/vwa_regression.c: add intervening label to pattern a0e5872 [2012-03-23 10:15:00 -0500] Update DEV-PHASE through a19f368 3ababb8 [2012-03-05 14:38:15 -0600] msp430.h: remove poisoned TARGET_VERSION 7dff65e [2012-03-23 10:11:43 -0500] Update DEV-PHASE for pre-a19f368 bfb26ec [2012-03-22 16:08:29 -0500] testsuite: update to match current generated code aabcb4fc [2012-03-23 10:08:13 -0500] Update DEV-PHASE through 81bcd36 45a3763 [2012-03-05 16:18:41 -0600] convert function_arg to target hook f3c6757 [2012-03-23 10:04:10 -0500] Update DEV-PHASE for pre-81bcd36 b0dee11 [2012-03-23 09:56:51 -0500] Update DEV-PHASE through ac86af5 6167c65 [2012-03-05 14:59:32 -0600] Add affects_type_identity to attribute_spec b79baed [2012-03-23 09:52:25 -0500] Update DEV-PHASE for pre-ac86af5 e53674f [2012-03-22 14:20:44 -0500] testsuite/volpeep_mem.c: now uses r14 instead of r15 f5b498c [2011-09-22 09:25:24 -0500] SF 3412439 address IRA issue in upstream pr50427/rtl-optimization 178665e [2011-09-22 09:22:25 -0500] SF 3412886 pre-patch pr50213/tree-optimization f78df09 [2011-02-21 03:47:03 -0600] Anticipatory patch for PR middle-end/42722 (SF 3148801) 6815742 [2011-01-18 13:13:21 -0600] Add %:include-noerr as spec function. 3b0e67a [2011-07-25 18:13:25 -0500] Regenerate 500b2ac [2012-03-21 16:00:08 -0500] Add msp430 target support to GCC 0fa909f [2012-03-23 08:30:38 -0500] Update for release 5a3c262 [2012-03-22 15:22:49 -0500] msp430.md: fix operand 1 pattern for strlen fac40d9 [2012-03-22 14:45:35 -0500] Eliminate various compiler warnings 75e6526 [2012-03-22 10:00:54 -0500] Update for release 6ee7148 [2012-03-22 04:01:56 -0500] SF 3113886 Peripheral RAM block mapping ba7338c [2012-03-21 15:58:43 -0500] SF 3474171 support TI standard interrupt declaration d3f7972 [2012-03-11 13:09:56 -0500] Update for release 8e6ca75 [2012-03-10 15:00:01 -0600] SF 3499699 Incorrect generated code returning from main b2ed137 [2012-03-07 13:33:04 -0600] SF 3420924 gdb can't find local variables in unoptimized main b96f163 [2012-03-07 11:14:52 -0600] SF 3498729 diagnose frame pointer corruption in task 11f355e [2012-03-04 16:36:31 -0600] msp430-builtins: eliminate signed/unsigned comparison warning 8f6a458 [2012-03-04 16:26:17 -0600] SF 3496195 possibly incorrect using of conditional branch adf92c7 [2012-03-04 14:07:16 -0600] Refine cc0 implementation dca4c73 [2012-02-24 04:33:56 -0600] Update for release d3a6ed9 [2012-02-23 17:06:37 -0600] SF 3486466 if mcu left off, unclear error msg b39ee97 [2012-02-23 16:37:08 -0600] SF 3486463 msp430 4.6.1 toolchain warns about .noinit 473e1ea [2012-02-06 17:29:00 -0600] Use standard method of emitting labels 59ded52 [2012-02-06 17:25:33 -0600] SF 3440809 -O2 conflicts with naked functions ff1697d [2012-02-06 17:13:16 -0600] Reorder return insns so default does not have extraneous tests d4c922c [2012-02-06 13:51:29 -0600] Revert "SF 3440809 -O2 conflicts with naked functions" b27610a [2012-01-25 13:35:56 -0600] Update for release 51fd720 [2012-01-25 12:02:17 -0600] SF 3479668 msp430-libc ICE on 32-bit host 161ca2e [2012-01-25 10:33:48 -0600] SF 3479660 delay_cycles(INT32_MAX) fails on 32-bit host 79181ea [2012-01-19 16:01:35 -0600] Update for release 2da8f82 [2012-01-06 16:39:04 -0600] Reuse existing function to determine length of constant 8196139 [2012-01-06 16:16:14 -0600] Accept length for tablejump ec86a20 [2012-01-06 11:46:06 -0600] Swap args when dest is indirect register 3228dad [2012-01-06 10:29:39 -0600] Disable early-clobber constraints on multi-word operations f5bcb28 [2012-01-05 17:05:11 -0600] Update for release 9e311cd [2012-01-05 14:35:56 -0600] Fix length for non-standard out-of-range branches 64670b7 [2012-01-05 10:08:06 -0600] Update length adjustment for conditional jump, return, and basic operands 707930d [2012-01-05 09:09:40 -0600] Correct setcc insn length; fix bit carry mode error ee4eccd [2012-01-04 21:45:47 -0600] Use local labels instead of byte offsets 9acab17 [2012-01-04 21:13:28 -0600] Permit comparisons on stack pointer and pseudo registers ad2846a [2012-01-04 20:50:19 -0600] Restore SF 3296698 peephole optimization 6f93e81 [2012-01-04 19:04:54 -0600] Another attempt to make bittest for bit extraction non-volatile b440bae [2012-01-04 18:16:09 -0600] Update CC status based on attribute effects 295a3b1 [2011-10-31 11:29:56 -0500] Review and update all cc attr values 6356b4d [2012-01-04 17:11:30 -0600] Avoid comparison change on symbol_ref operands b700ea0 [2011-10-30 12:59:24 -0500] Replace cbranch infrastructure 44686c2 [2012-01-05 16:58:09 -0600] Restore peephole optimization for andm2 172eabb [2011-10-26 10:01:56 -0500] Cull peepholes and sequelae 234f8ae [2011-12-24 11:09:01 -0600] Update for release 5e574ea [2011-12-23 16:46:35 -0600] SF 3461162 remove non-standard ABI from libgcc functions e6f2470 [2011-12-23 13:05:23 -0600] Replace div/mod library functions b1d9c36 [2011-12-23 11:54:42 -0600] Remove all div/mod/divmod traces in preparation for replacement 4f0a4b1 [2011-12-21 17:45:55 -0600] Rework libcall multiply to conform to ABI 8ae17f9 [2011-12-21 10:17:46 -0600] Remove unreferenced umulsi3hw 83ced76 [2011-12-21 10:07:25 -0600] Remove cmpsf libfunc 0e29d57 [2011-12-19 11:18:02 -0600] Update for release a6b5024 [2011-12-16 16:20:29 -0600] SF 3459792 64-bit division/remainder clobber frame pointer 2ae67d6 [2011-12-16 16:02:45 -0600] SF 3461136 epilog popm insn corrupted 55c7f4b [2011-12-13 20:31:50 -0600] SF 3459655 broken bitfield extraction a4eef8e [2011-12-09 07:59:37 -0600] Validate SF 3273856 bee4f4d [2011-12-05 08:17:00 -0600] Update for release 5d1b4b6 [2011-11-21 12:28:33 -0600] SF 3440809 -O2 conflicts with naked functions 377b6c8 [2011-11-20 09:32:43 -0600] SF 3383371 add watchdog support intrinsics 0798f01 [2011-11-18 20:30:49 -0600] Test for errors on use of -fpic/-fPIC 21cfc98 [2011-11-05 09:31:47 -0500] SF 3433730 Bug when casting function parameters 4f902d7 [2011-11-04 09:34:12 -0500] Update for release c0bfdb1 [2011-11-03 12:06:53 -0500] Rework shift to avoid techniques that inhibit optimizations 21a606e [2011-10-31 16:01:56 -0500] Generalize bittest to support non-constant values 6d2c0aa [2011-11-03 10:41:00 -0500] SF 3431602 Incorrect comparison to 32-bit literal 408f228 [2011-10-30 08:59:10 -0500] Update for release 27f8454 [2011-10-29 15:01:11 -0500] Simplify convoluted template output dd0075e [2011-10-26 13:09:04 -0500] Clean up print operand 9a900b5 [2011-10-29 14:12:02 -0500] Remove unreachable code 6bbfd3b [2011-10-25 17:31:58 -0500] SF 3428439 support source auto increment operands 7aa61ac [2011-10-25 16:06:11 -0500] Remove definitions of unused constraints 12ff090 [2011-10-25 12:04:50 -0500] Canonicalize placement of cc attr settings and post-comma asm spacing dc3b946 [2011-10-25 11:46:50 -0500] Replace gratuitously complex jump insn 675176b [2011-10-24 14:42:05 -0500] Eliminate inconsistency between call/call_value 613706b [2011-10-25 11:31:56 -0500] Clean up extract insns b152dad [2011-10-25 18:36:59 -0500] Restore lost mode on unspec 440301c [2011-10-24 10:11:33 -0500] Update for release 0a76b34 [2011-10-24 09:59:20 -0500] Clarify interface to msp430_expand_insn functions eca5c47 [2011-10-24 09:30:05 -0500] Run things through indent bba6b13 [2011-10-24 09:25:51 -0500] Remove unused file 0be6fc8 [2011-10-24 09:00:52 -0500] Use prefered mechanism for identifying size optimization 0ee4d4e [2011-10-23 14:52:17 -0500] Refine length correction for other unspecs 0babd77 [2011-10-23 14:45:30 -0500] SF 3426564 signed bitfield extraction broken 774f509 [2011-10-21 13:24:30 -0500] Fix insn models for rotate in from carry. 117ac67 [2011-10-21 12:38:30 -0500] Remove unspec_volatile from insns that are correctly modeled without it 27a2c6a [2011-10-21 12:13:01 -0500] Model effect of rotate insns on carry flag 18ada90 [2011-10-21 10:56:18 -0500] Inhibit extv insns 2fde3be [2011-10-21 07:59:11 -0500] Update for release ebe1165 [2011-10-20 20:37:05 -0500] Eliminate peepholes related to shift operations bdbcf3e [2011-10-20 16:46:40 -0500] Remove redundant quotes cdf919b [2011-10-20 16:24:23 -0500] Use REGNO_* for register number constants 87d3f7e [2011-10-20 12:35:53 -0500] Use pushm/popm in libgcc functions 14fadac [2011-10-20 12:22:33 -0500] SF 3426468 use pushm for si/di values on stack 44ba82e [2011-10-20 11:53:22 -0500] SF 3237004 implement 430x pushm dfb2de2 [2011-10-18 20:13:21 -0500] Update for release e8294a4 [2011-10-16 10:25:48 -0500] SF 3423822 validate interrupt attribute parameter e6c4351 [2011-10-11 09:23:06 -0500] Update for release 2a8a2c9 [2011-10-11 09:19:52 -0500] SF 3377789 Review ASSEMBLER_DIALECT 47b1a52 [2011-10-11 09:15:16 -0500] SF 3377785 test default ASM_APP_{ON,OFF} a2096f6 [2011-10-08 09:35:12 -0500] SF 3416278 allow users to control __low_level_init() c404e6e [2011-10-07 10:33:35 -0500] SF 3417263 GDB wrong address for variables ad6bb37 [2011-09-22 11:21:37 -0500] Update for release 4830af7 [2011-09-18 13:15:02 -0500] SF 3411254 add __swap_bytes intrinsic f60dcf8 [2011-09-18 12:08:16 -0500] SF 3411243 need get/set interrupt state intrinsics 4214b9f [2011-08-30 13:06:33 -0500] Update for release 6a654e0 [2011-08-30 12:23:26 -0500] SF 3399395 revisit no-volatile-workaround 9fab0e5 [2011-08-30 09:37:26 -0500] SF 3400750 infomemnobits missing 44b88a0 [2011-08-29 20:57:00 -0500] Verify self-modifying operations. 556cbad [2011-08-29 17:15:49 -0500] Extend RMW peepholes to addition and subtraction b5b464f [2011-08-29 16:58:23 -0500] Fix regression assigning through constant cast as volatile pointer fc183b6 [2011-08-29 15:30:20 -0500] Fix remaining regressions in existing test suite 45c1914 [2011-08-29 15:28:41 -0500] Fix VWA regression in builtins_sp.c. 31dd799 [2011-08-29 15:17:54 -0500] Fix VWA regression in builtins_read_sr.c. 307d7f5 [2011-08-29 15:00:00 -0500] Optimize nand on volatile memory f671271 [2011-08-29 14:40:22 -0500] Optimize nand from memory f3872bf [2011-08-29 14:15:39 -0500] Optimizations involving non-volatile and volatile memory c37b500 [2011-08-29 13:52:27 -0500] Optimizations involving only volatile memory 6c89cb6 [2011-08-29 13:23:59 -0500] Combine bit operation peepholes with structural equivalence cb03664 [2011-08-29 13:03:36 -0500] Peephole optimizations supporting peripheral register AND, IOR, XOR, NAND* f35a949 [2011-08-29 11:16:49 -0500] Remove the volatile workaround a2f0e8f [2011-08-29 09:42:50 -0500] Avoid addition of nonexistent libg during static links using -g 1cc49f3 [2011-08-23 20:07:50 -0500] Update for release 904f407 [2011-08-23 18:21:52 -0500] SF 3397068 generalize noinit support 227645b [2011-08-22 16:54:33 -0500] Eliminate easy_mul 09e55aa [2011-08-22 16:51:49 -0500] SF 3192592 review cost expressions a7d4a15 [2011-08-20 20:21:02 -0500] Update for release 129e28e [2011-08-20 19:53:15 -0500] SF 3237002 implement 430x multi-bit shift/rotate 60b0556 [2011-08-20 18:46:06 -0500] Lift clrc out of loop for all lshr operations cd984c5 [2011-08-20 17:29:04 -0500] Refactor to decrease use of r_op c48bd09 [2011-08-20 10:21:03 -0500] Prepare for inline non-const shifts 3aeae48 [2011-08-20 09:02:59 -0500] Avoid r_op for multi-word register shifts cbe5cb5 [2011-08-20 04:25:13 -0500] Optimize 8-bit shifts ac32b96 [2011-08-20 02:43:13 -0500] Eliminate redundant moves related to r_op a86a6f5 [2011-08-19 15:37:27 -0500] Avoid temporary registers where no optimization possible c80fb27 [2011-08-19 15:08:33 -0500] Rework to use temporary registers independently of subregs f2b650c [2011-08-19 10:26:45 -0500] Refactor NBITS-1 shifts to avoid excessive multi-word registers 2f93714 [2011-08-19 10:26:11 -0500] Correct predicate on LHS of storeqi2 5365c4a [2011-08-19 08:34:37 -0500] Use standard RTL for extension operation, rename for clarity 0226d04 [2011-08-19 08:16:11 -0500] Define matching pair for QI val / full reg load and store 20335d2 [2011-08-18 14:04:57 -0500] Implement 16-bit optimized shifts and piecewise sub-8bit shifts 97fad8e [2011-08-18 14:04:25 -0500] Correct insn constraints 3977c66 [2011-08-18 12:01:26 -0500] Add piecewise insn for logical right shift; correct shift cc clobbers c59d8cb [2011-08-18 11:17:56 -0500] Rework tradeoff between loop and inline to respect -Os vs -O 2bd47e9 [2011-08-18 10:36:39 -0500] Restructure in preparation for word-based sub-8-bit rotates 0914c4a [2011-08-17 20:28:06 -0500] Optimize shifts 32..47 bits 2109c59 [2011-08-17 19:59:48 -0500] Refactor for clarity 34751fa [2011-08-17 19:42:09 -0500] Optimize shifts of 48 or more bits e7fab1f [2011-08-17 19:25:01 -0500] Start move toward eliminating copy from src to dest 4bb7e55 [2011-08-17 14:57:13 -0500] Clean up how shift types are identified aa91bd5 [2011-08-17 12:03:12 -0500] Add shift primitive ops, optimize shift of NBITS-1 fed9c4a [2011-08-17 10:08:34 -0500] Invert so we can replace r_op as we refine the results 622528d [2011-08-17 05:09:02 -0500] Use loops for constant shifts if unrolled will take more space 927c7bb [2011-08-17 04:39:34 -0500] Eliminate bogus cost estimations for shift operations. 60dbead [2011-08-17 04:29:58 -0500] Another stab at multi-position support. baf509d [2011-08-17 04:02:12 -0500] Fix rrum on CPUX hi. 027f317 [2011-08-17 03:33:38 -0500] Gross generation of constant shift sequences. 74449ed [2011-08-17 03:08:16 -0500] Cleanup: consistent use of constraint instead of matchdup ae4fe30 [2011-08-16 17:55:31 -0500] Fix ashrhi3_15 again 6fd83e8 [2011-08-16 17:34:56 -0500] Recognize more (trivial) inline opportunities 9e68677 [2011-08-16 17:06:19 -0500] Fix ashrhi3_15 clobber; emit inline single-insn HImode shifts 8acad80 [2011-08-16 16:26:26 -0500] Correct format for rl* insns de793db [2011-08-16 16:14:44 -0500] Prepare for potential of expanding using template b1205bc [2011-08-16 13:30:17 -0500] Replace shift implementation with library calls 42da5d9 [2011-08-16 03:50:31 -0500] Add optimized shift implementations b98a654 [2011-08-18 20:06:13 -0500] SF 3394176 unrecognizable insn error subtracting addresses 1df1153 [2011-08-16 16:18:27 -0500] Correct first parameter to conditional generator 61a7360 [2011-08-16 04:51:12 -0500] Eliminate compiler errors, detect unhandled cases 626e547 [2011-08-16 02:48:31 -0500] Comment cleanup b886801 [2011-08-13 11:17:45 -0500] SF 3390964 broken optimization with emulated multiply libcalls 2f5126f [2011-08-09 13:16:59 -0500] Update for release 544b161 [2011-08-09 03:17:25 -0500] SF 3388064 __delay_cycles is limited to 65535 62f859e [2011-08-08 12:29:09 -0500] Eliminate compiler warning 8f9c203 [2011-08-06 07:44:58 -0500] Update for release af7ce10 [2011-08-05 18:15:43 -0500] SF 3191569 register use cleanup: tieable ff84717 [2011-08-05 17:15:46 -0500] SF 3195549 addc_zero/subc_zero inconsistency eec1581 [2011-08-05 17:07:54 -0500] SF 3273856 eliminate cse of constant zero 2b00fae [2011-08-05 16:33:49 -0500] Eliminate compiler warnings and style errors 23a6f17 [2011-08-05 16:24:23 -0500] Remove unused global costs function 97268c5 [2011-08-05 09:21:26 -0500] Get rid of magic numbers dbd2219 [2011-08-05 08:32:31 -0500] Put function-local string constants into unique rodata where appropriate 1cf2f35 [2011-08-03 04:29:35 -0500] Update for release e4f5384 [2011-08-02 16:34:25 -0500] SF 3384766 string constants misplaced in text section 3f602e2 [2011-07-27 09:54:27 -0500] SF 3370978: ICE on shift with 32-bit count 5454162 [2011-07-27 06:03:06 -0500] Avoid warning about undeclared diagnostic functions 95e763b [2011-07-25 21:13:35 -0500] Review and update to 4.6.0 version of Chapter 17 (Target Macros) 98f6c89 [2011-07-25 19:31:48 -0500] Run everything through indent db4a82e [2011-07-25 18:09:55 -0500] Change spelling of spec function 38dde08 [2011-07-25 16:53:02 -0500] Avoid garbage collection of mpy rtx structures 79787aa [2011-07-25 14:00:41 -0500] Remove non-standard movstrhi/clrstrhi 9e2bf05 [2011-01-01 20:51:50 -0600] Rework how unwinding is done. f4a6bd4 [2011-07-25 12:03:54 -0500] Replace GET_ENVIRONMENT 51fcf95 [2011-01-01 20:18:39 -0600] Update GNU garbage collector use. a322715 [2011-01-01 20:57:32 -0600] Eliminate declarations for option variables. 26e94eb [2011-01-01 21:24:01 -0600] Generalize optimization-dependent option defaults. 086f349 [2011-01-01 20:42:15 -0600] Replace OVERRIDE_OPTIONS with TARGET_OPTION_OVERRIDE. 0f8c96c [2011-01-01 20:37:34 -0600] Remove RETURN_POPS_ARGS. 95ffbd3 [2011-01-01 20:03:53 -0600] Eliminate ORDER_REGS_FOR_LOCAL_ALLOC and TARGET_REORDER. b3bc594 [2011-07-05 17:09:07 -0500] Update for release 203cd7e [2011-07-05 17:03:47 -0500] SF 3354800 put back -mdisable-hwmul 5a9eec4 [2011-07-05 16:42:49 -0500] SF 3354807 ICE with -mmpy=16 on 32-bit constant multiplies c17a05a [2011-07-05 16:08:47 -0500] Update for release 356dce9 [2011-07-05 15:56:40 -0500] Fix illegal extraction of low part of constant multiplication operand 29af6de [2011-07-05 15:19:06 -0500] Complete support for MPY32 339ecc8 [2011-07-05 15:06:47 -0500] Tested hardware multiply for non-MPY32 support e018493 [2011-07-05 15:01:28 -0500] Tiny optimization in mulsidi3 0808b4d [2011-07-05 14:59:27 -0500] Add library functions for widen-to-64 multiply a74eec7 [2011-07-05 14:33:06 -0500] Validate muldi3 391b168 [2011-07-05 10:39:24 -0500] Use mode iterators for multiplication insns 3fd730b [2011-07-05 10:03:32 -0500] Clean up multiplication f6048bb [2011-07-05 09:03:08 -0500] Use correct "can't happen" function 5ceb03b [2011-07-05 07:21:04 -0500] Remove patterns from non-expanded RTL templates c8d5bff [2011-07-04 21:29:21 -0500] Avoid unnecessary sign extension on mulqihi operations c692ec0 [2011-07-04 21:24:19 -0500] Refine multiplier peripheral indicator values c979dee [2011-07-04 21:16:18 -0500] SF 3354053 remove -mforce-hwmul, -mdisable-hwmul c4cc7fd [2011-07-04 20:13:07 -0500] Fix indentation defe95e [2011-07-04 15:43:25 -0500] More syntax cleanup 7ae064f [2011-07-04 15:38:45 -0500] Syntax cleanup c6f5686 [2011-07-04 14:57:11 -0500] SF 3317421 -Os generates unrecognized insn for multiply-by-constant e534b53 [2011-07-04 14:08:58 -0500] Run things through GNU indent again c6b9d85 [2011-07-04 13:44:11 -0500] Eliminate special insns for MPY peripheral access 7301357 [2011-07-04 12:56:41 -0500] Rework multiply interrupt protection insns 81c5841 [2011-07-04 07:30:03 -0500] pophi sr clobbers condition codes 596fe75 [2011-07-04 08:02:06 -0500] Clean up msp430_init_once 4f1b02a [2011-06-25 15:15:52 -0500] Remove distracting disabled code 2b1e36a [2011-06-25 15:01:31 -0500] Reformat macros so they are readable 0aa02ac [2011-06-25 15:00:52 -0500] Remove unreferenced multiply-related registers 0b0cd25 [2011-06-25 13:43:53 -0500] Remove outdated push helper functions b680b48 [2011-06-25 13:20:43 -0500] SF 3317711 path to ldscripts broken if installation moved 73007d8 [2011-06-25 11:07:53 -0500] Patch provided by submitter 9f6f736 [2011-06-12 08:35:07 -0500] Update for release e0d67b8 [2011-06-12 08:33:32 -0500] SF 3313978 ICE (unrecognizable insn) related to rotate c67eb41 [2011-05-30 11:39:49 -0500] Update for release c5b4fc7 [2011-05-30 10:23:18 -0500] SF 3302511: ICE building newlib 1.19.0 eb98053 [2011-05-15 15:36:20 -0500] Update for release a6911fa [2011-05-10 20:02:57 -0500] SF 300205 regression: sizeof(short) != 2 7949660 [2011-05-03 06:15:17 -0500] SF 3296698: unoptimized code for bit field/union d372fa6 [2011-04-30 14:21:18 -0500] Use a less obscure RTL pattern for swpb 7aceebf [2011-04-30 12:35:41 -0500] Remove repeated calculation in cost expression calculation 6e3c8e9 [2011-04-24 04:32:16 -0500] SF 3291533 __cmpdi2 wrong redux f4dcf98 [2011-04-23 13:34:41 -0500] Lift out function that splits multiword operands bbb040e [2011-04-23 09:48:47 -0500] Simplify absm2 2cf5283 [2011-04-23 09:48:24 -0500] Avoid mode-less constants as op0 f3c5554 [2011-04-22 20:50:21 -0500] New solution to expansion of multi-word comparisons 87310b1 [2011-04-22 17:36:53 -0500] Strip cbranchsi4 support e545f89 [2011-04-22 13:25:29 -0500] SF 3291533 __cmpdi2 wrong 5111472 [2011-04-21 17:33:06 -0500] Refactor high/low part extraction d24a5af [2011-04-21 16:58:42 -0500] Consolidate cbranch-related functions c5cacde [2011-04-21 15:44:34 -0500] Inline the operation to use canonical MSP430 comparison operator 138db44 [2011-04-21 15:33:24 -0500] Eliminate unreferenced functions 74cc7c0 [2011-04-21 11:36:18 -0500] br is an emulated format II instruction 629871e [2011-04-21 10:22:56 -0500] Update for release e3b4304 [2011-04-21 09:09:11 -0500] SF 3195322 remove profile options -mpgs, -mpgl, -mpgr 378cb1e [2011-04-21 09:02:14 -0500] SF 3288916 dint builtin should emit noop 6809b99 [2011-04-21 08:55:04 -0500] SF 3290923 sequence of calls can overrun stack e0cda89 [2011-04-19 16:04:42 -0500] Eliminate introduction of temporary c638954 [2011-04-19 15:11:38 -0500] Strip out unused code 1ed8438 [2011-04-19 14:52:02 -0500] Remove useless TARGET_LEGITIMIZE_ADDRESS 4f07ba8 [2011-04-19 14:30:54 -0500] Tighten up checks on base register validity 731f995 [2011-04-19 13:27:14 -0500] Rework strlenhi 1b0bb04 [2011-04-19 09:27:41 -0500] Review use of vwa predicates in new insn definitions 1f5fd5c [2011-04-19 08:29:15 -0500] Rename predicates associated with volatile work-around 212891e [2011-04-18 10:36:32 -0500] Implement xorm3 5d19c1f [2011-04-18 10:09:09 -0500] Replace iorm3 244b312 [2011-04-18 09:53:07 -0500] Implement andm3 f9ff60d [2011-04-18 08:06:10 -0500] Move validated instructions up in file 2a623d5 [2011-04-18 08:05:46 -0500] Mode-specific condition code iterator macro d832a5d [2011-04-16 21:32:00 -0500] Add unary output support (ones complement, neg expansion) b87855f [2011-04-16 21:16:19 -0500] Correct push/pop length calculations 36f2fdf [2011-04-16 18:38:10 -0500] Eliminate compile-time warnings 5b7f8b4 [2011-04-16 14:41:57 -0500] Use iterator to generate RMW insn patterns 2ac17c0 [2011-04-16 13:47:25 -0500] Calculate default instr_mult from destination mode e08079c [2011-04-16 13:34:32 -0500] Normalize NAND and check resulting lengths 214da4a [2011-04-16 12:55:38 -0500] Combine indirect_jump and verify length calculations 7f4e613 [2011-04-16 12:19:05 -0500] Remove explicit_br 5237148 [2011-04-16 11:59:03 -0500] Remove unused code f3f561b [2011-04-16 11:53:44 -0500] Disallow use of stack or pseudo-registers in non-HImode operations 15a2411 [2011-04-16 11:49:05 -0500] SF 3288235 : clobber in non-move operations 7101e2e [2011-04-16 09:30:11 -0500] Re-optimize frame register adjustments 325baaa [2011-04-15 17:22:42 -0500] Clean up subm3 823391e [2011-04-15 14:21:14 -0500] Remove old addm3 code a508e2a [2011-04-15 13:50:45 -0500] Use iterator to avoid duplicating CG plus-to-minus split 549a067 [2011-04-15 13:44:39 -0500] Use split to detect negative CG matches 9070d43 [2011-04-15 13:20:59 -0500] Update for lengths for addhi3 11c06de [2011-04-15 12:48:49 -0500] Use iterator to define addm3 expansions 43b08b3 [2011-04-15 12:32:26 -0500] Implement swpb as rotate:HI for better optimization b812758 [2011-04-15 04:02:06 -0500] Define SHIFT_COUNT_TRUNCATED e00e7f5 [2011-04-14 14:33:17 -0500] Reduce alternatives in multi-word push operations 91c9f6d [2011-04-14 14:32:44 -0500] pop operands are indirect stack references with side effects c298a78 [2011-04-14 14:13:25 -0500] Normalize order of attributes d4afe8c [2011-04-14 13:47:58 -0500] Handle parallel patterns, adjust delay_cycles builtin c08216c [2011-04-14 13:18:45 -0500] Refine format/length/alternatives for builtins 2e169bf [2011-04-14 13:04:28 -0500] Indirect register as destination requires offset word 95e0c28 [2011-04-14 12:48:29 -0500] Make instruction length based on format, not specific insn 32585d4 [2011-04-14 09:57:01 -0500] Step to refining instruction length calculations b0c3415 [2011-04-15 12:32:26 -0500] Implement swpb as rotate:HI for better optimization 0e7b758 [2011-04-15 04:02:43 -0500] Add a delay_cycles where the constant is not compatible with CG d69a3cf [2011-04-15 16:01:51 -0500] Remove dead dummy updates 4d8b01e [2011-04-15 15:50:28 -0500] Remove unnecessary arguments from msp430_cbranch be559d2 [2011-04-14 17:52:13 -0500] SF 3286842 Compiler stores r2 but does not restore it 4092793 [2011-04-13 18:06:16 -0500] Avoid potentially too strict requirement on index expressions 1a62597 [2011-04-13 18:03:58 -0500] Replace imprecisely named function with new version 6078f25 [2011-04-13 17:55:02 -0500] Provide utility functions to characterize rtx addressing mode a661df5 [2011-04-13 17:31:25 -0500] Eliminate whines from callers using unsigned regnum expressions 17641ef [2011-04-12 15:43:47 -0500] Update for release b4aa2cb [2011-04-12 14:43:03 -0500] SF 3207700 make watchdog optional a32ae89 [2011-04-12 11:14:12 -0500] SF 3237009 default task for main 31da821 [2011-04-12 15:39:54 -0500] Correct mis-use of force_reg d5e6c6d [2011-04-11 13:53:14 -0500] Update for release 512271a [2011-04-11 11:05:12 -0500] Correct another frame/stack misunderstanding 7526887 [2011-04-11 09:18:25 -0500] Improve optimization of zero-extended byte values 4a492a8 [2011-04-11 09:14:41 -0500] Remove extranous space from movhi2 template 56556b7 [2011-04-10 21:31:41 -0500] Correct potential mis-assignment of registers b0cabfe [2011-04-10 21:25:31 -0500] Fix suboptimal register reloading 703a8d0 [2011-04-10 21:19:16 -0500] Make internal functions/data static c40ae95 [2011-04-10 16:47:46 -0500] Avoid abort() in ASM_OUTPUT macros 972c5d5 [2011-04-10 16:46:31 -0500] Use register as more evocative unspecv parameter 2d5b4cd [2011-04-10 16:33:44 -0500] SF 3260589 change frame pointer semantics 9924371 [2011-04-10 10:38:14 -0500] SF 3191622 register use cleanup: SMALL_REGISTER_CLASSES cc2a80e [2011-04-09 19:17:06 -0500] Become much more strict about register uses. cd59dd3 [2011-04-09 18:54:30 -0500] Revert SF 3188386 263c35c [2011-04-09 15:03:48 -0500] Fix wrong operator 2d28aa6c [2011-04-09 13:33:44 -0500] Get rid of unnecessary TFPR (alloca already handled) 3065f10 [2011-04-09 10:47:42 -0500] Rework implementation of critical to avoid RETI 6583166 [2011-04-09 10:16:15 -0500] Minor documentation cleanup 927f4d3 [2011-04-08 21:27:25 -0500] SF 3261372: critical attribute incompatible with -g flag 8cc29a6 [2011-04-08 09:38:52 -0500] SF 3191614: register use cleanup: old constraints c155abc [2011-04-08 08:26:05 -0500] Uniformly use pushm1 insns c04654b [2011-04-07 21:18:44 -0500] Fix problem with pseudo-register assignment 0bd318a [2011-04-07 09:15:04 -0500] Handle SFmode in msp430_mov_noclobber 764d7f5 [2011-04-05 13:47:30 -0500] Use utility function to create offset mem exprs 507ebad [2011-04-05 13:11:42 -0500] Inhibit peephole code when no peepholes defined 5f4f010 [2011-04-05 13:09:19 -0500] Storing into memory cannot clobber registers 2fd1283 [2011-04-05 12:54:38 -0500] Handle interior clobbers b452d9c [2011-04-05 12:47:17 -0500] Implement alternative no-clobber solution 632da2f [2011-04-05 10:09:12 -0500] Use mode iterators to reduce duplication in extend insns d8381a8 [2011-04-05 08:05:06 -0500] Use pushqi1 instead of relaxing constraint on push_operand 7be7f29 [2011-04-05 07:20:57 -0500] Avoid corrupting registers in moves f53a4cd [2011-04-04 22:44:25 -0500] Correct constraint documentation; clobber regs in builtins 2d8a38e [2011-04-04 22:37:04 -0500] Remove some magic numbers 6b77e9a [2011-04-04 22:22:46 -0500] Use a move iterator to handle SF using SI at no extra charge 07b1838 [2011-04-04 22:04:28 -0500] Remove unused code 3fc7864 [2011-04-04 21:53:12 -0500] Add movdi code 5a5e4bc [2011-04-04 21:41:19 -0500] Combine alternatives with same pattern and lengths cd5a82e [2011-04-04 21:27:11 -0500] Implement movsi 7cbd810 [2011-04-04 15:24:18 -0500] Support offset for stack-relative pushes 0071bac [2011-04-04 12:47:03 -0500] Add movhi* 0b2ce1e [2011-04-04 12:46:19 -0500] Disable ADJUST_INSN_LENGTH 1db0967 [2011-04-04 12:22:14 -0500] Incorporate pushqi into movqi handling. bca4d4e [2011-04-04 08:47:25 -0500] Validation of movqi e5ff982 [2011-04-04 08:58:41 -0500] Remove unreferenced sameoperand code (leftover pre extend rewrite) 6ed2af5 [2011-04-04 08:17:28 -0500] Move all peephole definitions to separate file. 77f1c6a [2011-04-03 17:43:29 -0500] Cleanup around extend insns df372c4 [2011-04-03 17:17:33 -0500] Implement zero_extendmn2 sharing extendmn2 code 29099e7 [2011-04-03 16:28:48 -0500] Re-implement sign extension insns (extendmn2) 8ce32c4 [2011-04-03 12:45:56 -0500] Avoid overwrite when r11:di is copied to r12:di f74872c [2011-03-31 15:07:36 -0500] SF 3264484: need naked with stack variables 14f89fa [2011-03-31 14:14:36 -0500] Trivial cleanups 9a3f541 [2011-03-31 09:38:35 -0500] Remove RTX_FRAME_RELATED_P from prologue insns not affecting frame ed80052 [2011-03-30 11:14:56 -0500] Verify critical attribute results in reti 3c63c7f [2011-03-30 09:24:53 -0500] Remove unreferenced variable dcbe77e [2011-03-30 08:55:23 -0500] SF 3257192: obey noreturn a11a4b6 [2011-03-30 08:37:16 -0500] Convert saveprologue elimination to warning 9982fac [2011-03-29 11:46:52 -0500] Remove debug messages 0d370a4 [2011-03-29 10:50:28 -0500] Update for release a72612b [2011-03-29 10:49:11 -0500] SF 3257021, 3257192: function attribute rework 3abb531 [2011-03-28 12:50:38 -0500] Run everything through indent again 091b3d0 [2011-03-28 12:36:12 -0500] SF 3250899: error right shift 32-bit values 64c6735 [2011-03-27 19:33:36 -0500] SF 3250605: error left shift 64-bit values 5a0a5da [2011-03-27 18:58:59 -0500] SF 3250633: error right logical shift 64-bit values 53cbbd9 [2011-03-26 12:43:06 -0500] Reformatting in shift code 96ecb5a [2011-03-26 11:50:34 -0500] Remove uncalled statics, inline uniquely called statics d1dcc05 [2011-03-26 11:42:21 -0500] Remove length calculations in shift operations bb404e2 [2011-03-26 11:02:41 -0500] Clear out more bogus instruction length infrastructure 4e598c6 [2011-03-25 14:07:41 -0500] Partial SF 3244669: remove hard-coded lengths from msp430_name_code 5fef21d [2011-03-25 13:43:40 -0500] Remove patterns which use @Rn+ naturally. c1fbc59 [2011-03-25 12:54:35 -0500] Reduce visibility of utility functions. c42f445 [2011-03-25 12:47:22 -0500] Correct instruction lengths for set expressions in builtins. 3d2dd01 [2011-03-25 11:50:40 -0500] Consistent placement of unspec_volatile on set patterns. a059b93 [2011-03-25 11:50:34 -0500] Eliminate build warnings from use of HOST_WIDE_INT in printf formats 6b16b08 [2011-03-26 07:48:23 -0500] Update version for next release 238764f [2011-03-25 22:00:19 -0500] Fix delay_cycles on CPUXV2 a454332 [2011-03-25 00:36:23 -0500] SF 3237005: add __delay_cycles intrinsic 660b860 [2011-03-24 13:25:27 -0500] Fix varargs problem on 64-bit hosts. c3279c7 [2011-03-22 17:44:06 -0500] Update version for next release 0820353 [2011-03-22 15:25:24 -0500] Remove problematic and unuseful example fd873cf [2011-03-22 10:34:07 -0500] Rename builtin for consistency eea6dd2 [2011-03-21 12:18:51 -0500] Clean up interrupt attribute parameter processing a0beb09 [2011-03-21 11:34:46 -0500] Clean up prototypes/public functions 0875583 [2011-03-21 11:12:57 -0500] Improve validation of naked/task attributes. 1e086ab [2011-03-21 10:19:17 -0500] Check for incompatibility among attribute declarations 240b794 [2011-03-20 15:30:08 -0500] Replace code that detected empty epilogue 6fe5e6c [2011-03-20 14:20:59 -0500] Use flags to specify frame prologue/epilogue actions 3e9047c [2011-03-20 13:05:45 -0500] Disable saveprologue a65f990 [2011-03-20 11:56:58 -0500] Remove unused references to instruction address data 2dbd885 [2011-03-20 11:46:25 -0500] Clean up stack alignment and adjustment for frame size 3a69c2f [2011-03-20 11:16:20 -0500] Regression test for saveprologue. 8973349 [2011-03-20 10:28:23 -0500] Calculate frame-saved register set in one place. f917da2 [2011-03-19 14:22:36 -0500] Use attribute trees instead of booleans to record function attributes ac08763 [2011-03-19 11:00:10 -0500] Make machine_status the ultimate source of function attributes. cdadcad [2011-03-19 10:44:36 -0500] Remove sibcall-related code. a5a0f44 [2011-03-19 09:43:11 -0500] Avoid marking interrupt functions as used until is_interrupt validated. 70197bb [2011-03-19 09:27:31 -0500] Attribute cleanup: consistent format for warning messages 105eb82 [2011-03-19 08:24:40 -0500] Run through indent cd4f3b6 [2011-03-19 08:19:36 -0500] Inline once-called, remove never-called frame handler functions 96d200c [2011-03-16 12:27:20 -0500] Collect function attribute analysis into one place. cfbbf71 [2011-03-16 10:19:49 -0500] Remove unreferenced reserve attribute b950248 [2011-03-15 15:25:22 -0500] SF 3214051: validate is_leaf workaround 8cdad9e [2011-03-14 20:47:40 -0500] Rename function to reflect what it does c657168 [2011-03-14 20:39:28 -0500] Remove -mendup-at and -minit-stack c0d0094 [2011-03-15 13:53:42 -0500] Remove calculation of function prologue/epilogue size. ddae3bc [2011-03-14 19:35:40 -0500] Remove .L__FrameSize/.L__FrameOffset f1f180b [2011-03-15 13:44:02 -0500] Remove GCC_VERSION_INT. 33a486a [2011-03-14 19:24:32 -0500] SF 3195317: clean up -maccumulate-outgoing-args dfdf943 [2011-03-14 13:04:51 -0500] SF 3193396: fix uniarch ctors/dtors 4b859f0 [2011-03-12 15:34:40 -0600] SF 3207046: get rid of jump to main b00681e [2011-03-12 15:21:44 -0600] Recognize that stack pointer may be a 20-bit pointer (not an unsigned int) 04b7030 [2011-03-12 14:48:26 -0600] Correct support for named sections 7856ccc [2011-03-12 11:56:08 -0600] SF 3207853: bad constant extraction on 64-bit systems b4fa76e [2011-03-11 17:40:27 -0600] Mark frame-related instructions b984f27 [2011-03-11 15:26:59 -0600] Inline the inline functions (not shared, no reason to put in separate file) e640bc6 [2011-03-11 15:24:47 -0600] Baby step: remove unused garbage from framehelpers.inl 935d403 [2011-03-11 14:29:23 -0600] SF 3195323: remove -mrtl 1294c59 [2011-03-11 12:08:51 -0600] Unit tests validating SF 3104943 85bd56d [2011-03-11 11:40:16 -0600] SF 3206654: provide facility to identify mspgcc version 39596e3 [2011-03-11 10:15:12 -0600] Implement __builtin_{read,write}_stack_pointer f02889e [2011-03-11 10:05:57 -0600] Implement __bis_status_register 1dfce7c [2011-03-11 09:59:10 -0600] Implement __bic_status_register 34c43ae [2011-03-11 09:47:08 -0600] Implement __write_status_register 4d3889b [2011-03-11 09:24:09 -0600] Stub status-register builtins; implement read e5a7012 [2011-03-11 08:46:24 -0600] SF 3195325: remove -mdeb 7cd7646 [2011-03-11 08:36:42 -0600] SF 3195329: remove -mIAR 5a9c069 [2011-03-06 20:38:53 -0600] SF 3201686: gcc optimizes away static isr 53eb3ab [2011-03-06 20:18:23 -0600] SF 3198920: bi*_sr_irq incorrect a026cc3 [2011-03-05 14:34:35 -0600] SF 3198924: get_frame_address wrong ff69c66 [2011-03-05 13:45:44 -0600] Test builtins for return address and frame address. 537f549 [2011-03-03 15:55:14 -0600] Rework intrinsics that require frame pointers. aafe5cc [2011-03-03 12:44:05 -0600] Cleanup/consistency in nop/eint/dint a5a6811 [2011-03-03 12:31:04 -0600] Clean up bi*_sr_irq builtins. 4af5a14 [2011-03-02 13:39:37 -0600] Add built-ins for nop, eint, dint 1cad52d [2011-03-02 13:19:54 -0600] Unit test for get_frame_address 5e8a925 [2011-03-02 13:19:33 -0600] Refine parameter to builtins df9cf2a [2011-03-02 09:46:35 -0600] Tests for bi[cs]_sr_irq intrinsics 32a021d [2011-03-01 10:18:06 -0600] Generate preprocessor symbols for cpu, mpy, and ivcnt values. 6371377 [2011-02-28 17:20:04 -0600] Clean up built-in declarations. 5813cf3 [2011-02-28 16:49:53 -0600] Remove more magic numbers 67fae96 [2011-02-28 16:31:36 -0600] Clean up built-in RTX expressions. 9d18745 [2011-02-28 16:17:00 -0600] Replace magic numbers with constants from md file 8102441 [2011-02-28 15:54:04 -0600] Eliminate magic numbers for unspec indices 7d5c8f8 [2011-02-27 13:13:11 -0600] Make everything just depend on cpu/mpy/ivcnt 2ce5df8 [2011-02-27 12:53:39 -0600] Enable calculation of proper multilib directory. 81f6003 [2011-02-27 11:50:39 -0600] Correct various problems with multilib specification 9096dee [2011-02-27 10:32:54 -0600] Basic multilib support. 6e41a2b [2011-02-27 09:19:26 -0600] Sort target hooks by manual section 727739a [2011-02-26 13:29:45 -0600] Remove all the declarations by moving the reference to follow the definition 4abff5d [2011-02-26 13:11:55 -0600] Do not presume that c++ is the same as c 600cad3 [2011-02-26 13:11:37 -0600] Put more things back where they belong. bd7b5e8 [2011-02-26 13:02:02 -0600] Remove more unreferenced stuff; keep in the one legitimate one f7a48de [2011-02-26 12:57:52 -0600] Replace unnecessary global macro c23994a [2011-02-26 12:51:19 -0600] Put things where they belong 8f4fefa [2011-02-26 12:18:10 -0600] Go back and do the first subsections of Target Macros cb4494f [2011-02-26 12:02:29 -0600] Move private macro to implementation file; remove outdated comments 30404eb [2011-02-26 11:59:28 -0600] Complete target macros. 8f0e198 [2011-02-26 11:36:50 -0600] Debugging info. 8d1c576 [2011-02-26 11:25:47 -0600] Complete Assembler Format 909929d [2011-02-26 11:18:14 -0600] Instruction output 4bde3c0 [2011-02-26 11:03:54 -0600] Macros for initialization 7332c83 [2011-02-26 11:00:51 -0600] Initialization 6ff0a5d [2011-02-26 11:00:43 -0600] Correct function name; add documentation removed from libgcc.S 4b07834 [2011-02-26 11:00:16 -0600] Remove material now located in crt0.S f601076 [2011-02-25 16:04:32 -0600] Data and label output 4bc8c86 [2011-02-25 15:20:25 -0600] Reverse incorrect code standard change. 3be4849 [2011-02-25 15:10:18 -0600] Move hook to msp430.c; do 17.21.2 Data Output 405c77e [2011-02-25 14:56:42 -0600] Remove outdated/unreferenced asm_output_* functions b1f3392 [2011-02-25 14:40:03 -0600] Sections 257efb3 [2011-02-25 14:19:26 -0600] Costs and scheduling c9f5a9d [2011-02-25 13:58:35 -0600] Condition codes. 7a283c2 [2011-02-25 13:37:54 -0600] Run things through indent again e45d06f [2011-02-25 13:33:00 -0600] Replace GO_IF_LEGITIMATE_ADDRESS with target hook 213ce55 [2011-02-25 13:20:44 -0600] Cleanup varargs, trampolines, library calls, addressing modes d32099b [2011-02-25 10:14:15 -0600] Minor cleanup d93445d [2011-02-25 09:33:21 -0600] Complete review of msp430.h for 17.10 Stack and Calling c801827 [2011-02-25 09:19:37 -0600] 17.10.7 Register Arguments 6555205 [2011-02-25 08:55:15 -0600] 17.10.6 Stack Arguments 1f2ccd3 [2011-02-25 08:45:07 -0600] Stack/call up to 17.10.6 cd569f1 [2011-02-24 15:31:31 -0600] Review 17.8 and 17.9 (register classes and outdated constraints) ef9e05c [2011-02-24 14:38:22 -0600] Review 17.7 Registers c3beb73 [2011-02-24 13:31:06 -0600] Clean up section 17.6 Layout of Source Language Data Types 99fc7e4 [2011-02-24 13:08:51 -0600] Review and cleanup storage-related target data acfd4e4 [2011-02-24 12:14:53 -0600] Consistent names for macros related to register returns 3adeb1d [2011-02-21 12:23:03 -0600] Convert LIBCALL_VALUE to target hook. a98a5e7 [2011-02-21 12:07:03 -0600] SF 3188386: inefficient struct return convention 46f8277 [2011-02-21 11:52:13 -0600] Convert FUNCTION_VALUE to target hook 7689eb5 [2011-02-21 10:58:45 -0600] Remove STRUCT_VALUE macro. 94fccc8 [2011-02-21 10:55:06 -0600] Convert RETURN_IN_MEMORY to target hook feee18d [2011-02-21 10:54:24 -0600] Correct target macro selection d230668 [2011-02-10 09:04:44 -0600] Remove multilib and default mcu 7d72ab9 [2011-02-07 09:59:05 -0600] Emit cpu and mpy in generated assembly source 634cd52 [2011-02-24 11:52:32 -0600] Reduce check to accommodate gcc 4.5 limitation. 669ba0c [2011-02-21 03:46:48 -0600] Test case for PR middle-end/42722 (SF 3148801) d6772e6 [2011-02-20 12:18:35 -0600] Test case for SF 3177314 951a044 [2011-02-20 11:39:38 -0600] Test case for SF 3112089 78fbbf0 [2011-02-19 16:14:12 -0600] Infrastructure for dejagnu autotests. ebd6be7 [2011-02-24 09:47:54 -0600] Remove hard-coded MCU-specific information from msp430 port. a13c84e [2011-01-01 19:51:09 -0600] Decouple front-end dependencies from target. b2accf6 [2011-01-01 15:10:24 -0600] Update trampoline interface to current GCC implementation. de467e5 [2011-01-01 14:46:49 -0600] Remove CAN_ELIMINATE. 50fd87a [2011-01-01 14:39:16 -0600] Update frame pointer support to current GCC implementation. 63cb597 [2011-01-01 14:25:04 -0600] Update for cond-optab branch. 2354f1f [2011-01-01 13:46:09 -0600] Remove poisoned LEGITIMIZE_ADDRESS. 6cf95dd [2011-01-01 13:41:09 -0600] Correct placement of GC marker 03a9106 [2011-01-01 12:22:52 -0600] Avoid reference to uninitialized operands. 36b4cae [2011-01-01 12:21:13 -0600] Fix mis-use of MEM_VOLATILE_P. 4c59517 [2010-12-31 18:43:31 -0600] Run through indent again cba5a77 [2010-11-14 10:11:57 -0600] SF 3109143: Support value-line MSP430G22x1 devices 5092e93 [2010-08-29 13:10:46 -0500] SF 3055519: add support for 55xx chips 526fee6 [2010-08-29 10:45:10 -0500] Provide machine mode for certain constant integer operands. 7401fc6 [2010-08-29 10:22:54 -0500] SF 3055171: ICE in trunc_int_for_mode d7d7602 [2010-11-19 14:50:58 -0600] SF 3112089: improper elimination of condition code set 1b0f6ad [2010-11-06 14:58:21 -0500] SF 3090574: -fPIC silently won't work d89c540 [2010-08-15 08:58:26 -0500] Correct function prototype 735355e [2010-08-14 21:57:21 -0500] Down to one last warning that I plan to ignore for now d2104bf [2010-08-14 21:45:10 -0500] C++ comments, format spec, const and signed qualifiers 4b508e3 [2010-08-14 21:36:00 -0500] Remove invalid comma, fix function declarations acc8075 [2010-08-14 21:23:20 -0500] Eliminate warnings about C++ comments, mixed code/decl, unused variable d0d36e1 [2010-08-14 21:12:01 -0500] Run through indent again 03bff4b [2010-08-14 21:11:32 -0500] Remove old-style definitions 136e923 [2010-08-14 20:36:44 -0500] Remove PARAMS wrappers, re-run indent. 3785875 [2010-08-14 20:27:26 -0500] Run everything through GNU indent version 2.2.10. 7ba79e4 [2010-07-16 19:00:47 -0500] Merge branch 'msp430' into dev/4.4.4 95b0112 [2010-07-16 18:11:23 -0500] Avoid dereferencing SET_SRC if instruction is not SET. 8288f6e [2010-05-27 14:19:20 -0500] Correct chip name 9da84ee [2010-05-20 19:17:08 +0000] Add file missed in commit 133 1b52f5f [2010-05-20 19:04:47 +0000] Revise generic categorization to match binutils and support new architectures. 2de401c [2010-02-15 21:26:05 -0700] Revise generic categorization to match binutils and support new architectures. f7a3ca5 [2010-02-09 21:58:10 +0000] Integrated cc430 patches 4681bf9 [2010-02-03 09:53:20 +0000] Fixed incorrect stack allocation in main() 8efbb4c [2010-01-24 17:23:32 +0000] Improved MinGW compatibility ed54f2c [2010-01-14 13:09:59 +0000] Fixed 'critical' and 'reentrant' attributes. 0cbc9ff [2010-01-14 11:58:49 +0000] Added patch for gcc 4.4.2 fixing incorrect structure pushing Fixed incorrect "call offset(sp)" instruction generation and simulation Fixed incorrect prologue generation for function with stack frame pointer caused by stack arguments and without local variables b596201 [2009-12-23 14:37:11 +0000] Fixed frame structure generation 14dc41f [2009-12-19 11:07:46 +0000] Fixed the cc1 crash when a "push SP" instruction was generated. Eliminated the need to use R5 as an argument pointer. Added experimental support for -maccumulate-outgoing-args fb8c53c [2009-11-21 19:30:36 +0000] Added full support for DWARF2 frame info and epilogue-based unwinder. 2d439aa [2009-11-21 14:57:38 +0000] Upgraded prologue/epilogue generation to INSN-level interface. Added support for DWARF2 frame unwind info generation. df2957c [2009-11-03 15:21:55 +0000] Fixed ret/reti bug a0c7049 [2009-11-03 12:45:40 +0000] git-svn-id: http://mspgcc4.svn.sourceforge.net/svnroot/mspgcc4@25 9c79f009-54bf-40f1-a1dd-edde5f34ab85 716d2c5 [2009-10-25 12:24:55 +0000] Temporary disabled incomplete DWARF2 unwind info generation 710a650 [2009-10-24 20:56:37 +0000] git-svn-id: http://mspgcc4.svn.sourceforge.net/svnroot/mspgcc4@16 9c79f009-54bf-40f1-a1dd-edde5f34ab85 236305a [2009-10-24 20:41:22 +0000] Added unwind info generation flag f948168 [2009-10-24 19:14:13 +0000] Added full support for GDB 6.8 and 7.0 Added support for GCC 4.4.2 e72d34a [2009-10-01 10:49:22 +0000] Updated copyright notes d730759 [2009-09-08 14:21:29 +0000] Initial version diff --git gcc-4.7.0.orig/configure gcc-4.7.0/configure index 9136c24..60a502e 100755 --- gcc-4.7.0.orig/configure +++ gcc-4.7.0/configure @@ -3546,6 +3546,9 @@ case "${target}" in mmix-*-*) noconfigdirs="$noconfigdirs gdb" ;; + msp430-*-*) + noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj} target-libssp" + ;; mt-*-*) noconfigdirs="$noconfigdirs sim" ;; diff --git gcc-4.7.0.orig/configure.ac gcc-4.7.0/configure.ac index 92e6db3..d4bfa8a 100644 --- gcc-4.7.0.orig/configure.ac +++ gcc-4.7.0/configure.ac @@ -972,6 +972,9 @@ case "${target}" in mmix-*-*) noconfigdirs="$noconfigdirs gdb" ;; + msp430-*-*) + noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj} target-libssp" + ;; mt-*-*) noconfigdirs="$noconfigdirs sim" ;; diff --git gcc-4.7.0.orig/gcc/DEV-PHASE gcc-4.7.0/gcc/DEV-PHASE index e69de29..9d0a73c 100644 --- gcc-4.7.0.orig/gcc/DEV-PHASE +++ gcc-4.7.0/gcc/DEV-PHASE @@ -0,0 +1 @@ +mspgcc dev 20120911 diff --git gcc-4.7.0.orig/gcc/alias.c gcc-4.7.0/gcc/alias.c index e9d701f..e058b9f 100644 --- gcc-4.7.0.orig/gcc/alias.c +++ gcc-4.7.0/gcc/alias.c @@ -1131,7 +1131,7 @@ find_base_value (rtx src) /* As we do not know which address space the pointer is refering to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ - if (!target_default_pointer_address_modes_p ()) + if (!targetm.default_pointer_address_modes_p ()) break; if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode)) break; @@ -1150,7 +1150,7 @@ find_base_value (rtx src) /* As we do not know which address space the pointer is refering to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ - if (!target_default_pointer_address_modes_p ()) + if (!targetm.default_pointer_address_modes_p ()) break; { @@ -1557,7 +1557,7 @@ find_base_term (rtx x) /* As we do not know which address space the pointer is refering to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ - if (!target_default_pointer_address_modes_p ()) + if (!targetm.default_pointer_address_modes_p ()) return 0; if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode)) return 0; @@ -1576,7 +1576,7 @@ find_base_term (rtx x) /* As we do not know which address space the pointer is refering to, we can handle this only if the target does not support different pointer or address modes depending on the address space. */ - if (!target_default_pointer_address_modes_p ()) + if (!targetm.default_pointer_address_modes_p ()) return 0; { diff --git gcc-4.7.0.orig/gcc/auto-inc-dec.c gcc-4.7.0/gcc/auto-inc-dec.c index 1c9edf8..89e4556 100644 --- gcc-4.7.0.orig/gcc/auto-inc-dec.c +++ gcc-4.7.0/gcc/auto-inc-dec.c @@ -1091,9 +1091,8 @@ find_inc (bool first_try) we are going to increment the result of the add insn. For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ - addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); if (GET_MODE (inc_insn.reg_res) - != targetm.addr_space.address_mode (as)) + != MEM_ADDRESS_MODE (*mem_insn.mem_loc)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); @@ -1142,9 +1141,8 @@ find_inc (bool first_try) { /* For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ - addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); if (GET_MODE (inc_insn.reg_res) - != targetm.addr_space.address_mode (as)) + != MEM_ADDRESS_MODE (*mem_insn.mem_loc)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); diff --git gcc-4.7.0.orig/gcc/builtins.c gcc-4.7.0/gcc/builtins.c index a086a8c..9abd37e 100644 --- gcc-4.7.0.orig/gcc/builtins.c +++ gcc-4.7.0/gcc/builtins.c @@ -1674,12 +1674,6 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) /* All arguments and registers used for the call are set up by now! */ function = prepare_call_address (NULL, function, NULL, &call_fusage, 0, 0); - /* Ensure address is valid. SYMBOL_REF is already valid, so no need, - and we don't want to load it into a register as an optimization, - because prepare_call_address already did it if it should be done. */ - if (GET_CODE (function) != SYMBOL_REF) - function = memory_address (FUNCTION_MODE, function); - /* Generate the actual call instruction and save the return value. */ #ifdef HAVE_untyped_call if (HAVE_untyped_call) diff --git gcc-4.7.0.orig/gcc/c-family/c-common.c gcc-4.7.0/gcc/c-family/c-common.c index 1d19251..3e354af 100644 --- gcc-4.7.0.orig/gcc/c-family/c-common.c +++ gcc-4.7.0/gcc/c-family/c-common.c @@ -2818,6 +2818,12 @@ check_case_bounds (tree type, tree orig_type, tree c_common_type_for_size (unsigned int bits, int unsignedp) { + tree type; + + type = targetm.c_common_type_for_size (bits, unsignedp); + if (type) + return type; + if (bits == TYPE_PRECISION (integer_type_node)) return unsignedp ? unsigned_type_node : integer_type_node; @@ -3118,6 +3124,10 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type) { tree type1; + type1 = targetm.c_common_signed_or_unsigned_type (unsignedp, type); + if (type1) + return type1; + /* This block of code emulates the behavior of the old c_common_unsigned_type. In particular, it returns long_unsigned_type_node if passed a long, even when a int would @@ -5057,8 +5067,10 @@ c_common_nodes_and_builtins (void) default_function_type = build_varargs_function_type_list (integer_type_node, NULL_TREE); - ptrdiff_type_node - = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE))); + ptrdiff_type_node = targetm.ptrdiff_type_tree(); + if (!ptrdiff_type_node) + ptrdiff_type_node + = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE))); unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node); lang_hooks.decls.pushdecl @@ -6589,10 +6601,9 @@ handle_mode_attribute (tree *node, tree name, tree args, if (POINTER_TYPE_P (type)) { - addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); tree (*fn)(tree, enum machine_mode, bool); - if (!targetm.addr_space.valid_pointer_mode (mode, as)) + if (!targetm.type_valid_pointer_mode (mode, TREE_TYPE (type))) { error ("invalid pointer mode %qs", p); return NULL_TREE; diff --git gcc-4.7.0.orig/gcc/c-family/c-cppbuiltin.c gcc-4.7.0/gcc/c-family/c-cppbuiltin.c index 608dba6..3af6f5b 100644 --- gcc-4.7.0.orig/gcc/c-family/c-cppbuiltin.c +++ gcc-4.7.0/gcc/c-family/c-cppbuiltin.c @@ -1211,6 +1211,9 @@ builtin_define_type_minmax (const char *min_macro, const char *max_macro, char *buf; size_t idx; + if (targetm.cpp_builtin_define_type_minmax (min_macro, max_macro, type)) + return; + /* Pre-rendering the values mean we don't have to futz with printing a multi-word decimal value. There are also a very limited number of precisions that we support, so it's really a waste of time. */ diff --git gcc-4.7.0.orig/gcc/calls.c gcc-4.7.0/gcc/calls.c index 19b2bfa..527ce0c 100644 --- gcc-4.7.0.orig/gcc/calls.c +++ gcc-4.7.0/gcc/calls.c @@ -169,21 +169,24 @@ rtx prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value, rtx *call_fusage, int reg_parm_seen, int sibcallp) { - /* Make a valid memory address and copy constants through pseudo-regs, - but not for a constant address if -fno-function-cse. */ - if (GET_CODE (funexp) != SYMBOL_REF) - /* If we are using registers for parameters, force the - function address into a register now. */ - funexp = ((reg_parm_seen - && targetm.small_register_classes_for_mode_p (FUNCTION_MODE)) - ? force_not_mem (memory_address (FUNCTION_MODE, funexp)) - : memory_address (FUNCTION_MODE, funexp)); - else if (! sibcallp) + if (GET_MODE (funexp) != FUNCTION_MODE) { + /* Make a valid memory address and copy constants through pseudo-regs, + but not for a constant address if -fno-function-cse. */ + if (GET_CODE (funexp) != SYMBOL_REF) + /* If we are using registers for parameters, force the + function address into a register now. */ + funexp = ((reg_parm_seen + && targetm.small_register_classes_for_mode_p (FUNCTION_MODE)) + ? force_not_mem (memory_address (FUNCTION_MODE, funexp)) + : memory_address (FUNCTION_MODE, funexp)); + else if (! sibcallp) + { #ifndef NO_FUNCTION_CSE - if (optimize && ! flag_no_function_cse) - funexp = force_reg (Pmode, funexp); + if (optimize && ! flag_no_function_cse) + funexp = force_reg (FUNCTION_MODE, funexp); #endif + } } if (static_chain_value != 0) @@ -264,12 +267,6 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU n_popped += CALL_POPS_ARGS (*get_cumulative_args (args_so_far)); #endif - /* Ensure address is valid. SYMBOL_REF is already valid, so no need, - and we don't want to load it into a register as an optimization, - because prepare_call_address already did it if it should be done. */ - if (GET_CODE (funexp) != SYMBOL_REF) - funexp = memory_address (FUNCTION_MODE, funexp); - funmem = gen_rtx_MEM (FUNCTION_MODE, funexp); if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL) { diff --git gcc-4.7.0.orig/gcc/cfgexpand.c gcc-4.7.0/gcc/cfgexpand.c index bde15f6..daccccb 100644 --- gcc-4.7.0.orig/gcc/cfgexpand.c +++ gcc-4.7.0/gcc/cfgexpand.c @@ -2616,6 +2616,8 @@ expand_debug_expr (tree exp) enum machine_mode inner_mode = VOIDmode; int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp)); addr_space_t as; + enum machine_mode pointer_mode; + enum machine_mode address_mode; switch (TREE_CODE_CLASS (TREE_CODE (exp))) { @@ -2851,12 +2853,20 @@ expand_debug_expr (tree exp) } if (POINTER_TYPE_P (TREE_TYPE (exp))) - as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + { + tree to_type = TREE_TYPE (TREE_TYPE (exp)); + as = TYPE_ADDR_SPACE (to_type); + pointer_mode = targetm.type_pointer_mode (to_type); + address_mode = targetm.type_address_mode (to_type); + } else - as = ADDR_SPACE_GENERIC; + { + as = ADDR_SPACE_GENERIC; + pointer_mode = targetm.addr_space.pointer_mode (as); + address_mode = targetm.addr_space.address_mode (as); + } - op0 = convert_debug_memory_address (targetm.addr_space.address_mode (as), - op0, as); + op0 = convert_debug_memory_address (address_mode, op0, as); if (op0 == NULL_RTX) return NULL; @@ -2866,6 +2876,7 @@ expand_debug_expr (tree exp) && !is_gimple_mem_ref_addr (TREE_OPERAND (exp, 0))) set_mem_expr (op0, NULL_TREE); set_mem_addr_space (op0, as); + set_mem_pointer_address_modes (op0, pointer_mode, address_mode); return op0; @@ -2880,12 +2891,20 @@ expand_debug_expr (tree exp) return NULL; if (POINTER_TYPE_P (TREE_TYPE (exp))) - as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + { + tree to_type = TREE_TYPE (TREE_TYPE (exp)); + as = TYPE_ADDR_SPACE (to_type); + pointer_mode = targetm.type_pointer_mode (to_type); + address_mode = targetm.type_address_mode (to_type); + } else - as = ADDR_SPACE_GENERIC; + { + as = ADDR_SPACE_GENERIC; + pointer_mode = targetm.addr_space.pointer_mode (as); + address_mode = targetm.addr_space.address_mode (as); + } - op0 = convert_debug_memory_address (targetm.addr_space.address_mode (as), - op0, as); + op0 = convert_debug_memory_address (address_mode, op0, as); if (op0 == NULL_RTX) return NULL; @@ -2893,6 +2912,7 @@ expand_debug_expr (tree exp) set_mem_attributes (op0, exp, 0); set_mem_addr_space (op0, as); + set_mem_pointer_address_modes (op0, pointer_mode, address_mode); return op0; diff --git gcc-4.7.0.orig/gcc/combine.c gcc-4.7.0/gcc/combine.c index d06de040..40a83f6 100644 --- gcc-4.7.0.orig/gcc/combine.c +++ gcc-4.7.0/gcc/combine.c @@ -4607,8 +4607,7 @@ find_split_point (rtx *loc, rtx insn, bool set_src) if (GET_CODE (XEXP (x, 0)) == CONST || GET_CODE (XEXP (x, 0)) == SYMBOL_REF) { - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + enum machine_mode address_mode = MEM_ADDRESS_MODE (x); SUBST (XEXP (x, 0), gen_rtx_LO_SUM (address_mode, diff --git gcc-4.7.0.orig/gcc/common/config/msp430/msp430-common.c gcc-4.7.0/gcc/common/config/msp430/msp430-common.c new file mode 100644 index 0000000..516cfe6 --- /dev/null +++ gcc-4.7.0/gcc/common/config/msp430/msp430-common.c @@ -0,0 +1,39 @@ +/* Common hooks for TI MSP430. + Copyright (C) 2012 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "common/common-target.h" +#include "common/common-target-def.h" + +/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ +static const struct default_options msp430_option_optimization_table[] = { + {OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1}, + {OPT_LEVELS_NONE, 0, NULL, 0} +}; + +#undef TARGET_OPTION_OPTIMIZATION_TABLE +#define TARGET_OPTION_OPTIMIZATION_TABLE msp430_option_optimization_table + +#undef TARGET_EXCEPT_UNWIND_INFO +#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info + +struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; diff --git gcc-4.7.0.orig/gcc/config.gcc gcc-4.7.0/gcc/config.gcc index 8b837b3..e8ea9d8 100644 --- gcc-4.7.0.orig/gcc/config.gcc +++ gcc-4.7.0/gcc/config.gcc @@ -939,6 +939,14 @@ avr-*-*) extra_gcc_objs="driver-avr.o avr-devices.o" extra_objs="avr-devices.o avr-log.o" ;; +msp430-*-*) + tm_file="elfos.h msp430/msp430.h dbxelf.h" + tmake_file=msp430/t-msp430 + extra_gcc_objs="msp430-gcc.o" + extra_objs="msp430-builtins.o msp430-function.o" + c_target_objs="msp430-c.o" + cxx_target_objs="msp430-c.o" + ;; bfin*-elf*) tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h bfin/elf.h" tmake_file=bfin/t-bfin-elf diff --git gcc-4.7.0.orig/gcc/config/avr/avr.c gcc-4.7.0/gcc/config/avr/avr.c index 7ead6f4..df9d740 100644 --- gcc-4.7.0.orig/gcc/config/avr/avr.c +++ gcc-4.7.0/gcc/config/avr/avr.c @@ -9869,6 +9869,9 @@ avr_emit_movmemhi (rtx *xop) } set_mem_addr_space (SET_SRC (XVECEXP (insn, 0, 0)), as); + set_mem_pointer_address_modes (SET_SRC (XVECEXP (insn, 0, 0)), + targetm.addr_space.pointer_mode(as), + targetm.addr_space.address_mode(as)); emit_insn (insn); return true; diff --git gcc-4.7.0.orig/gcc/config/avr/avr.md gcc-4.7.0/gcc/config/avr/avr.md index 5cc3e3e..23aaa68 100644 --- gcc-4.7.0.orig/gcc/config/avr/avr.md +++ gcc-4.7.0/gcc/config/avr/avr.md @@ -376,6 +376,9 @@ operands[2] = force_operand (XEXP (operands[1], 0), NULL_RTX); operands[1] = replace_equiv_address (operands[1], operands[3]); set_mem_addr_space (operands[1], ADDR_SPACE_FLASH); + set_mem_pointer_address_modes (operands[1], + targetm.addr_space.pointer_mode(ADDR_SPACE_FLASH), + targetm.addr_space.address_mode(ADDR_SPACE_FLASH)); }) (define_insn "load__libgcc" @@ -414,7 +417,10 @@ insn = emit_insn (gen_xload_8 (operands[0], hi8)); set_mem_addr_space (SET_SRC (single_set (insn)), - MEM_ADDR_SPACE (operands[1])); + MEM_ADDR_SPACE (operands[1])); + set_mem_pointer_address_modes (SET_SRC (single_set (insn)), + MEM_POINTER_MODE (operands[1]), + MEM_ADDRESS_MODE (operands[1])); DONE; }) @@ -433,7 +439,6 @@ rtx addr = XEXP (operands[1], 0); rtx reg_z = gen_rtx_REG (HImode, REG_Z); rtx addr_hi8 = simplify_gen_subreg (QImode, addr, PSImode, 2); - addr_space_t as = MEM_ADDR_SPACE (operands[1]); rtx insn; /* Split the address to R21:Z */ @@ -442,7 +447,10 @@ /* Load with code from libgcc */ insn = emit_insn (gen_xload__libgcc ()); - set_mem_addr_space (SET_SRC (single_set (insn)), as); + set_mem_addr_space (SET_SRC (single_set (insn)), MEM_ADDR_SPACE (operands[1])); + set_mem_pointer_address_modes (SET_SRC (single_set (insn)), + MEM_POINTER_MODE (operands[1]), + MEM_ADDRESS_MODE (operands[1])); /* Move to destination */ emit_move_insn (operands[0], gen_rtx_REG (mode, 22)); diff --git gcc-4.7.0.orig/gcc/config/msp430/constraints.md gcc-4.7.0/gcc/config/msp430/constraints.md new file mode 100644 index 0000000..c50de3f --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/constraints.md @@ -0,0 +1,86 @@ +;; -*- Mode: Scheme -*- +;; Constraint definitions for Texas Instruments MSP430. +;; Copyright (C) 2011 Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;; Available letters: +;;; ABCD GHIJK O Z +;;; abcdef h jkl q t v x +;;; (nb: generic used are EFVXgimnoprs) + +;; Note that the hard frame pointer is also a general register. + +(define_register_constraint "z" "PC_REG" + "Program counter r0") + +(define_register_constraint "y" "SP_REG" + "Stack pointer r1") + +(define_register_constraint "Y" "GENERAL_SP_REGS" + "Union of r (GENERAL), y (SP)") + +(define_register_constraint "w" "SR_REG" + "Status register r2") + +(define_register_constraint "W" "GENERAL_SR_REGS" + "Union of r (GENERAL), w (SR)") + +(define_register_constraint "u" "FIXED_PSEUDO_REGS" + "Fixed pseudo-register (argp, soft fp)") + +(define_register_constraint "U" "FIXED_PSEUDO_GENERAL_SP_REGS" + "Union of u (FIXED PSEUDO), r (GENERAL), y (SP)") + +(define_constraint "R" + "Indirect register @rN (general or stack pointer)" + (match_test "msp430_indirect_register_operand (op)")) + +(define_constraint "S" + "Indirect stack pointer @r2" + (match_test "msp430_indirect_register_operand (op) && REGNO (XEXP (op, 0)) == STACK_POINTER_REGNUM")) + +(define_constraint "T" + "Indexed stack pointer X(r2)" + (match_test "msp430_indexed_register_operand (op) && REGNO (XEXP (XEXP (op, 0), 0)) == STACK_POINTER_REGNUM")) + +(define_constraint "M" + "CPUX and integer constant suitable for multi-position shift operations" + (and (match_code "const_int") + (match_test "TARGET_CPUX && MSP430_CPUX_MULTISHIFT_COUNT_P(ival)"))) + +(define_constraint "Q" + "Post-increment memory reference" + (and (match_code "mem") + (match_code "post_inc" "0") + (match_code "reg" "00"))) + +(define_constraint "L" + "Constant between 1 and 16 inclusive (for repeat count in CPUX extension word)" + (and (match_code "const_int") + (match_test "TARGET_CPUX && MSP430_CPUX_REPEAT_COUNT_P(ival)"))) + +(define_constraint "N" + "General purpose register number as integer constant " + (and (match_code "const_int") + (match_test "(MSP430_MIN_GENERAL_REGNUM <= ival) && (ival <= MSP430_MAX_GENERAL_REGNUM)"))) + +(define_constraint "P" + "Integer constant supported by constant generator registers" + (and (match_code "const_int") + (match_test "(ival == -1 || ival == 0 || ival == 1 || ival == 2 || ival == 4 || ival == 8)"))) + diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-builtins.c gcc-4.7.0/gcc/config/msp430/msp430-builtins.c new file mode 100644 index 0000000..e1b896d --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-builtins.c @@ -0,0 +1,483 @@ +/* This work is partially financed by the European Commission under the +* Framework 6 Information Society Technologies Project +* "Wirelessly Accessible Sensor Populations (WASP)". +*/ + +/* +GCC 4.x port by Ivan Shcherbakov +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "tree.h" +#include "output.h" +#include "expr.h" +#include "toplev.h" +#include "obstack.h" +#include "function.h" +#include "recog.h" +#include "tm_p.h" +#include "target.h" +#include "target-def.h" +#include "insn-codes.h" +#include "ggc.h" +#include "langhooks.h" +#include "rtl-error.h" + +/* The following functions are defined in this file and used by msp430.c */ +void msp430_init_builtins (void); +rtx msp430_expand_builtin (tree, rtx, rtx, enum machine_mode, int); + +enum msp430_builtins +{ + MSP430_BUILTIN_NOP, + MSP430_BUILTIN_DINT, + MSP430_BUILTIN_EINT, + MSP430_BUILTIN_READ_STATUS_REGISTER, + MSP430_BUILTIN_WRITE_STATUS_REGISTER, + MSP430_BUILTIN_BIC_STATUS_REGISTER, + MSP430_BUILTIN_BIS_STATUS_REGISTER, + MSP430_BUILTIN_BIC_SR_IRQ, + MSP430_BUILTIN_BIS_SR_IRQ, + MSP430_BUILTIN_READ_STACK_POINTER, + MSP430_BUILTIN_WRITE_STACK_POINTER, + MSP430_BUILTIN_DELAY_CYCLES, + MSP430_BUILTIN_GET_INTERRUPT_STATE, + MSP430_BUILTIN_SET_INTERRUPT_STATE, + MSP430_BUILTIN_SWAP_BYTES, + MSP430_BUILTIN_GET_WATCHDOG_CLEAR_VALUE, + MSP430_BUILTIN_SET_WATCHDOG_CLEAR_VALUE, + MSP430_BUILTIN_WATCHDOG_CLEAR, + MSP430_BUILTIN_EVEN_IN_RANGE, + MSP430_BUILTIN_last_enum +}; + +void +msp430_init_builtins (void) +{ + gcc_assert (PSImode == TYPE_MODE (msp430_a20_integer_type_node)); + (*lang_hooks.types.register_builtin_type) (msp430_a20_integer_type_node, + "__int20"); + gcc_assert (PSImode == TYPE_MODE (msp430_a20_unsigned_type_node)); + (*lang_hooks.types.register_builtin_type) (msp430_a20_unsigned_type_node, + "__uint20"); + add_builtin_function ("__nop", + build_function_type_list (void_type_node, NULL_TREE), + MSP430_BUILTIN_NOP, BUILT_IN_MD, NULL, NULL_TREE); + add_builtin_function ("__dint", + build_function_type_list (void_type_node, NULL_TREE), + MSP430_BUILTIN_DINT, BUILT_IN_MD, NULL, NULL_TREE); + add_builtin_function ("__eint", + build_function_type_list (void_type_node, NULL_TREE), + MSP430_BUILTIN_EINT, BUILT_IN_MD, NULL, NULL_TREE); + add_builtin_function ("__read_status_register", + build_function_type_list (unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_READ_STATUS_REGISTER, BUILT_IN_MD, + NULL, NULL_TREE); + add_builtin_function ("__get_interrupt_state", + build_function_type_list (unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_GET_INTERRUPT_STATE, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__write_status_register", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_WRITE_STATUS_REGISTER, BUILT_IN_MD, + NULL, NULL_TREE); + add_builtin_function ("__bic_status_register", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_BIC_STATUS_REGISTER, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__bis_status_register", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_BIS_STATUS_REGISTER, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__set_interrupt_state", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_SET_INTERRUPT_STATE, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__bic_status_register_on_exit", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_BIC_SR_IRQ, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__bis_status_register_on_exit", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_BIS_SR_IRQ, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__read_stack_pointer", + build_function_type_list (ptr_type_node, NULL_TREE), + MSP430_BUILTIN_READ_STACK_POINTER, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__write_stack_pointer", + build_function_type_list (void_type_node, + ptr_type_node, NULL_TREE), + MSP430_BUILTIN_WRITE_STACK_POINTER, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__delay_cycles", + build_function_type_list (void_type_node, + long_unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_DELAY_CYCLES, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__swap_bytes", + build_function_type_list (unsigned_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_SWAP_BYTES, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__get_watchdog_clear_value", + build_function_type_list (unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_GET_WATCHDOG_CLEAR_VALUE, BUILT_IN_MD, + NULL, NULL_TREE); + add_builtin_function ("__set_watchdog_clear_value", + build_function_type_list (void_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_SET_WATCHDOG_CLEAR_VALUE, BUILT_IN_MD, + NULL, NULL_TREE); + add_builtin_function ("__watchdog_clear", + build_function_type_list (void_type_node, NULL_TREE), + MSP430_BUILTIN_WATCHDOG_CLEAR, BUILT_IN_MD, NULL, + NULL_TREE); + add_builtin_function ("__even_in_range", + build_function_type_list (unsigned_type_node, + unsigned_type_node, + unsigned_type_node, + NULL_TREE), + MSP430_BUILTIN_EVEN_IN_RANGE, BUILT_IN_MD, + NULL, NULL_TREE); +} + +rtx +msp430_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + rtx arg = 0; + rtx retval = 0; + rtx deref_stack_sr = 0; + rtx insn = 0; + bool need_insn = true; + tree fndecl; + enum msp430_builtins builtin_code; + struct machine_function *mfp = cfun->machine; + + fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + builtin_code = (enum msp430_builtins) DECL_FUNCTION_CODE (fndecl); + + if (builtin_code == MSP430_BUILTIN_BIC_SR_IRQ + || builtin_code == MSP430_BUILTIN_BIS_SR_IRQ) + { + if (mfp->interrupt == NULL_TREE) + error + ("__bi%c_status_register_on_exit invalid outside of function with interrupt attribute", + (builtin_code == MSP430_BUILTIN_BIC_SR_IRQ) ? 'c' : 's'); + /* If we used hard_frame_pointer_rtx here, which would be right, + we'd end up setting frame_pointer_required even if it isn't. + So use arg_pointer_rtx offset by the two words pushed by the + interrupt. */ + deref_stack_sr = + gen_rtx_MEM (HImode, + plus_constant (arg_pointer_rtx, -2 * UNITS_PER_WORD)); + } + + switch (builtin_code) + { + default: + break; + case MSP430_BUILTIN_NOP: + insn = gen_nop (); + break; + case MSP430_BUILTIN_DINT: + emit_insn (gen_dint ()); + insn = gen_nop (); + break; + case MSP430_BUILTIN_EINT: + insn = gen_eint (); + break; + case MSP430_BUILTIN_READ_STATUS_REGISTER: + retval = gen_reg_rtx (HImode); + insn = gen_read_status_register (retval); + break; + case MSP430_BUILTIN_WRITE_STATUS_REGISTER: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_write_status_register (arg); + break; + case MSP430_BUILTIN_GET_INTERRUPT_STATE: + retval = gen_reg_rtx (HImode); + insn = gen_get_interrupt_state (retval); + break; + case MSP430_BUILTIN_BIC_STATUS_REGISTER: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_bic_status_register (arg); + break; + case MSP430_BUILTIN_BIS_STATUS_REGISTER: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_bis_status_register (arg); + break; + case MSP430_BUILTIN_SET_INTERRUPT_STATE: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_set_interrupt_state (arg); + break; + case MSP430_BUILTIN_BIC_SR_IRQ: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_bic_status_register_on_exit (deref_stack_sr, arg); + break; + case MSP430_BUILTIN_BIS_SR_IRQ: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_bis_status_register_on_exit (deref_stack_sr, arg); + break; + case MSP430_BUILTIN_READ_STACK_POINTER: + retval = gen_reg_rtx (Pmode); + insn = gen_read_stack_pointer (retval); + break; + case MSP430_BUILTIN_WRITE_STACK_POINTER: + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_write_stack_pointer (arg); + break; + case MSP430_BUILTIN_GET_WATCHDOG_CLEAR_VALUE: + retval = gen_reg_rtx (HImode); + if (msp430_disable_watchdog) + insn = gen_movhi (retval, constm1_rtx); + else + insn = gen_get_watchdog_clear_value (retval); + break; + case MSP430_BUILTIN_SET_WATCHDOG_CLEAR_VALUE: + if (msp430_disable_watchdog) + need_insn = false; + else + { + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + insn = gen_set_watchdog_clear_value (arg); + } + break; + case MSP430_BUILTIN_WATCHDOG_CLEAR: + if (msp430_disable_watchdog) + need_insn = false; + else + insn = gen_watchdog_clear (); + break; + case MSP430_BUILTIN_DELAY_CYCLES: + { + tree cycles_arg = CALL_EXPR_ARG (exp, 0); + const enum machine_mode itercnt_mode = HImode; + const HOST_WIDE_INT itercnt_max = + (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (itercnt_mode); + const int decr_cycles = 1; + const int jump_cycles = 2; + const int iter_overhead_cycles = decr_cycles + jump_cycles; + const int iter0_cycles = iter_overhead_cycles; + const int cg_init_cycles = 1; + const int noncg_init_cycles = 2; + const HOST_WIDE_INT iter1_cycles = + itercnt_max * iter0_cycles + iter_overhead_cycles; + HOST_WIDE_INT cycles; + rtx iterreg0 = NULL_RTX; + + need_insn = false; + if (!cst_and_fits_in_hwi (cycles_arg) + || (0 > ((cycles = int_cst_value (cycles_arg))))) + { + error + ("__delay_cycles argument must be non-negative integer constant"); + break; + } + while (0 < cycles) + { + HOST_WIDE_INT itercnt1 = 0; + HOST_WIDE_INT itercnt0; + + if (cycles >= iter_overhead_cycles) + itercnt1 = (cycles - iter_overhead_cycles) / iter1_cycles; + if (itercnt1 > 0) + itercnt0 = + (cycles - itercnt1 * iter1_cycles - + iter_overhead_cycles) / iter0_cycles; + else + itercnt0 = cycles / iter0_cycles; + if (itercnt0 > itercnt_max) + { + itercnt0 -= itercnt_max; + ++itercnt1; + } + else if ((itercnt1 > 0) && (itercnt0 == 0)) + { + itercnt1 -= 1; + itercnt0 += itercnt_max; + } + gcc_assert (0 <= itercnt0 && itercnt0 <= itercnt_max); + if (itercnt0 > 0) + { + while (1) + { + unsigned HOST_WIDE_INT loop_cycles; + int cycles_in_init; + + cycles_in_init = + MSP430_CG_INT_P (trunc_int_for_mode + (itercnt0, + itercnt_mode)) ? cg_init_cycles : + noncg_init_cycles; + loop_cycles = itercnt0 * iter0_cycles; + if (itercnt1 > 0) + { + loop_cycles += + itercnt1 * iter1_cycles + iter_overhead_cycles; + cycles_in_init += + MSP430_CG_INT_P (trunc_int_for_mode + (1 + itercnt1, + itercnt_mode)) ? cg_init_cycles : + noncg_init_cycles; + } + if (loop_cycles + cycles_in_init <= + (unsigned HOST_WIDE_INT) cycles) + break; + + --itercnt0; + if (itercnt0 == 0 && itercnt1 > 0) + { + itercnt0 += itercnt_max; + --itercnt1; + } + } + if (itercnt0 > 0) + { + rtx loop_label = gen_label_rtx (); + rtx iterreg1 = NULL_RTX; + + if (itercnt1 > 0) + iterreg1 = gen_reg_rtx (itercnt_mode); + if (iterreg0 == NULL_RTX) + iterreg0 = gen_reg_rtx (itercnt_mode); + + if (iterreg1 != NULL_RTX) + { + emit_insn (gen_delay_cycles_init + (iterreg1, + gen_int_mode (1 + itercnt1, + itercnt_mode))); + cycles -= + MSP430_CG_INT_P (trunc_int_for_mode + (1 + itercnt1, + itercnt_mode)) ? cg_init_cycles : + noncg_init_cycles; + } + + emit_insn (gen_delay_cycles_init + (iterreg0, + gen_int_mode (itercnt0, itercnt_mode))); + cycles -= + MSP430_CG_INT_P (trunc_int_for_mode + (itercnt0, + itercnt_mode)) ? cg_init_cycles : + noncg_init_cycles; + + emit_label (loop_label); + emit_insn (gen_delay_cycles_decr (iterreg0)); + gcc_assert (HImode == itercnt_mode); + emit_jump_insn (gen_delay_cycles_jump (loop_label)); + cycles -= itercnt0 * iter0_cycles; + if (iterreg1 != NULL_RTX) + { + emit_insn (gen_delay_cycles_decr (iterreg1)); + emit_jump_insn (gen_delay_cycles_jump (loop_label)); + cycles -= + itercnt1 * iter1_cycles + iter_overhead_cycles; + } + /* In the areas between single (max 196608) and + * double (min 196619) loops, the remainder may + * warrant another single loop instead of a + * sequence of nine nops. */ + gcc_assert (0 <= cycles); + continue; + } + } + while (cycles--) + emit_insn (gen_nop ()); + break; + } + break; + } + case MSP430_BUILTIN_SWAP_BYTES: + retval = gen_reg_rtx (HImode); + arg = + expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, VOIDmode, + EXPAND_NORMAL); + emit_move_insn (retval, arg); + insn = gen_bswaphi1 (retval); + break; + case MSP430_BUILTIN_EVEN_IN_RANGE: + { + tree key_tree = CALL_EXPR_ARG (exp, 0); + tree limit_tree = CALL_EXPR_ARG (exp, 1); + rtx key; + HOST_WIDE_INT limit_val; + + need_insn = false; + if (!cst_and_fits_in_hwi (limit_tree) + || (0 > ((limit_val = int_cst_value (limit_tree))))) + { + error + ("__even_in_range second argument must be non-negative integer constant"); + break; + } + key = expand_expr (key_tree, NULL_RTX, VOIDmode, EXPAND_NORMAL); + retval = gen_reg_rtx (HImode); + /* This is a stub. To complete this, we need to attach notes + * that assert that the value is, in fact, even and between 0 + * and the second argument. No idea how to do that in a way + * that gcc's tablejump will pay any attention to. */ + emit_move_insn (retval, key); + break; + } + } + + if (insn) + emit_insn (insn); + else if (need_insn) + error ("Unhandled built-in function `%s'", + IDENTIFIER_POINTER (DECL_NAME (fndecl))); + + return retval; +} diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-c.c gcc-4.7.0/gcc/config/msp430/msp430-c.c new file mode 100644 index 0000000..5f3735f --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-c.c @@ -0,0 +1,85 @@ +/* C-family support for MSP430 back end. + +Copyright (C) 2012 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tm.h" +#include "tm_p.h" +#include "target.h" +#include "output.h" +#include "c-family/c-common.h" +#include "c-family/c-pragma.h" +#include "intl.h" +#include "diagnostic.h" + +#define GCC_BAD(gmsgid) \ + do { warning (OPT_Wpragmas, gmsgid); return; } while (0) +#define GCC_BAD2(gmsgid, arg) \ + do { warning (OPT_Wpragmas, gmsgid, arg); return; } while (0) + +void +msp430_pr_vector (cpp_reader * reader ATTRIBUTE_UNUSED) +{ + enum cpp_ttype token; + bool need_close_paren = false; + tree x; + tree t; + + if (pragma_lex (&t) != CPP_EQ) + GCC_BAD ("missing %<=%> after %<#pragma vector%> - ignored"); + token = pragma_lex (&t); + if (token == CPP_OPEN_PAREN) + { + token = pragma_lex (&t); + need_close_paren = true; + } + if (token != CPP_NUMBER) + GCC_BAD ("malformed %<#pragma vector%> - ignored"); + if (TREE_CODE (t) != INTEGER_CST) + GCC_BAD ("invalid constant in %<#pragma vector%> - ignored"); + if (need_close_paren && pragma_lex (&x) != CPP_CLOSE_PAREN) + GCC_BAD ("malformed %<#pragma vector%> - ignored"); + msp430_vector_offset_tree = t; +} + +bool +msp430_cpp_builtin_define_type_minmax (const char *min_macro, + const char *max_macro, + tree type) +{ + static const char *const values[] + = { "524287", "1048575" }; + char *buf; + const char *value; + const char *suffix = "L"; + + if (20 != TYPE_PRECISION (type)) + return false; + + value = values + TYPE_UNSIGNED (type); + buf = (char *) alloca (strlen (max_macro) + 1 + strlen (value) + + strlen (suffix) + 1); + sprintf (buf, "%s=%s%s", max_macro, value, suffix); + cpp_define (parse_in, buf); + gcc_assert (!min_macro); + return true; +} diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-function.c gcc-4.7.0/gcc/config/msp430/msp430-function.c new file mode 100644 index 0000000..52ab756 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-function.c @@ -0,0 +1,957 @@ +/* This work is partially financed by the European Commission under the +* Framework 6 Information Society Technologies Project +* "Wirelessly Accessible Sensor Populations (WASP)". +*/ + +/* +GCC 4.x port by Ivan Shcherbakov +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "tree.h" +#include "output.h" +#include "expr.h" +#include "toplev.h" +#include "obstack.h" +#include "function.h" +#include "recog.h" +#include "tm_p.h" +#include "target.h" +#include "target-def.h" +#include "insn-codes.h" +#include "ggc.h" +#include "langhooks.h" +#include "df.h" +#include "intl.h" +#include "rtl-error.h" + +#define STACK_ALIGN_SIZE(_v) (~1 & ((_v)+1)) + +/* registers used for incoming funct arguments */ +static char arg_register_used[16]; + +#define FIRST_CUM_REG 16 +static CUMULATIVE_ARGS *cum_incoming = 0; + +static int msp430_num_arg_regs (enum machine_mode mode, const_tree type); + +#define S_signal "signal" +#define S_interrupt "interrupt" +#define S_naked "naked" +#define S_task "task" +#define S_wakeup "wakeup" +#define S_critical "critical" +#define S_reentrant "reentrant" +#define S_saveprologue "saveprologue" +#define S_noint_hwmul "noint_hwmul" +#define S_hosted "hosted" +#define S_sr16 "sr16" +#define S_sr20 "sr20" +#define S_c16 "c16" +#define S_c20 "c20" +#define S_far "far" +#define S_near "near" + +void msp430_function_end_prologue (FILE * file); +void msp430_function_begin_epilogue (FILE * file); + +static inline void +warn_attribute_requires (tree decl, const char *a1, const char *a2) +{ + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + _("%qs attribute ignored (requires %qs)"), a1, a2); +} + +static inline void +warn_attribute_incompatible (tree decl, const char *a1, const char *a2) +{ + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + _("%qs attribute ignored (incompatible with %qs)"), a1, a2); +} + +GTY(()) tree msp430_vector_offset_tree; + +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in + struct attribute_spec.handler. */ +tree +msp430_handle_fndecl_attribute (tree * node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + tree decl_attrs; + tree conflicting_attr = NULL_TREE; + bool reject_cpux = false; + + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored on %qT", name, *node); + *no_add_attrs = true; + return NULL_TREE; + } + decl_attrs = DECL_ATTRIBUTES (*node); + + if (MSP430_MATCH_ATTRIBUTE_NAME (S_signal, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_interrupt, name)) + { + conflicting_attr = lookup_attribute (S_far, decl_attrs); + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_wakeup, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_naked, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_task, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_critical, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_reentrant, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_saveprologue, name)) + { + warning (OPT_Wattributes, _("%qE no longer supported"), name); + *no_add_attrs = true; + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_noint_hwmul, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_hosted, name)) + { + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_sr16, name)) + { + conflicting_attr = lookup_attribute (S_sr20, decl_attrs); + if (NULL_TREE == conflicting_attr) + conflicting_attr = lookup_attribute (S_far, decl_attrs); + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_sr20, name)) + { + if (!TARGET_CPUX) + reject_cpux = true; + else + conflicting_attr = lookup_attribute (S_sr16, decl_attrs); + } + else + { + } + if (reject_cpux) + { + warning (OPT_Wattributes, _("%qE requires CPUX-capable MCU"), name); + *no_add_attrs = true; + } + else if (NULL_TREE != conflicting_attr) + { + warning (OPT_Wattributes, _("%qE cannot combine with %qE"), name, + TREE_PURPOSE (conflicting_attr)); + *no_add_attrs = true; + } + return NULL_TREE; +} + +bool +msp430_function_attribute_inlinable_p (const_tree fndecl) +{ + tree decl_attrs = DECL_ATTRIBUTES (fndecl); + + /* sr16 and sr20 do not inhibit inline. + * Everything else does. */ + return NULL_TREE == lookup_attribute (S_signal, decl_attrs) + && NULL_TREE == lookup_attribute (S_interrupt, decl_attrs) + && NULL_TREE == lookup_attribute (S_naked, decl_attrs) + && NULL_TREE == lookup_attribute (S_task, decl_attrs) + && NULL_TREE == lookup_attribute (S_wakeup, decl_attrs) + && NULL_TREE == lookup_attribute (S_critical, decl_attrs) + && NULL_TREE == lookup_attribute (S_reentrant, decl_attrs) + && NULL_TREE == lookup_attribute (S_hosted, decl_attrs); +} + +rtx +msp430_prepare_call_address (rtx fnaddr) +{ + rtx symbol; + + gcc_assert (MEM_P (fnaddr)); + symbol = XEXP (fnaddr, 0); + if (GET_MODE (fnaddr) != GET_MODE (symbol)) + { + fnaddr = shallow_copy_rtx (fnaddr); + if (MSP430_SYMBOL_REF_C20_P (symbol)) + gcc_assert (PSImode == GET_MODE (symbol)); + PUT_MODE (fnaddr, GET_MODE (symbol)); + } + + return fnaddr; +} + +/* Update SYMBOL_REF_FLAGS based on declaration attributes */ +void +msp430_function_encode_symbol_flags (tree decl, rtx symbol) +{ + tree decl_attrs = DECL_ATTRIBUTES (decl); + tree type_attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + gcc_assert (FUNCTION_DECL == TREE_CODE (decl)); + if (NULL_TREE == lookup_attribute (S_sr16, decl_attrs) + && (TARGET_SR20 + || (NULL_TREE != lookup_attribute (S_sr20, decl_attrs)))) + SYMBOL_REF_FLAGS (symbol) |= MSP430_SYMBOL_FLAG_SR20; + if (NULL_TREE == lookup_attribute (S_c16, type_attrs) + && (TARGET_C20 || (NULL_TREE != lookup_attribute (S_c20, type_attrs)))) + SYMBOL_REF_FLAGS (symbol) |= MSP430_SYMBOL_FLAG_C20; +} + +void +msp430_set_current_function (tree decl) +{ + struct machine_function *mfp; + tree decl_attrs; + tree type_attrs; + tree naked; + tree interrupt; + tree task; + tree saveprologue; + tree noint_hwmul; + tree critical; + tree reentrant; + tree wakeup; + tree signal; + tree hosted; + tree sr16; + tree sr20; + tree c16; + tree c20; + + if ((decl == NULL_TREE) || (!cfun) || (!cfun->machine) + || cfun->machine->initialized) + return; + gcc_assert ((cfun->decl == NULL_TREE) || (cfun->decl == decl)); + decl_attrs = DECL_ATTRIBUTES (decl); + type_attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + + mfp = cfun->machine; + signal = lookup_attribute (S_signal, decl_attrs); + interrupt = lookup_attribute (S_interrupt, decl_attrs); + naked = lookup_attribute (S_naked, decl_attrs); + task = lookup_attribute (S_task, decl_attrs); + wakeup = lookup_attribute (S_wakeup, decl_attrs); + critical = lookup_attribute (S_critical, decl_attrs); + reentrant = lookup_attribute (S_reentrant, decl_attrs); + saveprologue = lookup_attribute (S_saveprologue, decl_attrs); + noint_hwmul = lookup_attribute (S_noint_hwmul, decl_attrs); + hosted = lookup_attribute (S_hosted, decl_attrs); + sr16 = lookup_attribute (S_sr16, decl_attrs); + sr20 = lookup_attribute (S_sr20, decl_attrs); + c16 = lookup_attribute (S_c16, type_attrs); + c20 = lookup_attribute (S_c20, type_attrs); + + /* Validate attribute parameters */ + if (interrupt) + { + tree ia_args = TREE_VALUE (interrupt); + int vector_offset = -1; + tree t0; + + t0 = msp430_vector_offset_tree; + msp430_vector_offset_tree = NULL_TREE; + + /* New style no argument means unvectored ISR. Old-style used + * 255 as the vector offset for this. */ + if (NULL_TREE != ia_args) + { + gcc_assert (TREE_CODE (ia_args) == TREE_LIST); + t0 = TREE_VALUE (ia_args); + gcc_assert (NULL_TREE == TREE_CHAIN (ia_args)); + } + if (NULL_TREE != t0) + { + if (TREE_CODE (t0) == INTEGER_CST) + { + vector_offset = TREE_INT_CST_LOW (t0); + if (255 == vector_offset) + vector_offset = -1; + else if ((0 > vector_offset) || (vector_offset & 1)) + { + error_at (DECL_SOURCE_LOCATION (decl), + _("interrupt vector offset %d" + " must be even and non-negative"), + vector_offset); + vector_offset = 0; + } + } + else if (TREE_CODE (t0) == IDENTIFIER_NODE) + { + error_at (DECL_SOURCE_LOCATION (decl), + _("interrupt vector offset %qE" + " is not an integer constant"), t0); + vector_offset = 0; + } + else + { + error_at (DECL_SOURCE_LOCATION (decl), + _ + ("interrupt vector offset must be an even non-negative integer constant")); + vector_offset = 0; + } + } + mfp->vector_offset = vector_offset; + } + + + /* check attribute compatibility */ +#define REJECT_INCOMPATIBLE(_a1,_a2) do { \ + if ((_a1) && (_a2)) \ + { \ + warn_attribute_incompatible (decl, S_##_a1, S_##_a2); \ + _a1 = NULL_TREE; \ + } \ + } while (0) +#define REJECT_REQUIRES(_a1,_a2) do { \ + if ((_a1) && !(_a2)) \ + { \ + warn_attribute_requires (decl, S_##_a1, S_##_a2); \ + _a1 = NULL_TREE; \ + } \ + } while (0) + + /* incompatible hosted && noreturn */ + if (hosted && TREE_THIS_VOLATILE (decl)) + { + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + _("%qs ignored on noreturn function"), S_hosted); + hosted = NULL_TREE; + } + + /* interrupt > critical > reentrant */ + REJECT_INCOMPATIBLE (reentrant, critical); + REJECT_INCOMPATIBLE (reentrant, interrupt); + REJECT_INCOMPATIBLE (critical, interrupt); + + /* Ignore signal/wakeup on non-interrupt */ + REJECT_REQUIRES (signal, interrupt); + REJECT_REQUIRES (wakeup, interrupt); + + /* task > naked > saveprologue (or its successor) */ + if (saveprologue) + { + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + _("saveprologue no longer supported")); + saveprologue = NULL_TREE; + } + REJECT_INCOMPATIBLE (saveprologue, naked); + REJECT_INCOMPATIBLE (saveprologue, task); + REJECT_INCOMPATIBLE (naked, task); + + /* Legacy ignore reentrant/critical on naked (but we allow them on + * task) */ + REJECT_INCOMPATIBLE (reentrant, naked); + REJECT_INCOMPATIBLE (critical, naked); + + /* c20 incompatible with interrupt */ + if (c20 && interrupt) + error_at (DECL_SOURCE_LOCATION (decl), _("%qE incompatible with %qE"), + TREE_PURPOSE (c20), TREE_PURPOSE (interrupt)); + /* c20/c16 mutually incompatible */ + if (c20 && c16) + error_at (DECL_SOURCE_LOCATION (decl), _("%qE incompatible with %qE"), + TREE_PURPOSE (c20), TREE_PURPOSE (c16)); + + +#undef REJECT_REQUIRES +#undef REJECT_INCOMPATIBLE + + /* Update declaration based on validated attributes */ + if (interrupt) + { + /* Ensure code is not eliminated due to it (apparently) not + * being called. */ + TREE_USED (decl) = 1; + DECL_PRESERVE_P (decl) = 1; + } + + /* Set frame flags. NB: allocate_frame will be cleared in the + * prologue if the frame size is zero. */ + mfp->frame_flags |= MSP430_FF_preserve_registers | MSP430_FF_allocate_frame; + if (critical) + mfp->frame_flags |= + MSP430_FF_prologue_push_sr | MSP430_FF_epilogue_pop_sr; + if (interrupt) + mfp->frame_flags |= MSP430_FF_use_reti; + if (signal) + mfp->frame_flags |= MSP430_FF_prologue_eint; + if (critical || reentrant) + mfp->frame_flags |= MSP430_FF_prologue_dint; + if (reentrant) + mfp->frame_flags |= MSP430_FF_epilogue_eint; + if (wakeup) + mfp->frame_flags |= MSP430_FF_epilogue_exit_lpm; + if (TREE_THIS_VOLATILE (decl)) + mfp->frame_flags |= MSP430_FF_inhibit_return; + if (MAIN_NAME_P (DECL_NAME (decl)) && !hosted) + { + static const char S_init9[] = ".init9"; + + if (c20) + error_at (DECL_SOURCE_LOCATION (decl), + _("%qE cannot apply to non-hosted main()"), + TREE_PURPOSE (c20)); + mfp->frame_flags |= MSP430_FF_treat_as_main; + if (DECL_SECTION_NAME (decl) == NULL_TREE) + DECL_SECTION_NAME (decl) = build_string (sizeof (S_init9), S_init9); + } + if (naked || task || (MSP430_FF_treat_as_main & mfp->frame_flags)) + { + mfp->frame_flags &= ~MSP430_FF_preserve_registers; + if (naked) + mfp->frame_flags &= ~MSP430_FF_allocate_frame; + mfp->frame_flags |= MSP430_FF_inhibit_return; + } + if (hosted) + mfp->frame_flags &= ~MSP430_FF_inhibit_return; + + if (NULL_TREE == sr16 && + (NULL_TREE != sr20 + || TARGET_SR20 || (TARGET_ISR20 && NULL_TREE != interrupt))) + mfp->frame_flags |= MSP430_FF_savereg_20; + if (NULL_TREE == c16 && (NULL_TREE != c20 || TARGET_C20)) + mfp->frame_flags |= MSP430_FF_callret_20; + + mfp->signal = signal; + mfp->interrupt = interrupt; + mfp->naked = naked; + mfp->task = task; + mfp->wakeup = wakeup; + mfp->critical = critical; + mfp->reentrant = reentrant; + mfp->saveprologue = saveprologue; + mfp->noint_hwmul = noint_hwmul; + mfp->initialized = true; +} + +int +msp430_epilogue_uses (int regno ATTRIBUTE_UNUSED) +{ + if (reload_completed + && cfun->machine && (cfun->machine->interrupt || cfun->machine->signal)) + return 1; + return 0; +} + +static rtx +return_addr_pointer (void) +{ + int adjustment = 0; + + if (cfun->machine->interrupt) + adjustment += UNITS_PER_WORD; + cfun->machine->frame_pointer_required = true; + return plus_constant (hard_frame_pointer_rtx, adjustment); +} + +rtx +msp430_return_addr_rtx (int count, rtx frameaddr ATTRIBUTE_UNUSED) +{ + if (0 == count) + return gen_rtx_MEM (Pmode, return_addr_pointer ()); + return NULL_RTX; +} + +/* Determine which registers need to be saved on the frame so they're + * restored for the caller. Returns the number of such registers; + * optionally sets a mask identifying the registers. + * + * A register must be preserved for the caller if it is not a + * call-used register or if this is an interrupt routine. The current + * function must perform such preservation if that register is live in + * this function. + * + * Non-leaf interrupt routines must save registers that they are + * allowed to use but don't. */ +static int +compute_savable_registers (unsigned int *maskp) +{ + int mask; + int count = 0; + int reg; + bool is_isr = cfun->machine->interrupt != NULL_TREE; + + mask = 0; + for (reg = 4; reg < 16; ++reg) + if ((df_regs_ever_live_p (reg) && (!call_used_regs[reg] || is_isr)) + || (is_isr && !current_function_is_leaf && call_used_regs[reg])) + { + mask |= (1 << reg); + ++count; + } + if (maskp) + *maskp = mask; + return count; +} + +/* Determine whether a particular register was saved in the frame */ +#define is_savable_register(REGNO) (cfun->machine->saved_regs_mask & (1 << (REGNO))) + +/* Generate and return an instruction that adjusts the register by a + * constant value. */ +static rtx +gen_adjust_register (rtx reg_rtx, int offset) +{ + gcc_assert (0 != offset); + if (MSP430_CG_INT_P (-offset) && !MSP430_CG_INT_P (offset)) + return gen_subP3 (reg_rtx, reg_rtx, gen_int_mode (-offset, Pmode)); + return gen_addP3 (reg_rtx, reg_rtx, gen_int_mode (offset, Pmode)); +} + +static rtx +emit_prolog_pushm (int regno, int numregs, enum machine_mode sr_mode) +{ + rtx note = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (1 + numregs)); + rtx (*gen_pushm2) (rtx, rtx) = + (PSImode == sr_mode) ? gen_pushmpsi2 : gen_pushmhi2; + rtx insn; + int i; + + insn = gen_rtx_SET (Pmode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + -UNITS_PER_WORD * numregs)); + RTX_FRAME_RELATED_P (insn) = 1; + XVECEXP (note, 0, 0) = insn; + + for (i = 0; i < numregs; ++i) + { + rtx spr; + spr = gen_rtx_MEM (sr_mode, + plus_constant (stack_pointer_rtx, + GET_MODE_SIZE (sr_mode) * (numregs - + i - 1))); + insn = gen_rtx_SET (sr_mode, spr, gen_rtx_REG (sr_mode, regno - i)); + RTX_FRAME_RELATED_P (insn) = 1; + XVECEXP (note, 0, 1 + i) = insn; + } + + insn = emit_insn (gen_pushm2 (GEN_INT (numregs), GEN_INT (regno))); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); + return insn; +} + +void +msp430_expand_prologue (void) +{ + int i; + struct machine_function *mfp = cfun->machine; + rtx insn; /* Last generated instruction */ + rtx need_nop_insn = NULL_RTX; + + mfp->saved_regs_count = compute_savable_registers (&mfp->saved_regs_mask); + if (0 == mfp->saved_regs_count) + mfp->frame_flags &= ~MSP430_FF_preserve_registers; + mfp->frame_size = STACK_ALIGN_SIZE (get_frame_size ()); + + /* Warn if we need a frame but have been told not to provide one. */ + if ((0 < mfp->frame_size) && !(mfp->frame_flags & MSP430_FF_allocate_frame)) + { + warning_at (DECL_SOURCE_LOCATION (cfun->decl), OPT_Wattributes, + _ + ("function requires %u bytes for stack storage but frame allocation inhibited by %qs"), + mfp->frame_size, S_naked); + mfp->frame_size = 0; + } + if (0 == mfp->frame_size) + mfp->frame_flags &= ~MSP430_FF_allocate_frame; + + if (MSP430_FF_prologue_push_sr & mfp->frame_flags) + { + insn = + emit_insn (gen_pushhi1 (gen_rtx_REG (HImode, STATUS_REGISTER_REGNUM))); + RTX_FRAME_RELATED_P (insn) = 1; + } + + if (MSP430_FF_prologue_dint & mfp->frame_flags) + { + need_nop_insn = insn = emit_insn (gen_dint ()); + } + + if (MSP430_FF_preserve_registers & mfp->frame_flags) + { + enum machine_mode sr_mode = MSP430_SAVEREGS_MODE (mfp); + rtx (*gen_push1) (rtx) = + (PSImode == sr_mode) ? gen_pushpsi1 : gen_pushhi1; + + for (i = MSP430_MAX_GENERAL_REGNUM; i >= MSP430_MIN_GENERAL_REGNUM; --i) + if (is_savable_register (i)) + { + if (TARGET_CPUX) + { + int n = 1; + + while ((i - n) >= MSP430_MIN_GENERAL_REGNUM + && is_savable_register (i - n)) + ++n; + if (1 < n) + { + insn = emit_prolog_pushm (i, n, sr_mode); + i = i - n + 1; + continue; + } + } + insn = emit_insn (gen_push1 (gen_rtx_REG (sr_mode, i))); + RTX_FRAME_RELATED_P (insn) = 1; + } + } + + if (frame_pointer_needed) + { + int fp_hfp_offset; + + if (!(MSP430_FF_preserve_registers & mfp->frame_flags) + && !(MSP430_FF_treat_as_main & mfp->frame_flags)) + warning_at (DECL_SOURCE_LOCATION (cfun->decl), OPT_Wattributes, + _("frame allocation destroys caller register due to %qs"), + S_task); + + fp_hfp_offset = + msp430_initial_elimination_offset (FRAME_POINTER_REGNUM, + HARD_FRAME_POINTER_REGNUM); + fp_hfp_offset += mfp->frame_size; + + insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + if (0 != fp_hfp_offset) + { + insn = + emit_insn (gen_adjust_register + (hard_frame_pointer_rtx, -fp_hfp_offset)); + RTX_FRAME_RELATED_P (insn) = 1; + } + } + + if (MSP430_FF_allocate_frame & mfp->frame_flags) + { + insn = + emit_insn (gen_adjust_register (stack_pointer_rtx, -mfp->frame_size)); + RTX_FRAME_RELATED_P (insn) = 1; + } + + if (MSP430_FF_prologue_eint & mfp->frame_flags) + { + insn = emit_insn (gen_eint ()); + } + + /* Ensure dint is followed by something before we hit the + * uninterruptible code */ + if (need_nop_insn != NULL_RTX && need_nop_insn == get_last_insn ()) + { + insn = emit_insn (gen_nop ()); + } + + /* If the epilogue will reduce to a single instruction, we can + * enable the return pattern now so gen_return at the end of basic + * blocks avoids a jump. */ + if (!(mfp->frame_flags & (MSP430_FF_inhibit_return + | MSP430_FF_epilogue_dint + | MSP430_FF_allocate_frame + | MSP430_FF_preserve_registers + | MSP430_FF_epilogue_pop_sr + | MSP430_FF_epilogue_exit_lpm + | MSP430_FF_epilogue_eint))) + mfp->frame_flags |= MSP430_FF_ready_for_return; + + mfp->inhibited_return_label = NULL; + if (mfp->frame_flags & MSP430_FF_inhibit_return) + { + static int const_labelno; + char tmp_label[100]; + + ASM_GENERATE_INTERNAL_LABEL (tmp_label, "LIRD", const_labelno); + const_labelno++; + mfp->inhibited_return_label = ggc_strdup (tmp_label); + } +} + + +/* Output function epilogue */ + +void +msp430_expand_epilogue (void) +{ + int i; + struct machine_function *mfp = cfun->machine; + rtx insn; + rtx need_nop_insn = NULL_RTX; + + /* Obey noreturn. Can't just exit */ + if (TREE_THIS_VOLATILE (current_function_decl)) + goto epilogue_done; + + if (MSP430_FF_epilogue_dint & mfp->frame_flags) + need_nop_insn = insn = emit_insn (gen_dint ()); + + if (MSP430_FF_allocate_frame & mfp->frame_flags) + insn = + emit_insn (gen_adjust_register (stack_pointer_rtx, mfp->frame_size)); + + if (MSP430_FF_preserve_registers & mfp->frame_flags) + { + enum machine_mode sr_mode = MSP430_SAVEREGS_MODE (mfp); + rtx (*gen_pop1) (rtx) = (PSImode == sr_mode) ? gen_poppsi1 : gen_pophi1; + rtx (*gen_popm2) (rtx, rtx) = + (PSImode == sr_mode) ? gen_popmpsi2 : gen_popmhi2; + for (i = MSP430_MIN_GENERAL_REGNUM; i <= MSP430_MAX_GENERAL_REGNUM; i++) + if (is_savable_register (i)) + { + if (TARGET_CPUX) + { + int n = 1; + + while ((i + n) <= MSP430_MAX_GENERAL_REGNUM + && is_savable_register (i + n)) + ++n; + if (1 < n) + { + i = i + n - 1; + insn = emit_insn (gen_popm2 (GEN_INT (n), GEN_INT (i))); + continue; + } + } + insn = emit_insn (gen_pop1 (gen_rtx_REG (sr_mode, i))); + } + } + + if (MSP430_FF_epilogue_pop_sr & mfp->frame_flags) + insn = + emit_insn (gen_pophi1 (gen_rtx_REG (HImode, STATUS_REGISTER_REGNUM))); + + if (MSP430_FF_epilogue_exit_lpm & mfp->frame_flags) + insn = + emit_insn (gen_bic_status_register_on_exit + (gen_rtx_MEM (HImode, stack_pointer_rtx), + gen_int_mode (0xf0, HImode))); + + if (MSP430_FF_epilogue_eint & mfp->frame_flags) + insn = emit_insn (gen_eint ()); + +epilogue_done: + + /* NB: if naked, this does not emit any code, but we have to invoke + * gen_return() at least once or sanity checks in the shared code + * fail. */ + mfp->frame_flags |= MSP430_FF_ready_for_return; + emit_jump_insn (gen_return ()); + + /* Ensure dint is followed by something before we hit the + * uninterruptible code. (Test will only pass if + * inhibit_return.) */ + if (need_nop_insn != NULL_RTX && need_nop_insn == get_last_insn ()) + insn = emit_insn (gen_nop ()); +} + +void +msp430_output_addr_vec_elt (FILE * stream, int value) +{ + fprintf (stream, "\t.%s\t.L%d\n", (CASE_VECTOR_MODE == PSImode) ? "long" : "word", value); +} + +rtx msp430_function_arg (cumulative_args_t, enum machine_mode, const_tree, + bool); +void msp430_function_arg_advance (cumulative_args_t, enum machine_mode, + const_tree, bool); + +/* Controls whether a function argument is passed +in a register, and which register. */ +rtx +msp430_function_arg (cumulative_args_t ca, enum machine_mode mode, + const_tree type, bool named ATTRIBUTE_UNUSED) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (ca); + int regs = msp430_num_arg_regs (mode, type); + + if (cum->nregs && regs <= cum->nregs) + { + int regnum = cum->regno - regs; + + if (cum == cum_incoming) + { + arg_register_used[regnum] = 1; + if (regs >= 2) + arg_register_used[regnum + 1] = 1; + if (regs >= 3) + arg_register_used[regnum + 2] = 1; + if (regs >= 4) + arg_register_used[regnum + 3] = 1; + } + + return gen_rtx_REG (mode, regnum); + } + return NULL_RTX; +} + +/* the same in scope of the cum.args., buf usefull for a +function call */ +void +msp430_init_cumulative_incoming_args (CUMULATIVE_ARGS * cum, tree fntype, + rtx libname) +{ + int i; + cum->nregs = 4; + cum->regno = FIRST_CUM_REG; + if (!libname) + { + int stdarg = (TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); + if (stdarg) + cum->nregs = 0; + } + + for (i = 0; i < 16; i++) + arg_register_used[i] = 0; + + cum_incoming = cum; +} + +/* Initializing the variable cum for the state at the beginning +of the argument list. */ +void +msp430_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, rtx libname, + tree fndecl ATTRIBUTE_UNUSED) +{ + cum->nregs = 4; + cum->regno = FIRST_CUM_REG; + if (!libname) + { + int stdarg = (TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); + if (stdarg) + cum->nregs = 0; + } +} + + +/* Update the summarizer variable CUM to advance past an argument +in the argument list. */ +void +msp430_function_arg_advance (cumulative_args_t ca, enum machine_mode mode, + const_tree type, bool named ATTRIBUTE_UNUSED) +{ + CUMULATIVE_ARGS *cum = get_cumulative_args (ca); + int regs = msp430_num_arg_regs (mode, type); + + cum->nregs -= regs; + cum->regno -= regs; + + if (cum->nregs <= 0) + { + cum->nregs = 0; + cum->regno = FIRST_CUM_REG; + } +} + +/* Returns the number of registers to allocate for a function argument. */ +static int +msp430_num_arg_regs (enum machine_mode mode, const_tree type) +{ + int size; + + if (BLKmode != mode) + return HARD_REGNO_NREGS (0, mode); + size = int_size_in_bytes (type); + if (size < UNITS_PER_WORD) + size = UNITS_PER_WORD; + return STACK_ALIGN_SIZE (size) / UNITS_PER_WORD; +} + +int +msp430_initial_elimination_offset (int from, int to) +{ + const struct machine_function *mfp = cfun->machine; + enum machine_mode sr_mode = MSP430_SAVEREGS_MODE (mfp); + int offset_words = 0; + int offset_bytes = 0; + + switch (from) + { + case ARG_POINTER_REGNUM: + if (mfp->interrupt) + offset_words += 2; + else if (MSP430_FF_callret_20 & mfp->frame_flags) + offset_words += 2; + else + offset_words += 1; + switch (to) + { + case HARD_FRAME_POINTER_REGNUM: + break; + case STACK_POINTER_REGNUM: + if (MSP430_FF_prologue_push_sr & mfp->frame_flags) + ++offset_words; + offset_bytes += + GET_MODE_SIZE (sr_mode) * compute_savable_registers (0); + offset_bytes += get_frame_size (); + break; + default: + gcc_unreachable (); + } + break; + case FRAME_POINTER_REGNUM: + switch (to) + { + case STACK_POINTER_REGNUM: + break; + case HARD_FRAME_POINTER_REGNUM: + if (MSP430_FF_prologue_push_sr & mfp->frame_flags) + ++offset_words; + offset_bytes += + GET_MODE_SIZE (sr_mode) * compute_savable_registers (0); + offset_bytes += get_frame_size (); + offset_words = -offset_words; + offset_bytes = -offset_bytes; + break; + default: + gcc_unreachable (); + } + break; + default: + gcc_unreachable (); + } + offset_bytes += UNITS_PER_WORD * offset_words; + return STACK_ALIGN_SIZE (offset_bytes); +} + +int +msp430_cfa_frame_base_offset (const_tree decl) +{ + int offset = 0; + struct machine_function *mfp = DECL_STRUCT_FUNCTION (decl)->machine; + + if (mfp->interrupt) + { + /* If Pmode is 32-bits, default is right; otherwise need to + * adjust for intervening status register */ + if (UNITS_PER_WORD == INCOMING_FRAME_SP_OFFSET) + offset -= UNITS_PER_WORD; + } + + /* Main routine entered via fall-through; no return address */ + if (mfp->frame_flags & MSP430_FF_treat_as_main) + offset -= INCOMING_FRAME_SP_OFFSET; + + return offset; +} diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-gcc.c gcc-4.7.0/gcc/config/msp430/msp430-gcc.c new file mode 100644 index 0000000..dece83d --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-gcc.c @@ -0,0 +1,123 @@ +#include "config.h" +#include "system.h" +#include "prefix.h" +#include "defaults.h" + +extern const char *msp430_mcucpp (int argc, const char **argv); + +extern const char *msp430_mculdscriptpaths (int argc, const char **argv); + +/* Return a new string -D__(toupper(mcu))__ */ +static const char * +gen_cpp (const char *mcu) +{ + static const char prefix[] = "-D__"; + static const char suffix[] = "__"; + size_t len; + char *result; + char *ep; + const char *cp; + + len = (sizeof (prefix) - 1) + strlen (mcu) + sizeof (suffix); + result = XNEWVAR (char, len); + ep = result; + strcpy (ep, prefix); + ep += sizeof (prefix) - 1; + cp = mcu; + while (*cp) + { + *ep++ = TOUPPER (*cp); + ++cp; + } + *ep = 0; + strcat (result, suffix); + return result; +} + +const char * +msp430_mcucpp (int argc, const char **argv) +{ + const char *mcu; + const char *defs; + const char *p; +#if 0 + fprintf (stderr, "%d args: ", argc); + for (len = 0; len < argc; ++len) + fprintf (stderr, "'%s' ", argv[len]); + fprintf (stderr, "\n"); +#endif + + if (0 == argc) + return NULL; + mcu = argv[argc - 1]; + defs = gen_cpp (mcu); + p = strchr (mcu, '_'); + if (NULL != p) + { + char *base_mcu = xstrndup (mcu, p - mcu); + defs = concat (gen_cpp (base_mcu), " ", defs, NULL); + free (base_mcu); + } + return defs; +} + +#ifndef DIR_UP +#define DIR_UP ".." +#endif /* DIR_UP */ + +/* Join additional directory components to a separator-terminated path + to create a new separator-terminated path. */ +static const char * +dir_join (const char *path, ...) +{ + static const char dir_sep[] = { DIR_SEPARATOR, 0 }; + const char *rv = path; + const char *elt; + va_list ap; + + va_start (ap, path); + while (1) + { + elt = va_arg (ap, const char *); + if (NULL == elt) + break; + rv = concat (rv, elt, dir_sep, NULL); + } + va_end (ap); + return rv; +} + +static const char * +gen_ldscriptpath (const char *mcu, const char *suffix) +{ + const char *gcc_exec_prefix; + + gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX"); + if (!gcc_exec_prefix) + gcc_exec_prefix = STANDARD_EXEC_PREFIX; + + return update_path (dir_join (gcc_exec_prefix, DIR_UP, DIR_UP, + DEFAULT_TARGET_MACHINE, "lib", + "ldscripts", mcu, suffix, NULL), "BINUTILS"); +} + +const char * +msp430_mculdscriptpaths (int argc, const char **argv) +{ + const char *mcu; + const char *paths = ""; + const char *p; + + if (0 == argc) + return 0; + + mcu = argv[argc - 1]; + p = strchr (mcu, '_'); + if (NULL != p) + { + mcu = xstrndup (mcu, p - mcu); + paths = concat (paths, "-L ", gen_ldscriptpath (mcu, p + 1), NULL); + } + paths = concat (paths, " -L ", gen_ldscriptpath (mcu, NULL), NULL); + return paths; +} diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-modes.def gcc-4.7.0/gcc/config/msp430/msp430-modes.def new file mode 100644 index 0000000..f86f345 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-modes.def @@ -0,0 +1,42 @@ +/* msp430 extra machine modes. + Copyright (C) 2012 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +/* 20-bit values, in 20-bit register or 32-bit memory, 16-bit aligned */ + +/* FRACTIONAL_INT_MODE(PSI, 20, 4) produces a type in MODE_INT, which + * participates in the standard widening hierarchy. We don't want that, + * because those modes show up even when building for chips that don't + * support them. Though we can work around that, gcc also becomes more + * aggressive about introducing restructuring like subregs in situations + * where it's not happy about registers that hold values that don't fit in a + * word. + * + * PARTIAL_INT_MODE(SI) produces a type in MODE_PARTIAL_INT, which is + * independent of widening, but the interface doesn't permit specifying the + * representation precision. We don't really want that either. + * + * We can explicitly create a MODE_PARTIAL_INT with the correct precision + * using PARTIAL_INT_MODE_PRECISION(SI, 20) (and the appropriate definition + * for that macro). + * + * And that's what we're doing. */ + +#define PARTIAL_INT_MODE_PRECISION(M,B) \ + make_partial_integer_mode (#M, "P" #M, B, __FILE__, __LINE__) +PARTIAL_INT_MODE_PRECISION(SI, 20); diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-opts.h gcc-4.7.0/gcc/config/msp430/msp430-opts.h new file mode 100644 index 0000000..c01b687 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-opts.h @@ -0,0 +1,98 @@ +/* Definitions for option handling for MSP430. + Copyright (C) 2001-2012 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#ifndef GCC_MSP430_OPTS_H +#define GCC_MSP430_OPTS_H + +/** Bit-markers for type of CPU present. */ +typedef enum msp430_cpu_e +{ + MSP430_CPU_MSP430 = 0x0000, + MSP430_CPU_MSP430X = 0x0002, + MSP430_CPU_MSP430XV2 = 0x0003, + MSP430_CPU = 0x0003 +} msp430_cpu_e; + +/** Bit-markers for type of hardware multiplier present. */ +typedef enum msp430_mpy_e +{ + MSP430_MPY_NONE = 0x0000, + MSP430_MPY_TYPE_16 = 0x0010, + MSP430_MPY_TYPE_32 = 0x0020, + MSP430_MPY_TYPE_ANY = 0x0030, + MSP430_MPY_HAS_SE = 0x0001, + MSP430_MPY_HAS_DW = 0x0002, + MSP430_MPY_16 = MSP430_MPY_TYPE_16, + MSP430_MPY_16SE = MSP430_MPY_16 | MSP430_MPY_HAS_SE, + MSP430_MPY_32 = MSP430_MPY_TYPE_16 | MSP430_MPY_TYPE_32 | MSP430_MPY_HAS_SE, + MSP430_MPY_32DW = MSP430_MPY_32 | MSP430_MPY_HAS_DW +} msp430_mpy_e; + +/** Bit-markers indicating the selected memory model. Values must be + * disjoint from msp430_cpu_e and msp430_cpux_target_e. Though these + * are recorded in __MSP430X__, use the MSP430_CPUX_TARGET_foo flags + * for control. */ +typedef enum msp430_memory_model_e +{ + /* No memory model specified */ + MSP430_MEMORY_MODEL_NONE = 0x0000, + /* Small: nominally -mc16 -md16 -msr16 -ma16 (all default) */ + MSP430_MEMORY_MODEL_SMALL = 0x0010, + /* Medium: nominally -mc20 -msr20 */ + MSP430_MEMORY_MODEL_MEDIUM = 0x0020, + /* Large: nominally -mc20 -md20 -msr20 */ + MSP430_MEMORY_MODEL_LARGE = 0x0030, + /* Huge: nominally -mc20 -md20 -msr20 -ma20 */ + MSP430_MEMORY_MODEL_HUGE = 0x0040, + /* Mask to extract the specific value from __MSP430X__ */ + MSP430_MEMORY_MODEL_MASK = 0x0070 +} msp430_memory_model_e; + +/** Bit-markers indicating CPUX target flags that are enabled. Values + * must be disjoint from msp430_cpu_e. + * + * NOTE: The values associated with these flags MUST NOT CHANGE. Ever. + * They get encoded into object files when the idiom: + * .cpux_target bits=__MSP430X__ + * appears in assembly sources. */ +typedef enum msp430_cpux_target_e +{ + MSP430_CPUX_TARGET_ISR20 = 0x0100, + MSP430_CPUX_TARGET_SR20 = 0x0200, + MSP430_CPUX_TARGET_A20 = 0x0400, + MSP430_CPUX_TARGET_C20 = 0x0800, + MSP430_CPUX_TARGET_D20 = 0x1000 +} msp430_cpux_target_e; + +/** Alternatives for the regions in which different types of + * declaration may be placed. */ +typedef enum msp430_section_region_e +{ + /** No specific region desired */ + MSP430_SECTION_REGION_DEFAULT, + /** Place in lower 64 kB memory */ + MSP430_SECTION_REGION_NEAR, + /** Place above 64 kB boundary */ + MSP430_SECTION_REGION_FAR, + /** Place in either near or far region */ + MSP430_SECTION_REGION_ANY +} msp430_section_region_e; + +#endif /* GCC_MSP430_OPTS_H */ diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430-protos.h gcc-4.7.0/gcc/config/msp430/msp430-protos.h new file mode 100644 index 0000000..6b31060 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430-protos.h @@ -0,0 +1,122 @@ +/* Prototypes for exported functions defined in msp430.c + + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Contributed by Dmitry Diky + + This file is part of GNU CC. + + GNU CC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +bool msp430_match_attribute_name (const char *, size_t, tree); + +int msp430_regno_ok_for_base_p (int reg, int strict); + +int msp430_adjust_insn_length (rtx insn, int length); + +#ifdef HAVE_MACHINE_MODES +extern int msp430_hard_regno_mode_ok (int regno, enum machine_mode mode); +#endif + +extern int msp430_initial_elimination_offset (int, int); + +#ifdef TREE_CODE +void msp430_asm_declare_function_name (FILE *, const char *, tree); +unsigned int msp430_section_type_flags (tree DECL, const char *NAME, + int RELOC); + +#ifdef RTX_CODE /* inside TREE_CODE */ +extern void msp430_init_cumulative_args (CUMULATIVE_ARGS * cum, + tree fntype, rtx libname, + tree fndecl); +extern void msp430_init_cumulative_incoming_args (CUMULATIVE_ARGS * cum, + tree fntype, rtx libname); +#endif /* RTX_CODE inside TREE_CODE */ + +#endif /* TREE_CODE */ + +#ifdef RTX_CODE + +int msp430_extract_multiword_operand (enum machine_mode innermode, rtx op, + rtx * parts); + +const char *msp430_output_template (enum machine_mode mode, + rtx * operands, + int src_operand, + const char *init_op, + const char *next_op, const char *prefix); +const char *msp430_output_cpux_template (enum machine_mode mode, + rtx * operands, + int src_operand, + const char *init_op, + const char *next_op, + const char *prefix); +const char *msp430_output_reverse_template (enum machine_mode mode, + rtx * operands, + int src_operand, + const char *init_op, + const char *next_op, + const char *prefix); + +const char *msp430_mov_noclobber (rtx operands[]); + +enum reg_class msp430_regno_reg_class (int); + +int msp430_extend_matches (const_rtx, const_rtx); +void msp430_expand_signextend (rtx operands[]); +void msp430_expand_zeroextend (rtx operands[]); + +int msp430_expand_extract (rtx operands[], bool signed_p); + +extern void msp430_notice_update_cc (rtx body, rtx insn); +extern void msp430_output_addr_vec_elt (FILE * stream, int value); + +extern void msp430_print_operand (FILE * file, rtx x, int code); + +extern int msp430_jump_dist (rtx x, rtx insn); + +extern void msp430_expand_mul (rtx[], int); +extern void msp430_expand_ashl (rtx[]); +extern void msp430_expand_ashr (rtx[]); +extern void msp430_expand_lshr (rtx[]); + +extern void msp430_expand_cbranch (rtx[]); +extern const char *msp430_output_branchcc (rtx, rtx[]); + +tree msp430_handle_fndecl_attribute (tree *, tree, tree, int, bool *); +bool msp430_function_attribute_inlinable_p (const_tree); +void msp430_function_encode_symbol_flags (tree, rtx); +extern void msp430_expand_prologue (void); +extern void msp430_expand_epilogue (void); +extern void msp430_set_current_function (tree); +extern int msp430_epilogue_uses (int regno); + +bool msp430_inhibited_return_fallthru_p (rtx insn); +rtx msp430_prepare_call_address (rtx fnaddr); + +rtx gen_addP3 (rtx, rtx, rtx); +rtx gen_subP3 (rtx, rtx, rtx); + +#endif /* RTX_CODE */ + +extern void msp430_pr_vector (struct cpp_reader *); +#ifdef TREE_CODE +extern +GTY (()) + tree msp430_vector_offset_tree; +#endif /* TREE_CODE */ + + extern rtx msp430_return_addr_rtx (int, rtx); + extern int msp430_cfa_frame_base_offset (const_tree decl); diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430.c gcc-4.7.0/gcc/config/msp430/msp430.c new file mode 100644 index 0000000..336630b --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430.c @@ -0,0 +1,4174 @@ +/* TODO + * cost speed attribute + */ +/* This work is partially financed by the European Commission under the +* Framework 6 Information Society Technologies Project +* "Wirelessly Accessible Sensor Populations (WASP)". +*/ + +/* + GCC 4.x port by Ivan Shcherbakov +*/ + +/* Subroutines for insn-output.c for Texas Instruments MSP430 MCU +Copyright (C) 2001, 2002 Free Software Foundation, Inc. +Contributed by Dmitry Diky + +This file is part of GNU CC. +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "tree.h" +#include "output.h" +#include "expr.h" +#include "toplev.h" +#include "obstack.h" +#include "function.h" +#include "optabs.h" +#include "recog.h" +#include "tm_p.h" +#include "target.h" +#include "target-def.h" +#include "common/common-target.h" +#include "insn-codes.h" +#include "ggc.h" +#include "langhooks.h" +#include "df.h" +#include "intl.h" +#include "diagnostic.h" + +/* Number of consecutive registers available for returning values from + * a function. These start with MSP430_RETURN_REGISTER_BASE and grow + * "down". */ +#define RETURN_REGISTERS_AVAILABLE 4 + +struct tag_value_pair_t +{ + const char *tag; + unsigned long value; +}; + +static const struct tag_value_pair_t cpu_tag_value_map[] = { + {"430", MSP430_CPU_MSP430}, + {"430x", MSP430_CPU_MSP430X}, + {"430xv2", MSP430_CPU_MSP430XV2}, + {0, 0} +}; + +static const struct tag_value_pair_t mpy_tag_value_map[] = { + {"none", MSP430_MPY_NONE}, + {"16", MSP430_MPY_16}, + {"16se", MSP430_MPY_16SE}, + {"32", MSP430_MPY_32}, + {"32dw", MSP430_MPY_32DW}, + {0, 0} +}; + +static const struct tag_value_pair_t * +find_pair_by_value (unsigned long value, const struct tag_value_pair_t *map) +{ + while (map->tag) + { + if (map->value == value) + return map; + ++map; + } + return 0; +} + +GTY(()) tree msp430_global_trees[MSP430_TI_MAX]; + +static GTY(()) rtx mpy_b_rtx; +static GTY(()) rtx mpys_b_rtx; +static GTY(()) rtx op2_b_rtx; +static GTY(()) rtx reslo_b_rtx; +static GTY(()) rtx mpy_rtx; +static GTY(()) rtx mpys_rtx; +static GTY(()) rtx op2_rtx; +static GTY(()) rtx reslo_rtx; +static GTY(()) rtx reshi_rtx; +static GTY(()) rtx mpy32l_rtx; +static GTY(()) rtx mpy32h_rtx; +static GTY(()) rtx mpys32l_rtx; +static GTY(()) rtx mpys32h_rtx; +static GTY(()) rtx op2l_rtx; +static GTY(()) rtx op2h_rtx; +static GTY(()) rtx res0_rtx; +static GTY(()) rtx res1_rtx; +static GTY(()) rtx res2_rtx; +static GTY(()) rtx res3_rtx; + +static GTY(()) rtx libsym_mulqi3; +static GTY(()) rtx libsym_mulqihi3; +static GTY(()) rtx libsym_umulqihi3; +static GTY(()) rtx libsym_mulhi3; +static GTY(()) rtx libsym_mulhisi3; +static GTY(()) rtx libsym_umulhisi3; +static GTY(()) rtx libsym_mulsi3; +static GTY(()) rtx libsym_mulsidi3; +static GTY(()) rtx libsym_umulsidi3; +static GTY(()) rtx libsym_muldi3; + +static GTY(()) rtx libsym_ashlqi3; +static GTY(()) rtx libsym_ashrqi3; +static GTY(()) rtx libsym_lshrqi3; +static GTY(()) rtx libsym_ashlhi3; +static GTY(()) rtx libsym_ashrhi3; +static GTY(()) rtx libsym_lshrhi3; +static GTY(()) rtx libsym_ashlsi3; +static GTY(()) rtx libsym_ashrsi3; +static GTY(()) rtx libsym_lshrsi3; +static GTY(()) rtx libsym_ashldi3; +static GTY(()) rtx libsym_ashrdi3; +static GTY(()) rtx libsym_lshrdi3; + +#define S_a16 "a16" +#define S_a20 "a20" +#define S_c16 "c16" +#define S_c20 "c20" +#define S_d16 "d16" +#define S_d20 "d20" +#define S_far "far" +#define S_near "near" +#define S_interrupt "interrupt" + +bool +msp430_match_attribute_name (const char *str, size_t str_len, tree name) +{ + size_t name_len; + const char *id; + gcc_assert (IDENTIFIER_NODE == TREE_CODE (name)); + name_len = IDENTIFIER_LENGTH (name); + id = IDENTIFIER_POINTER (name); + if (name_len == str_len) + return 0 == strcmp (str, id); + if (name_len == 4 + str_len) + return id[0] == '_' && id[1] == '_' && id[name_len - 2] == '_' + && id[name_len - 1] == '_' && strncmp (str, id + 2, str_len) == 0; + return false; +} + +int +msp430_current_function_noint_hwmul_function_p (void) +{ + return TARGET_NOINT_HWMUL || (cfun && cfun->machine + && cfun->machine->initialized + && cfun->machine->noint_hwmul != NULL_TREE); +} + +/* Convert an operand that requires multiple words into a sequence of + word-sized operands comprising its elements, from least significant + to most significant. Returns the number of word elements + extracted. */ +int +msp430_extract_multiword_operand (enum machine_mode innermode, rtx op, + rtx * parts) +{ + int words; + rtx last_insn = get_last_insn (); + int i; + + if (VOIDmode == innermode) + innermode = GET_MODE (op); + words = GET_MODE_SIZE (innermode) / UNITS_PER_WORD; + if (PSImode == innermode || 1 >= words) + { + parts[0] = op; + words = 1; + } + else + for (i = 0; i < words; ++i) + { + parts[i] = + simplify_gen_subreg (HImode, op, innermode, i * UNITS_PER_WORD); + gcc_assert (parts[i]); + if (MEM_P (parts[i])) + { + parts[i] = validize_mem (parts[i]); + gcc_assert (parts[i]); + } + } + gcc_assert (last_insn == get_last_insn ()); + return words; +} + +/* Generate the appropriate template for a read-modify-write operation + * in MODE, using the SRC_OPERAND as the operand index for a binary + * pattern, with the least significant word generated using INIT_OP + * and any higher words are generated using NEXT_OP (which defaults to + * INIT_OP if NULL). If SRC_OPERAND is 0, a unary pattern is used. */ +static const char * +output_template (enum machine_mode mode, + rtx * operands ATTRIBUTE_UNUSED, + int src_operand, bool reversep, bool forcex, + const char *std_init_op, const char *std_next_op, + const char *prefix) +{ + char buffer[1024]; + size_t offset = 0; + const char *init_op = std_init_op; + const char *next_op = std_next_op; + char init_op_buf[32]; + char next_op_buf[32]; + + if (!next_op) + next_op = init_op; + buffer[offset] = 0; + if (prefix) + offset += snprintf (buffer, sizeof (buffer) - offset, "%s\n\t", prefix); + + if (forcex + || PSImode == mode + || msp430x_ext_operand (operands[0], mode) + || (0 < src_operand && msp430x_ext_operand (operands[src_operand], mode))) + { + size_t nw; + + /* Need to use extended instructions if mode is PSImode or an + * operand involves a 20-bit memory address */ + nw = snprintf (init_op_buf, sizeof (init_op_buf), "%sx", init_op); + gcc_assert (nw < sizeof (init_op_buf)); + init_op = init_op_buf; + if (next_op) + { + nw = snprintf (next_op_buf, sizeof (next_op_buf), "%sx", next_op); + gcc_assert (nw < sizeof (next_op_buf)); + next_op = next_op_buf; + } + } + gcc_assert (offset < sizeof (buffer)); + switch (mode) + { + case QImode: + if (0 < src_operand) + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + "%s.b\t%%%d, %%0", init_op, src_operand); + else + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + "%s.b\t%%0", init_op); + break; + case HImode: + if (0 < src_operand) + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + "%s\t%%%d, %%0", init_op, src_operand); + else + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + "%s\t%%0", init_op); + break; + case PSImode: + if (0 < src_operand) + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + "%s.a\t%%%d, %%0", init_op, src_operand); + else + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + "%s.a\t%%0", init_op); + break; + case SImode: + case SFmode: + if (0 < src_operand) + { + const char *format = reversep + ? "%s\t%%B%d, %%B0\n\t" + "%s\t%%A%d, %%A0" : "%s\t%%A%d, %%A0\n\t" "%s\t%%B%d, %%B0"; + + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + format, init_op, src_operand, next_op, + src_operand); + } + else + { + const char *format = reversep + ? "%s\t%%B0\n\t" "%s\t%%A0" : "%s\t%%A0\n\t" "%s\t%%B0"; + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + format, init_op, next_op); + } + break; + case DImode: + if (0 < src_operand) + { + const char *format = reversep + ? "%s\t%%D%d, %%D0\n\t" + "%s\t%%C%d, %%C0\n\t" + "%s\t%%B%d, %%B0\n\t" + "%s\t%%A%d, %%A0" + : "%s\t%%A%d, %%A0\n\t" + "%s\t%%B%d, %%B0\n\t" "%s\t%%C%d, %%C0\n\t" "%s\t%%D%d, %%D0"; + + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + format, + init_op, src_operand, + next_op, src_operand, + next_op, src_operand, next_op, src_operand); + } + else + { + const char *format = reversep + ? "%s\t%%D0\n\t" + "%s\t%%C0\n\t" + "%s\t%%B0\n\t" + "%s\t%%A0" + : "%s\t%%A0\n\t" "%s\t%%B0\n\t" "%s\t%%C0\n\t" "%s\t%%D0"; + offset += snprintf (buffer + offset, sizeof (buffer) - offset, + format, init_op, next_op, next_op, next_op); + } + break; + default: + gcc_unreachable (); + } + gcc_assert (offset < sizeof (buffer)); + return ggc_strdup (buffer); +} + +/* Generate the appropriate template for a read-modify-write operation + * in MODE, using the SRC_OPERAND as the operand index for a binary + * pattern, with the least significant word generated using INIT_OP + * and any higher words are generated using NEXT_OP (which defaults to + * INIT_OP if NULL). If SRC_OPERAND is 0, a unary pattern is used. */ +const char * +msp430_output_template (enum machine_mode mode, + rtx * operands, + int src_operand, + const char *init_op, const char *next_op, + const char *prefix) +{ + return output_template (mode, operands, src_operand, false, false, init_op, + next_op, prefix); +} + +const char * +msp430_output_cpux_template (enum machine_mode mode, + rtx * operands, + int src_operand, + const char *init_op, const char *next_op, + const char *prefix) +{ + return output_template (mode, operands, src_operand, false, true, init_op, + next_op, prefix); +} + +const char * +msp430_output_reverse_template (enum machine_mode mode, + rtx * operands, + int src_operand, + const char *init_op, const char *next_op, + const char *prefix) +{ + return output_template (mode, operands, src_operand, true, false, init_op, + next_op, prefix); +} + + +/* Return an instruction template that performs the move without + clobbering registers used in the input. */ +const char * +msp430_mov_noclobber (rtx operands[]) +{ + enum machine_mode mode = GET_MODE (operands[0]); + int delay_reg = -1; + bool reversep = false; + char buffer[1024]; + size_t offset = 0; + int wi; + char end_char; + char shift_char; + const char *mov = "mov"; + + gcc_assert (SImode == mode || SFmode == mode || DImode == mode); + if (msp430x_ext_operand (operands[0], mode) + || msp430x_ext_operand (operands[1], mode)) + mov = "movx"; + + if (!REG_P (operands[0]) + || safe_from_earlyclobber (operands[1], operands[0])) + reversep = false; + else if (REG_P (operands[1])) + reversep = REGNO (operands[0]) > REGNO (operands[1]); + else + { + int index_reg; + int dst_regno = REGNO (operands[0]); + int dst_end_regno = END_REGNO (operands[0]); + + gcc_assert (MEM_P (operands[1])); + for (index_reg = dst_regno; index_reg < dst_end_regno; ++index_reg) + if (reg_mentioned_p (gen_rtx_REG (VOIDmode, index_reg), operands[1])) + break; + if (index_reg == dst_regno) + reversep = true; + else if (index_reg + 1 == dst_end_regno) + reversep = false; + else + { + reversep = false; + delay_reg = index_reg - dst_regno; + } + } + end_char = 'A' + (GET_MODE_SIZE (mode) / UNITS_PER_WORD) - 1; + for (wi = 0; wi < GET_MODE_SIZE (mode) / UNITS_PER_WORD; ++wi) + { + if (wi == delay_reg) + continue; + if (0 < offset) + { + buffer[offset++] = '\n'; + buffer[offset++] = '\t'; + } + shift_char = reversep ? (end_char - wi) : ('A' + wi); + gcc_assert (offset < sizeof(buffer)); + offset += snprintf (buffer + offset, sizeof(buffer) - offset, + "%s\t%%%c1, %%%c0", mov, shift_char, shift_char); + + } + if (0 <= delay_reg) { + gcc_assert (!reversep); + gcc_assert (0 < offset); + gcc_assert (delay_reg < (GET_MODE_SIZE (mode) / UNITS_PER_WORD)); + shift_char = 'A' + delay_reg; + buffer[offset++] = '\n'; + buffer[offset++] = '\t'; + gcc_assert (offset < sizeof(buffer)); + offset += snprintf (buffer + offset, sizeof(buffer) - offset, + "%s\t%%%c1, %%%c0", mov, shift_char, shift_char); + } + gcc_assert (offset < sizeof(buffer)); + return ggc_strdup (buffer); +} + +/* Offset from insn to dest in bytes. If addresses are not known, + returns a value known to be considered "out of range" for a + conditional jump. */ +int +msp430_jump_dist (rtx dest, rtx insn) +{ + int dest_addr; + int cur_addr; + + if (!insn_addresses_) + return 1026; + + dest_addr = INSN_ADDRESSES (INSN_UID (GET_CODE (dest) == LABEL_REF + ? XEXP (dest, 0) : dest)); + cur_addr = INSN_ADDRESSES (INSN_UID (insn)); + return dest_addr - cur_addr; +} + +/* 1 if REGNO is a general register or the stack pointer */ +int +msp430_general_or_stack_reg (int regno) +{ + return MSP430_GENERAL_REGISTER_NUM_P (regno) + || STACK_POINTER_REGNUM == regno; +} + +/* 1 if X is a memory reference through a register suitable for + indirect referencing: @rN. */ +int +msp430_indirect_register_operand (rtx x) +{ + if (!MEM_P (x)) + return 0; + x = XEXP (x, 0); + if (!REG_P (x)) + return 0; + return msp430_general_or_stack_reg (REGNO (x)); +} + +/* 1 if X is a indexed memory reference: X(rN). */ +int +msp430_indexed_register_operand (rtx x) +{ + if (!MEM_P (x)) + return 0; + x = XEXP (x, 0); + if (GET_CODE (x) != PLUS) + return 0; + /* Left addend (Rn) must be an indexing register, but assume that + the assembler will be able to create a constant out of whatever + the right addend (X) is. */ + return msp430_general_or_stack_reg (REGNO (XEXP (x, 0))); +} + +int +msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return 1; +} + +rtx +gen_addP3 (rtx op0, rtx op1, rtx op2) +{ + return gen_rtx_SET (Pmode, op0, gen_rtx_PLUS (Pmode, op1, op2)); +} + +rtx +gen_subP3 (rtx op0, rtx op1, rtx op2) +{ + return gen_rtx_SET (Pmode, op0, gen_rtx_MINUS (Pmode, op1, op2)); +} + +/* Adjustment to overall insn length if the given integer value is the + source for an operation in the given value. Assumption is that the + operation consists of a single MSP430 instruction repeated once for + each word in mode. */ +static int +length_adjustment_for_int (HOST_WIDE_INT ival, enum machine_mode mode) +{ + HOST_WIDE_INT i; + int adjustment = 0; + + switch (mode) + { + case DImode: +#if HOST_BITS_PER_WIDE_INT > 32 + i = trunc_int_for_mode (0xFFFF & (ival >> 48), HImode); + if (MSP430_CG_INT_P (i)) + adjustment -= UNITS_PER_WORD; + i = trunc_int_for_mode (0xFFFF & (ival >> 32), HImode); + if (MSP430_CG_INT_P (i)) + adjustment -= UNITS_PER_WORD; +#endif /* HOST_BITS_PER_WIDE_INT */ + /* FALLTHRU */ + case SImode: + case SFmode: + i = trunc_int_for_mode (0xFFFF & (ival >> 16), HImode); + if (MSP430_CG_INT_P (i)) + adjustment -= UNITS_PER_WORD; + /* FALLTHRU */ + case HImode: + case QImode: + i = trunc_int_for_mode (0xFFFF & (ival >> 0), HImode); + if (MSP430_CG_INT_P (i)) + adjustment -= UNITS_PER_WORD; + break; + case PSImode: + i = trunc_int_for_mode (0xFFFFF & ival, PSImode); + if (MSP430_CG_INT_P (i)) + adjustment -= UNITS_PER_WORD; + break; + default: + break; + } + return adjustment; +} + +/* Adjustment to instruction length if the given op is an immediate + value source for an operation in the given mode. */ +static int +length_adjustment_for_immediate (rtx op, enum machine_mode mode) +{ + int adjustment = 0; + HOST_WIDE_INT ival; + + switch (GET_CODE (op)) + { + case CONST_INT: + ival = INTVAL (op); +#if HOST_BITS_PER_WIDE_INT <= 32 + if (DImode == mode) + adjustment -= 2 * UNITS_PER_WORD; +#endif /* HOST_BITS_PER_WIDE_INT */ + break; + case CONST_DOUBLE: +#if HOST_BITS_PER_WIDE_INT <= 32 + if (4 < GET_MODE_SIZE (mode)) + adjustment += + length_adjustment_for_int (CONST_DOUBLE_HIGH (op), mode); +#endif /* HOST_BITS_PER_WIDE_INT */ + ival = CONST_DOUBLE_LOW (op); + break; + case SYMBOL_REF: + case LABEL_REF: + case CONST: + return 0; + default: + gcc_unreachable (); + } + adjustment += length_adjustment_for_int (ival, mode); + return adjustment; +} + +/* Return the length adjusted for the effects of pattern in the + context of insn. */ +static int +adjust_pattern_length (rtx insn, rtx pattern, int len) +{ +#if TRACE_INSN_LENGTH + int ilen = len; +#endif + + switch (GET_CODE (pattern)) + { + case SET: + { + bool skip_adjustment = false; + enum rtx_code src_code; + bool output_uses_S; + rtx src = SET_SRC (pattern); + rtx src0; + rtx dst = SET_DEST (pattern); + enum machine_mode mode = GET_MODE (dst); + enum attr_instr_format format = get_attr_instr_format (insn); + + if (INSTR_FORMAT_UNDEF == format) + break; + + output_uses_S = push_operand (dst, mode); + src_code = GET_CODE (src); + switch (src_code) + { + case UNSPEC: + switch (XINT (src, 1)) + { + case UNSPEC_PUSH_MULTI: + case UNSPEC_POP_MULTI: + src = gen_rtx_REG (GET_MODE (XVECEXP (src, 0, 2)), + INTVAL (XVECEXP (src, 0, 1))); + break; + case UNSPEC_BITTEST_FOR_CARRY: + gcc_assert (dst == cc0_rtx || CCmode == GET_MODE (dst)); + dst = XVECEXP (src, 0, 0); + src = XVECEXP (src, 0, 1); + break; + default: +#if CHECK_INSN_LENGTH + fprintf (stderr, "Unrecognized unspec code %d in source", + XINT (src, 1)); + debug_rtx (src); +#endif /* CHECK_INSN_LENGTH */ + break; + } + break; + case UNSPEC_VOLATILE: + switch (XINT (src, 1)) + { + case UNSPECV_GET_WATCHDOG_CLEAR_VALUE: + len += UNITS_PER_WORD; + src = XVECEXP (src, 0, 0); + break; + default: + src = XVECEXP (src, 0, 0); + break; + } + break; + case NOT: + case SIGN_EXTEND: + case ZERO_EXTEND: + case BSWAP: + src = XEXP (src, 0); + break; + case AND: /* includes NAND */ + case IOR: + case XOR: + case PLUS: + case MINUS: + case ASHIFT: + src0 = XEXP (src, 0); + if (GET_CODE (src0) == UNSPEC_VOLATILE) + src0 = XVECEXP (src0, 0, 0); + if (rtx_equal_p (dst, src0)) + src = XEXP (src, 1); + else + { + gcc_assert (rtx_equal_p (dst, XEXP (src, 1))); + src = src0; + } + if (src_code == AND && GET_CODE (src) == NOT) + src = XEXP (src, 0); + break; + case CALL: + src = XEXP (src, 0); + gcc_assert (MEM == GET_CODE (src)); + src = XEXP (src, 0); + output_uses_S = true; + break; + case COMPARE: + gcc_assert (dst == cc0_rtx); + src0 = XEXP (src, 0); + if (GET_CODE (src0) == AND) + { + gcc_assert (rtx_equal_p (XEXP (src, 1), const0_rtx)); + src = src0; + } + dst = XEXP (src, 0); + src = XEXP (src, 1); + break; + case IF_THEN_ELSE: + { + static const int condjmp_insn_len = UNITS_PER_WORD; + static const int jmp_insn_len = UNITS_PER_WORD; + static const int offset_len = UNITS_PER_WORD; /* @todo A20 */ + rtx cmp = XEXP (src, 0); + rtx if_loc = XEXP (src, 1); + rtx else_loc = XEXP (src, 2); + int dist = msp430_jump_dist (if_loc, insn); + bool in_range = MSP430_JUMP_IN_RANGE (dist); + + gcc_assert (XEXP (cmp, 0) == cc0_rtx + || (UNSPEC_VOLATILE == GET_CODE (XEXP (cmp, 0)) + && XVECEXP (XEXP (cmp, 0), 0, 0) == cc0_rtx)); + gcc_assert (XEXP (cmp, 1) == const0_rtx); + gcc_assert (else_loc == pc_rtx); + switch (GET_CODE (cmp)) + { + case LE: + case GT: + case LEU: + case GTU: + /* Simulate unsupported comparisons with an extra local jump */ + len += condjmp_insn_len; + /* FALLTHRU */ + case EQ: + case NE: + case LT: + case GE: + case LTU: + case GEU: + /* Out of range will jump around an added br insn + plus immediate offset (@todo A20 update) */ + if (!in_range) + len += jmp_insn_len + offset_len; + break; + default: + gcc_unreachable (); + } + skip_adjustment = true; + } + break; + case RETURN: + skip_adjustment = true; + break; + case CONST_INT: + case MEM: + case REG: + break; + default: +#if CHECK_INSN_LENGTH + fprintf (stderr, "Unrecognized source code %d (%s) in pattern ", + src_code, rtx_name[src_code]); + debug_rtx (pattern); +#endif /* CHECK_INSN_LENGTH */ + break; + } + if (skip_adjustment) + break; + + mode = GET_MODE (dst); + + switch (format) + { + case INSTR_FORMAT_EMU1DD: + case INSTR_FORMAT_EMU1DDX: + src = dst; + format = + (format == + INSTR_FORMAT_EMU1DDX) ? INSTR_FORMAT_FMT1X : INSTR_FORMAT_FMT1; + break; + case INSTR_FORMAT_FMT1: + case INSTR_FORMAT_FMT1X: + case INSTR_FORMAT_FMT2: + case INSTR_FORMAT_FMT2X: + case INSTR_FORMAT_FMT2S: + case INSTR_FORMAT_FMT2XS: + case INSTR_FORMAT_FMT2XN: + case INSTR_FORMAT_FMTA: + case INSTR_FORMAT_CONDJMP: + break; + default: + gcc_unreachable (); + } + + if (register_operand (src, VOIDmode)) + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + else if (format == INSTR_FORMAT_FMT1 + || format == INSTR_FORMAT_FMT1X + || format == INSTR_FORMAT_FMT2S + || format == INSTR_FORMAT_FMT2XS) + { + if (immediate_operand (src, VOIDmode)) + len += length_adjustment_for_immediate (src, mode); + else if (pop_operand (src, VOIDmode)) /* or other auto-increment indirect */ + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + else if (msp430_indirect_register_operand (src)) + { + if (! + ((format == INSTR_FORMAT_FMT2S + || format == INSTR_FORMAT_FMT2XS) && output_uses_S + && REGNO (XEXP (src, 0)) == STACK_POINTER_REGNUM)) + len -= UNITS_PER_WORD; + } + else + { + /* indexed and symbolic accounted for in default length. */ +#if CHECK_INSN_LENGTH + fprintf (stderr, "Unhandled fmt1/fmt2 src "); + debug_rtx (src); +#endif /* CHECK_INSN_LENGTH */ + } + } + else if (format == INSTR_FORMAT_FMT2XN) + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + else if (format == INSTR_FORMAT_FMTA) + { + if (((src_code == PLUS || src_code == MINUS) + && rtx_equal_p (src, const2_rtx)) + || msp430_indirect_register_operand (src)) + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + } + else + { +#if CHECK_INSN_LENGTH + fprintf (stderr, "Unhandled fmt %d src ", format); + debug_rtx (src); +#endif /* CHECK_INSN_LENGTH */ + } + + switch (format) + { + case INSTR_FORMAT_FMT1: + case INSTR_FORMAT_FMT1X: + if (register_operand (dst, mode) || PC == GET_CODE (dst)) + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + break; + case INSTR_FORMAT_FMTA: + case INSTR_FORMAT_FMT2: + case INSTR_FORMAT_FMT2X: + case INSTR_FORMAT_FMT2S: + case INSTR_FORMAT_FMT2XS: + case INSTR_FORMAT_FMT2XN: + case INSTR_FORMAT_CONDJMP: + break; + default: + gcc_unreachable (); + } + break; + } + case PARALLEL: + case SEQUENCE: + { + int i; + for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--) + len = adjust_pattern_length (insn, XVECEXP (pattern, 0, i), len); + break; + } + case USE: + break; + case CALL: + { + rtx src = XEXP (pattern, 0); + gcc_assert (MEM == GET_CODE (src)); + src = XEXP (src, 0); + if (immediate_operand (src, VOIDmode)) + len += length_adjustment_for_immediate (src, HImode); + else if (register_operand (src, VOIDmode)) + len -= UNITS_PER_WORD; + else if (msp430_indirect_register_operand (src)) + { + if (REGNO (XEXP (src, 0)) != STACK_POINTER_REGNUM) + len -= UNITS_PER_WORD; + } + break; + } + case RETURN: + break; + case UNSPEC_VOLATILE: + case CLOBBER: + case ASM_INPUT: + case ASM_OPERANDS: + case ADDR_VEC: + default: +#if CHECK_INSN_LENGTH + fprintf (stderr, "Unhandled insn code %d %s\n", GET_CODE (pattern), + rtx_name[GET_CODE (pattern)]); +#endif /* CHECK_INSN_LENGTH */ + break; + } + +#if TRACE_INSN_LENGTH + fprintf (stderr, "insn len %d to %d format %d ", ilen, len, + get_attr_instr_format (insn)); + debug_rtx (insn); +#endif /* TRACE_INSN_LENGTH */ + return len; +} + +int +msp430_adjust_insn_length (rtx insn, int len) +{ + return adjust_pattern_length (insn, PATTERN (insn), len); +} + +/* Return 1 if X and Y are the same for a sign or zero extension, + i.e. register or memory reference match except in mode. */ +int +msp430_extend_matches (const_rtx x, const_rtx y) +{ + int rc = rtx_equal_p (x, y); + if (rc) + return rc; + if (GET_CODE (x) == REG && GET_CODE (y) == SUBREG && SUBREG_BYTE (y) == 0) + return rtx_equal_p (x, SUBREG_REG (y)); + if (GET_CODE (x) != GET_CODE (y)) + return 0; + if (GET_CODE (x) == REG) + return REGNO (x) == REGNO (y); + if (GET_CODE (x) == MEM) + return (mpys_rtx == x && mpys_b_rtx == y) + || (op2_rtx == x && op2_b_rtx == y) + || rtx_equal_p (XEXP (x, 0), XEXP (y, 0)); + if (GET_CODE (x) == SUBREG) + return SUBREG_BYTE (x) == SUBREG_BYTE (y) + && rtx_equal_p (SUBREG_REG (x), SUBREG_REG (y)); + return 0; +} + +/* x is the destination of an extend operation where the source is of + the given mode. Obtain a compatible reference to the low part of + the destination so we can copy the source into it. */ +static rtx +msp430_extend_force_to_mode (rtx x, enum machine_mode mode) +{ + switch (GET_CODE (x)) + { + case REG: + return gen_lowpart (mode, x); + case MEM: + return adjust_address (x, mode, 0); + break; + case SUBREG: + return simplify_rtx (gen_lowpart_SUBREG (mode, x)); + default: + break; + } + gcc_unreachable (); +} + +/* Expand all {,zero_}extendmn2 instructions. */ +static void +msp430_expand_extend (rtx operands[], bool signed_p) +{ + rtx dst_lo = NULL_RTX; /* hi, or lowpart (si, di) */ + rtx dst_lo_psi = NULL_RTX; /* psi */ + rtx dst_hi = NULL_RTX; /* highpart (hi, si) or highpart (hi, lowpart (si, di)) */ + rtx dst_llo = NULL_RTX; /* lowpart (hi, lowpart (si, di)) */ + rtx dst_lhi = NULL_RTX; /* highpart (hi, lowpart (si, di)) */ + rtx dst_hlo = NULL_RTX; /* lowpart (hi, highpart (si, di)) */ + rtx dst_hhi = NULL_RTX; /* highpart (hi, highpart (si, di)) */ + rtx extended_value; + bool need_copy; + bool need_store_back = false; + + switch (GET_MODE (operands[0])) + { + case HImode: + dst_lo = operands[0]; + break; + case PSImode: + if (MEM_P (operands[0])) + { + /* Do conversion into register and store back, so result + * does not have noise in upper 12 bits */ + dst_lo_psi = gen_reg_rtx (PSImode); + need_store_back = true; + } + else + dst_lo_psi = operands[0]; + dst_lo = gen_lowpart (HImode, dst_lo_psi); + break; + case SImode: + dst_lo = gen_lowpart (HImode, operands[0]); + dst_hi = gen_highpart (HImode, operands[0]); + break; + case DImode: + if (REG_P (operands[0])) + { + dst_llo = gen_rtx_SUBREG (HImode, operands[0], 0); + dst_lhi = gen_rtx_SUBREG (HImode, operands[0], UNITS_PER_WORD); + dst_hlo = gen_rtx_SUBREG (HImode, operands[0], 2 * UNITS_PER_WORD); + dst_hhi = gen_rtx_SUBREG (HImode, operands[0], 3 * UNITS_PER_WORD); + } + else if (MEM_P (operands[0])) + { + dst_llo = adjust_address (operands[0], HImode, 0); + dst_lhi = adjust_address (dst_llo, HImode, UNITS_PER_WORD); + dst_hlo = adjust_address (dst_lhi, HImode, UNITS_PER_WORD); + dst_hhi = adjust_address (dst_hlo, HImode, UNITS_PER_WORD); + } + else + { + debug_rtx (operands[0]); + gcc_unreachable (); + } + dst_lo = dst_llo; + dst_hi = dst_lhi; + break; + default: + gcc_unreachable (); + } + extended_value = signed_p ? NULL_RTX : GEN_INT (0); + need_copy = need_store_back + || !msp430_extend_matches (operands[0], operands[1]); + if (QImode == GET_MODE (operands[1])) + { + rtx dst_qi = msp430_extend_force_to_mode (dst_lo, QImode); + + if (!signed_p && GET_MODE (operands[0]) == HImode + && operands[0] == op2_rtx) + { + emit_insn (gen_andhi3 (dst_lo, dst_lo, GEN_INT (-256))); + return; + } + if (need_copy) + { + if (!signed_p && NULL_RTX != dst_lo_psi) + emit_insn (gen_loadqipsi2 (dst_lo_psi, operands[1])); + else if (!signed_p && register_operand (dst_lo, HImode)) + emit_insn (gen_loadqihi2 (dst_lo, operands[1])); + else + emit_move_insn (dst_qi, operands[1]); + } + if (signed_p) + { + if (dst_lo_psi) + { + rtx l_nonneg = gen_label_rtx (); + rtx t_ge = gen_rtx_GE (QImode, dst_qi, const0_rtx); + emit_jump_insn (gen_cbranchqi4 + (t_ge, dst_qi, const0_rtx, l_nonneg)); + emit_insn (gen_iorpsi3 + (dst_lo_psi, dst_lo_psi, GEN_INT (-256))); + emit_label (l_nonneg); + } + else + emit_insn (gen_extend8bithi1 (dst_lo)); + if (dst_hi) + { + extended_value = copy_to_reg (dst_lo); + emit_insn (gen_bswaphi1 (extended_value)); + emit_insn (gen_extend8bithi1 (extended_value)); + } + } + else + { + if (memory_operand (operands[0], GET_MODE (operands[0]))) + emit_move_insn (gen_highpart (QImode, dst_lo), extended_value); + else if (!need_copy && NULL_RTX != dst_lo_psi) + emit_insn (gen_andpsi3 (dst_lo_psi, dst_lo_psi, GEN_INT (0xff))); + else if (!need_copy) + emit_insn (gen_andhi3 (dst_lo, dst_lo, GEN_INT (0xff))); + } + } + else if (HImode == GET_MODE (operands[1])) + { + if (need_copy) + emit_move_insn (dst_lo, operands[1]); + if (signed_p && NULL_RTX != dst_lo_psi) + { + rtx l_nonneg = gen_label_rtx (); + rtx t_ge = gen_rtx_GE (HImode, dst_lo, const0_rtx); + emit_jump_insn (gen_cbranchhi4 + (t_ge, dst_lo, const0_rtx, l_nonneg)); + emit_insn (gen_iorpsi3 (dst_lo_psi, dst_lo_psi, GEN_INT (-65536))); + emit_label (l_nonneg); + } + else if (signed_p) + { + extended_value = gen_reg_rtx (HImode); + emit_insn (gen_ashrhi3 (extended_value, dst_lo, + GEN_INT (GET_MODE_PRECISION (HImode) - 1))); + } + } + else if (PSImode == GET_MODE (operands[1])) + { + rtx tmp = gen_reg_rtx (PSImode); + emit_move_insn (tmp, operands[1]); + emit_move_insn (dst_lo, gen_lowpart (HImode, tmp)); + extended_value = gen_reg_rtx (HImode); + emit_insn (gen_psinybble2 (tmp, tmp)); + emit_move_insn (extended_value, gen_lowpart (HImode, tmp)); + if (signed_p) + { + rtx l_nonneg = gen_label_rtx (); + rtx l_done = gen_label_rtx (); + rtx t_nz; + + emit_insn (gen_bittesthi2 (extended_value, GEN_INT (8))); + t_nz = gen_rtx_EQ (CCmode, cc0_rtx, const0_rtx); + emit_jump_insn (gen_branchcc (l_nonneg, t_nz)); + emit_insn (gen_iorhi3 + (extended_value, extended_value, GEN_INT (-16))); + emit_jump_insn (gen_jump (l_done)); + emit_barrier (); + emit_label (l_nonneg); + emit_insn (gen_andhi3 + (extended_value, extended_value, GEN_INT (0x0f))); + emit_label (l_done); + } + else + emit_insn (gen_andhi3 + (extended_value, extended_value, GEN_INT (0x0f))); + } + else if (SImode == GET_MODE (operands[1])) + { + if (need_copy) + emit_move_insn (gen_lowpart (SImode, operands[0]), operands[1]); + if (signed_p) + { + extended_value = gen_reg_rtx (HImode); + emit_insn (gen_ashrhi3 (extended_value, dst_hi, + GEN_INT (GET_MODE_PRECISION (HImode) - 1))); + } + dst_hi = NULL_RTX; + } + else + gcc_unreachable (); + if (need_store_back) + { + gcc_assert (PSImode == GET_MODE (operands[0])); + emit_move_insn (operands[0], dst_lo_psi); + } + if (dst_hi) + emit_move_insn (dst_hi, extended_value); + if (dst_hlo) + { + emit_move_insn (dst_hlo, extended_value); + emit_move_insn (dst_hhi, extended_value); + } +} + +/* Expand all (signed) extendmn2 instructions. Return 1 if all + necessary instructions have been emited; returns 0 to fall through + and generate extendqihi2_match. */ +void +msp430_expand_signextend (rtx operands[]) +{ + msp430_expand_extend (operands, true); +} + +/* Expand all zero_extendmn2 instructions. */ +void +msp430_expand_zeroextend (rtx operands[]) +{ + msp430_expand_extend (operands, false); +} + +int +msp430_expand_extract (rtx operands[], bool signed_p) +{ + rtx dst = operands[0]; + rtx bits = operands[1]; + rtx width = operands[2]; + rtx start = operands[3]; + HOST_WIDE_INT mask; + + if (!CONST_INT_P (width) || !CONST_INT_P (start)) + return 0; + if (1 != INTVAL (width)) + return 0; + if (signed_p) + return 0; + mask = (HOST_WIDE_INT) 1 << INTVAL (start); + if (trunc_int_for_mode (mask, GET_MODE (bits)) != mask) + return 0; + gcc_assert (HImode == GET_MODE (dst)); + if (GET_MODE (bits) == QImode) + emit_insn (gen_bittestforcarryqi2 (bits, GEN_INT (mask))); + else + { + gcc_assert (HImode == GET_MODE (bits)); + emit_insn (gen_bittestforcarryhi2 (bits, GEN_INT (mask))); + } + emit_move_insn (dst, const0_rtx); + emit_insn (gen_rlchi1 (dst)); + return 1; +} + +static int +mpy_for_hardware_multiply (enum machine_mode result_mode, + enum machine_mode operand_mode) +{ + bool widen; + int required_mpy = 0; + + if (VOIDmode == operand_mode) + operand_mode = result_mode; + widen = (operand_mode != result_mode); + switch (result_mode) + { + case QImode: + required_mpy = MSP430_MPY_TYPE_16; + break; + case HImode: + required_mpy = MSP430_MPY_TYPE_16; + break; + case SImode: + required_mpy = widen ? MSP430_MPY_TYPE_16 : MSP430_MPY_TYPE_32; + break; + case DImode: + required_mpy = widen ? MSP430_MPY_TYPE_32 : MSP430_MPY_NONE; + break; + default: + required_mpy = MSP430_MPY_NONE; + break; + } + return required_mpy; +} + +void +msp430_expand_mul (rtx operands[], int signed_mul) +{ + rtx m_mpy; + rtx m_op2; + rtx m_reslo; + int required_mpy; + bool widen; + enum machine_mode op0mode = GET_MODE (operands[0]); + enum machine_mode op1mode = GET_MODE (operands[1]); + enum machine_mode op2mode = GET_MODE (operands[2]); + + gcc_assert ((op1mode == op2mode) || CONST_INT_P (operands[2])); + op2mode = op1mode; + widen = (op0mode != op1mode); + gcc_assert (!widen || op0mode == GET_MODE_WIDER_MODE (op1mode) || (SImode == op0mode && HImode == op1mode)); + + required_mpy = mpy_for_hardware_multiply (op0mode, op1mode); + + if (!(msp430_mpy & required_mpy)) + { + rtx libsym = NULL_RTX; + + switch (op0mode) + { + case QImode: + libsym = libsym_mulqi3; + break; + case HImode: + if (widen) + libsym = (signed_mul ? libsym_mulqihi3 : libsym_umulqihi3); + else + libsym = libsym_mulhi3; + break; + case SImode: + if (widen) + libsym = (signed_mul ? libsym_mulhisi3 : libsym_umulhisi3); + else + libsym = libsym_mulsi3; + break; + case DImode: + if (widen) + libsym = (signed_mul ? libsym_mulsidi3 : libsym_umulsidi3); + else + libsym = libsym_muldi3; + break; + default: + gcc_unreachable (); + } + + emit_library_call_value (libsym, operands[0], LCT_CONST, + op0mode, 2, + operands[1], op1mode, operands[2], op1mode); + return; + } + + if (!MSP430_NOINT_HWMUL) + emit_insn (gen_mpy_inhibit_intr ()); + + if (MSP430_MPY_TYPE_16 == required_mpy) + { + m_mpy = signed_mul ? mpys_rtx : mpy_rtx; + m_op2 = op2_rtx; + m_reslo = reslo_rtx; + if (op0mode == QImode) + m_reslo = reslo_b_rtx; + if (op1mode == QImode) + m_mpy = signed_mul ? mpys_b_rtx : mpy_b_rtx; + if (op2mode == QImode) + m_op2 = op2_b_rtx; + + emit_move_insn (m_mpy, operands[1]); + if (op1mode == QImode && signed_mul + && !(msp430_mpy & MSP430_MPY_HAS_SE)) + { + gcc_assert (m_mpy == mpys_b_rtx); + emit_insn (gen_extendqihi2 (mpys_rtx, m_mpy)); + } + emit_move_insn (m_op2, operands[2]); + if (op2mode == QImode && signed_mul + && !(msp430_mpy & MSP430_MPY_HAS_SE)) + emit_insn (gen_extendqihi2 (op2_rtx, m_op2)); + + switch (op0mode) + { + case QImode: + case HImode: + emit_move_insn (operands[0], m_reslo); + break; + case SImode: + emit_move_insn (gen_lowpart (HImode, operands[0]), reslo_rtx); + emit_move_insn (gen_highpart (HImode, operands[0]), reshi_rtx); + break; + default: + gcc_unreachable (); + } + } + else + { + gcc_assert (SImode == op1mode); + emit_move_insn (signed_mul ? mpys32l_rtx : mpy32l_rtx, + gen_lowpart (HImode, operands[1])); + emit_move_insn (signed_mul ? mpys32h_rtx : mpy32h_rtx, + gen_highpart (HImode, operands[1])); + if (CONST_INT_P (operands[2])) + { + HOST_WIDE_INT iv = INTVAL (operands[2]); + emit_move_insn (op2l_rtx, + GEN_INT (trunc_int_for_mode + (iv & ((1 << BITS_PER_WORD) - 1), + HImode))); + emit_move_insn (op2h_rtx, + GEN_INT (trunc_int_for_mode + (iv >> BITS_PER_WORD, HImode))); + } + else + { + gcc_assert (SImode == op2mode); + emit_move_insn (op2l_rtx, gen_lowpart (HImode, operands[2])); + emit_move_insn (op2h_rtx, gen_highpart (HImode, operands[2])); + } + switch (op0mode) + { + case SImode: + emit_move_insn (gen_lowpart (HImode, operands[0]), reslo_rtx); + emit_move_insn (gen_highpart (HImode, operands[0]), reshi_rtx); + break; + case DImode: + { + rtx dst_llo = NULL_RTX; /* lowpart (hi, lowpart (si, di)) */ + rtx dst_lhi = NULL_RTX; /* highpart (hi, lowpart (si, di)) */ + rtx dst_hlo = NULL_RTX; /* lowpart (hi, highpart (si, di)) */ + rtx dst_hhi = NULL_RTX; /* highpart (hi, highpart (si, di)) */ + + if (REG_P (operands[0])) + { + dst_llo = gen_rtx_SUBREG (HImode, operands[0], 0); + dst_lhi = + gen_rtx_SUBREG (HImode, operands[0], UNITS_PER_WORD); + dst_hlo = + gen_rtx_SUBREG (HImode, operands[0], 2 * UNITS_PER_WORD); + dst_hhi = + gen_rtx_SUBREG (HImode, operands[0], 3 * UNITS_PER_WORD); + } + else if (MEM_P (operands[0])) + { + dst_llo = adjust_address (operands[0], HImode, 0); + dst_lhi = adjust_address (dst_llo, HImode, UNITS_PER_WORD); + dst_hlo = adjust_address (dst_lhi, HImode, UNITS_PER_WORD); + dst_hhi = adjust_address (dst_hlo, HImode, UNITS_PER_WORD); + } + else + gcc_unreachable (); + + emit_move_insn (dst_llo, res0_rtx); + emit_move_insn (dst_lhi, res1_rtx); + emit_move_insn (dst_hlo, res2_rtx); + emit_move_insn (dst_hhi, res3_rtx); + break; + } + default: + gcc_unreachable (); + } + } + + if (!MSP430_NOINT_HWMUL) + emit_insn (gen_mpy_restore_intr ()); +} + +enum shift_type_e +{ + ST_INVALID, + ST_ashl, + ST_ashr, + ST_lshr, + ST_lshr_first, + ST_lshr_next +}; + +/* Shift types: (arith << 1) | left */ + +#define ST_IS_ARITH(_st) (ST_ashl == (_st) || ST_ashr == (_st)) +#define ST_IS_LEFT(_st) (ST_ashl == (_st)) + +static void +msp430_expand_libcall_shift (rtx operands[], enum shift_type_e shift_type) +{ + enum machine_mode op0mode = GET_MODE (operands[0]); + bool arith_shift = ST_IS_ARITH (shift_type); + bool left_shift = ST_IS_LEFT (shift_type); + rtx libsym; + + gcc_assert (CONST_INT_P (operands[2]) || QImode == GET_MODE (operands[2])); + gcc_assert (GET_MODE (operands[1]) == op0mode); + switch (op0mode) + { + case QImode: + if (arith_shift) + libsym = (left_shift ? libsym_ashlqi3 : libsym_ashrqi3); + else + libsym = libsym_lshrqi3; + break; + case HImode: + if (arith_shift) + libsym = (left_shift ? libsym_ashlhi3 : libsym_ashrhi3); + else + libsym = libsym_lshrhi3; + break; + case SImode: + if (arith_shift) + libsym = (left_shift ? libsym_ashlsi3 : libsym_ashrsi3); + else + libsym = libsym_lshrsi3; + break; + case DImode: + if (arith_shift) + libsym = (left_shift ? libsym_ashldi3 : libsym_ashrdi3); + else + libsym = libsym_lshrdi3; + break; + default: + gcc_unreachable (); + } + emit_library_call_value (libsym, + operands[0], LCT_CONST, + op0mode, 2, + operands[1], GET_MODE (operands[0]), + operands[2], QImode); +} + +static bool +expand_shift_bitsm1 (rtx r_dst, rtx r_src, enum shift_type_e shift_type) +{ + enum machine_mode opmode = GET_MODE (r_dst); + enum machine_mode word_mode; + rtx parts[4]; + rtx r_word; + rtx r_fill; + rtx r_qi = 0; + int pres; + int pmax; + int nparts = msp430_extract_multiword_operand (opmode, r_src, parts); + + /* The only time it's worth considering doing this operation in + * memory is if src==dst and src is memory and it's an ashl or lshr + * on QImode or HImode, at which point we save one word of ROM. */ + gcc_assert (0 < nparts); + pmax = nparts - 1; + pres = ST_IS_LEFT (shift_type) ? pmax : 0; + if (QImode == opmode) + { + r_word = gen_reg_rtx (HImode); + emit_insn (gen_loadqihi2 (r_word, parts[pmax - pres])); + r_qi = gen_lowpart (QImode, r_word); + } + else + { + r_word = gen_reg_rtx (GET_MODE (parts[pmax - pres])); + emit_move_insn (r_word, parts[pmax - pres]); + } + word_mode = GET_MODE (r_word); + + r_fill = const0_rtx; + if (ST_ashl == shift_type) + { + if (PSImode == word_mode) + emit_insn (gen_rrapsi1 (r_word)); + else + emit_insn (gen_rrahi1 (r_word)); + emit_move_insn (r_word, const0_rtx); + if (QImode == opmode) + emit_insn (gen_rrcqi1 (r_qi)); + else if (PSImode == opmode) + emit_insn (gen_rrcpsi1 (r_word)); + else + emit_insn (gen_rrchi1 (r_word)); + } + else if (ST_ashr == shift_type) + { + if (QImode == opmode) + { + emit_insn (gen_extend8bithi1 (r_word)); + emit_insn (gen_bswaphi1 (r_word)); + } + else if (PSImode == opmode) + { + rtx l_neg = gen_label_rtx (); + rtx l_bottom = gen_label_rtx (); + rtx t_cmp = gen_rtx_LT (word_mode, r_word, const0_rtx); + emit_jump_insn (gen_cbranchpsi4 (t_cmp, r_word, const0_rtx, l_neg)); + emit_move_insn (r_word, const0_rtx); + emit_jump_insn (gen_jump (l_bottom)); + emit_barrier (); + emit_label (l_neg); + emit_move_insn (r_word, constm1_rtx); + emit_label (l_bottom); + } + else + { + emit_insn (gen_bswaphi1 (r_word)); + emit_insn (gen_extend8bithi1 (r_word)); + emit_insn (gen_bswaphi1 (r_word)); + emit_insn (gen_extend8bithi1 (r_word)); + } + r_fill = r_word; + } + else + { + gcc_assert (ST_lshr == shift_type); + if (QImode == opmode) + emit_insn (gen_rlaqi1 (r_qi)); + else if (PSImode == opmode) + emit_insn (gen_rlapsi1 (r_word)); + else + emit_insn (gen_rlahi1 (r_word)); + emit_move_insn (r_word, const0_rtx); + if (PSImode == opmode) + emit_insn (gen_rlcpsi1 (r_word)); + else + emit_insn (gen_rlchi1 (r_word)); + } + + if (QImode == opmode) + emit_insn (gen_storeqi2 (r_dst, r_word)); + else + { + int pi; + + nparts = msp430_extract_multiword_operand (opmode, r_dst, parts); + for (pi = 0; pi < nparts; ++pi) + emit_move_insn (parts[pi], (pres == pi) ? r_word : r_fill); + } + return true; +} + +static void msp430_expand_shift (rtx operands[], + enum shift_type_e shift_type); + +static void +expand_unary_shift (rtx op, int count, enum shift_type_e shift_type) +{ + rtx operands[3]; + + operands[0] = op; + operands[1] = op; + operands[2] = GEN_INT (count); + msp430_expand_shift (operands, shift_type); +} + +static const int shift_loop_overhead_words = 5; /* push?, mov[2?], decr, jne, pop? */ + +static void +msp430_expand_shift (rtx operands[], enum shift_type_e shift_type) +{ + rtx r_src = operands[1]; + rtx r_dst = operands[0]; + rtx l_bottom = NULL_RTX; + rtx r_cnt = NULL_RTX; + rtx r_prec = NULL_RTX; + rtx (*gen_shift) (rtx, rtx) = 0; + enum machine_mode opmode = GET_MODE (r_dst); + bool arith_shift = ST_IS_ARITH (shift_type); + bool left_shift = ST_IS_LEFT (shift_type); + int count; + rtx src_parts[4]; + rtx op_parts[4]; + bool op_is_mem; + bool use_dst_as_op; + bool need_op_init; + bool need_op_store; + int pi; + int pmin; + int pmax; + int nparts; + + if (CONST_INT_P (operands[2])) + { + count = INTVAL (operands[2]) % GET_MODE_PRECISION (opmode); + operands[2] = GEN_INT (count); + } + else + { + /* Load r_cnt with the shift count, truncated within range. */ + count = -1; + r_cnt = gen_reg_rtx (QImode); + emit_move_insn (r_cnt, operands[2]); + if (GET_MODE_PRECISION (GET_MODE (r_dst)) != + GET_MODE_BITSIZE (GET_MODE (r_dst))) + { + rtx libfunc = optab_libfunc (umod_optab, QImode); + rtx l_postcheck = gen_label_rtx (); + rtx t_lt; + + r_prec = gen_reg_rtx (QImode); + t_lt = gen_rtx_LT (QImode, r_cnt, r_prec); + emit_move_insn (r_prec, + GEN_INT (GET_MODE_PRECISION (GET_MODE (r_dst)))); + emit_jump_insn (gen_cbranchqi4 (t_lt, r_cnt, r_prec, l_postcheck)); + gcc_assert (libfunc); + emit_library_call_value (libfunc, r_cnt, LCT_CONST, + GET_MODE (r_cnt), 2, r_cnt, + GET_MODE (r_cnt), r_prec, + GET_MODE (r_prec)); + emit_label (l_postcheck); + } + else + emit_insn (gen_andqi3 + (r_cnt, r_cnt, + GEN_INT (GET_MODE_PRECISION (GET_MODE (r_dst)) - 1))); + } + + gcc_assert (GET_MODE (r_src) == GET_MODE (r_dst)); + + /* If effective shift is zero, do nothing */ + if (0 == count) + { + if (!rtx_equal_p (r_dst, r_src)) + emit_move_insn (r_dst, r_src); + return; + } + + if (count == GET_MODE_PRECISION (opmode) - 1 + && expand_shift_bitsm1 (r_dst, r_src, shift_type)) + return; + + if (msp430_enable_libcall_shift) + { + bool use_libcall = false; + + /* inline loops are smaller than the overhead of setting up for + * a library call plus the size of the library routine itself. + * Assuming that non-constant shifts are rare, prefer libcalls + * for non-constant shifts unless optimizing for size. There is + * no libcall for PSImode, and the repeat feature is smaller and + * faster, so don't use libcalls on CPUX either. */ + if (!optimize_function_for_size_p (cfun) + && !TARGET_CPUX && QImode != opmode && 0 > count) + use_libcall = true; + + if (use_libcall) + { + msp430_expand_libcall_shift (operands, shift_type); + return; + } + } + + /* Canonicalize the count, or note that it's determined at runtime */ + op_is_mem = false; + need_op_store = need_op_init = true; + if (rtx_equal_p (r_src, r_dst) && !register_operand (r_dst, VOIDmode)) + { + /* Potentially decide to put op in memory. */ + } + + nparts = msp430_extract_multiword_operand (opmode, r_src, src_parts); + pmin = 0; + pmax = nparts - 1; + + memset (op_parts, 0, sizeof (op_parts)); + + use_dst_as_op = false; + if (op_is_mem) + use_dst_as_op = true; + else if (QImode == opmode) + { + op_parts[pmin] = gen_reg_rtx (HImode); + emit_insn (gen_loadqihi2 (op_parts[pmin], src_parts[pmin])); + if (ST_ashr == shift_type) + emit_insn (gen_extend8bithi1 (op_parts[pmin])); + need_op_init = false; + } + else if ((count < BITS_PER_WORD) && register_operand (r_dst, VOIDmode)) + use_dst_as_op = true; + + if (use_dst_as_op) + { + if (!rtx_equal_p (r_dst, r_src)) + emit_move_insn (r_dst, r_src); + msp430_extract_multiword_operand (opmode, r_dst, op_parts); + need_op_store = need_op_init = false; + } + else if (!op_parts[0]) + { + if (PSImode == opmode) + { + gcc_assert (1 == nparts); + op_parts[0] = gen_reg_rtx (PSImode); + } + else + for (pi = 0; pi < nparts; ++pi) + op_parts[pi] = gen_reg_rtx (HImode); + } + + /* Optimizations for large shifts in non-fractional modes. */ + if (GET_MODE_BITSIZE (opmode) == GET_MODE_PRECISION (opmode)) + { + if (count >= 48) + { + rtx newop = NULL_RTX; + gcc_assert (4 == nparts); + gcc_assert (need_op_init); + if (ST_IS_LEFT (shift_type)) + { + emit_move_insn (op_parts[3], src_parts[0]); + emit_move_insn (op_parts[2], const0_rtx); + emit_move_insn (op_parts[1], const0_rtx); + emit_move_insn (op_parts[0], const0_rtx); + newop = op_parts[3]; + } + else + { + emit_move_insn (op_parts[0], src_parts[3]); + if (ST_IS_ARITH (shift_type)) + emit_insn (gen_ashrhi_15 (op_parts[3], op_parts[0])); + else + emit_move_insn (op_parts[3], const0_rtx); + emit_move_insn (op_parts[2], op_parts[3]); + emit_move_insn (op_parts[1], op_parts[3]); + newop = op_parts[0]; + } + need_op_init = false; + count -= 48; + if (0 < count) + { + expand_unary_shift (newop, count, shift_type); + count = 0; + } + goto done_op; + } + + if (count >= 32) + { + int base; + rtx r_fill = const0_rtx; + rtx newop = gen_reg_rtx (SImode); + + gcc_assert (4 == nparts); + if (ST_IS_LEFT (shift_type)) + { + emit_move_insn (gen_lowpart (HImode, newop), src_parts[0]); + emit_move_insn (gen_highpart (HImode, newop), src_parts[1]); + base = 2; + } + else + { + emit_move_insn (gen_lowpart (HImode, newop), src_parts[2]); + emit_move_insn (gen_highpart (HImode, newop), src_parts[3]); + base = 0; + if (ST_IS_ARITH (shift_type)) + { + r_fill = gen_reg_rtx (HImode); + emit_insn (gen_ashrhi_15 (r_fill, src_parts[3])); + } + } + count -= 32; + if (0 < count) + { + expand_unary_shift (newop, count, shift_type); + count = 0; + } + emit_move_insn (op_parts[base], gen_lowpart (HImode, newop)); + emit_move_insn (op_parts[base + 1], gen_highpart (HImode, newop)); + emit_move_insn (op_parts[2 - base], r_fill); + emit_move_insn (op_parts[2 - base + 1], r_fill); + need_op_init = false; + goto done_op; + } + + if (count >= 16) + { + gcc_assert (need_op_init); + if (ST_IS_LEFT (shift_type)) + { + for (pi = pmax; pmin < pi; --pi) + emit_move_insn (op_parts[pi], src_parts[pi - 1]); + emit_move_insn (op_parts[pmin], const0_rtx); + ++pmin; + } + else + { + for (pi = pmin; pi < pmax; ++pi) + emit_move_insn (op_parts[pi], src_parts[pi + 1]); + if (ST_IS_ARITH (shift_type)) + emit_insn (gen_ashrhi_15 (op_parts[pmax], src_parts[pmax])); + else + emit_move_insn (op_parts[pmax], const0_rtx); + --pmax; + } + need_op_init = false; + count -= 16; + } + + if (count >= 8) + { + if (need_op_init) + { + for (pi = pmin; pi <= pmax; ++pi) + emit_move_insn (op_parts[pi], src_parts[pi]); + need_op_init = false; + } + + if (ST_IS_LEFT (shift_type)) + { + for (pi = pmax; pmin < pi; --pi) + emit_insn (gen_mwshl8xor (op_parts[pi], op_parts[pi - 1])); + emit_insn (gen_loadqihi2 + (op_parts[pmin], + gen_lowpart (QImode, op_parts[pmin]))); + emit_insn (gen_bswaphi1 (op_parts[pmin])); + } + else + { + emit_insn (gen_bswaphi1 (op_parts[pmin])); + for (pi = pmin; pi < pmax; ++pi) + emit_insn (gen_mwshr8xor (op_parts[pi], op_parts[pi + 1])); + if (ST_ashr == shift_type) + emit_insn (gen_extend8bithi1 (op_parts[pmax])); + else + emit_insn (gen_loadqihi2 + (op_parts[pmax], + gen_lowpart (QImode, op_parts[pmax]))); + } + count -= 8; + } + } + + if (need_op_init) + for (pi = 0; pi < nparts; ++pi) + emit_move_insn (op_parts[pi], src_parts[pi]); + + /* If operation will support repeated or multi-position shift, get + * an expander, and possibly implement the loop if the count is a + * constant. */ + if (TARGET_CPUX && !op_is_mem && 1 == nparts) + { + if (PSImode == opmode) + gen_shift = + left_shift ? gen_ashlnpsi2 : (arith_shift ? gen_ashrnpsi2 : + gen_lshrnpsi2); + else + gen_shift = + left_shift ? gen_ashlnhi2 : (arith_shift ? gen_ashrnhi2 : + gen_lshrnhi2); + while (count >= MSP430_CPUX_MULTISHIFT_MAX) + { + emit_insn (gen_shift + (op_parts[pmin], GEN_INT (MSP430_CPUX_MULTISHIFT_MAX))); + count -= MSP430_CPUX_MULTISHIFT_MAX; + } + if (0 < count) + { + emit_insn (gen_shift (op_parts[pmin], GEN_INT (count))); + count -= count; + } + } + +done_op: + if (need_op_store) + { + if (QImode == opmode && HImode == GET_MODE (op_parts[0])) + emit_insn (gen_storeqi2 (r_dst, op_parts[0])); + else + { + rtx dst_parts[4]; + msp430_extract_multiword_operand (opmode, r_dst, dst_parts); + for (pi = 0; pi < nparts; ++pi) + emit_move_insn (dst_parts[pi], op_parts[pi]); + } + } + + if (0 != count) + { + rtx (*gen_shift_1) (rtx); + rtx l_top = NULL_RTX; + rtx t_ne = NULL_RTX; + bool use_loop; + + switch (opmode) + { + case QImode: + gen_shift_1 = + left_shift ? gen_ashlqi_1 : (arith_shift ? gen_ashrqi_1 : + gen_lshrqi_1); + break; + case HImode: + gen_shift_1 = + left_shift ? gen_ashlhi_1 : (arith_shift ? gen_ashrhi_1 : + gen_lshrhi_1); + break; + case PSImode: + gen_shift_1 = + left_shift ? gen_ashlpsi_1 : (arith_shift ? gen_ashrpsi_1 : + gen_lshrpsi_1); + break; + case SImode: + gen_shift_1 = + left_shift ? gen_ashlsi_1 : (arith_shift ? gen_ashrsi_1 : + gen_lshrsi_1); + break; + case DImode: + gen_shift_1 = + left_shift ? gen_ashldi_1 : (arith_shift ? gen_ashrdi_1 : + gen_lshrdi_1); + break; + default: + gcc_unreachable (); + } + + if (0 > count) + use_loop = true; + else + { + int shift_1_words; + int inline_words; + int loop_words; + + /* Warning: gcc without -Os will unroll loops up to eight + * times, so since we know the count will never exceed 7 + * this doesn't really do much good. */ + shift_1_words = MSP430_MODE_NREGS (opmode); + inline_words = count * shift_1_words; + loop_words = shift_loop_overhead_words + shift_1_words; + use_loop = + inline_words >= + (optimize_function_for_size_p (cfun) ? 1 : 4) * loop_words; + } + + if (use_loop) + { + if (0 < count) + { + gcc_assert (r_cnt == NULL_RTX); + r_cnt = gen_reg_rtx (QImode); + emit_move_insn (r_cnt, GEN_INT (count)); + } + else + { + rtx t_eq; + + gcc_assert (r_cnt); + l_bottom = gen_label_rtx (); + + /* Skip out if the count ends up being zero. */ + t_eq = gen_rtx_EQ (QImode, r_cnt, const0_rtx); + emit_jump_insn (gen_cbranchqi4 + (t_eq, r_cnt, const0_rtx, l_bottom)); + + if (gen_shift) + { + /* PSImode can shift up to 19, but the repeat + * instruction supports only up to 16. If the + * repeat count is larger than supported, generate + * one multishift to bring it down into range. */ + if (PSImode == opmode) + { + rtx l_postcheck = gen_label_rtx (); + rtx r_limit = GEN_INT (MSP430_CPUX_REPEAT_MAX); + rtx t_le = gen_rtx_LE (QImode, r_cnt, r_limit); + + gcc_assert (MSP430_CPUX_REPEAT_MAX + + MSP430_CPUX_MULTISHIFT_MAX >= + GET_MODE_PRECISION (opmode)); + emit_jump_insn (gen_cbranchqi4 + (t_le, r_cnt, r_limit, l_postcheck)); + emit_insn (gen_shift + (op_parts[pmin], + GEN_INT (MSP430_CPUX_MULTISHIFT_MAX))); + emit_insn (gen_subqi3 + (r_cnt, r_cnt, + GEN_INT (MSP430_CPUX_MULTISHIFT_MAX))); + emit_label (l_postcheck); + } + /* Do the whole thing with a single repeated instruction */ + emit_insn (gen_addqi3 (r_cnt, r_cnt, constm1_rtx)); + emit_insn (gen_shift (op_parts[pmin], r_cnt)); + count = 0; + } + } + if (0 != count) + { + l_top = gen_label_rtx (); + emit_label (l_top); + t_ne = gen_rtx_NE (QImode, r_cnt, const0_rtx); + count = 1; + } + } + + while (count--) + emit_insn (gen_shift_1 (r_dst)); + + /* If we have an iterated loop, decrement the shift count and + loop back to do it again. */ + if (l_top) + { + emit_move_insn (r_cnt, plus_constant (r_cnt, -1)); + emit_jump_insn (gen_cbranchqi4 (t_ne, r_cnt, const0_rtx, l_top)); + } + if (l_bottom) + emit_label (l_bottom); + } + + return; +} + +void +msp430_expand_ashl (rtx operands[]) +{ + msp430_expand_shift (operands, ST_ashl); +} + +void +msp430_expand_ashr (rtx operands[]) +{ + msp430_expand_shift (operands, ST_ashr); +} + +void +msp430_expand_lshr (rtx operands[]) +{ + msp430_expand_shift (operands, ST_lshr); +} + +static void +expand_cbranch (enum rtx_code code, rtx op0, rtx op1, rtx loc) +{ + rtx cmp; + enum machine_mode mode; + bool ps0; + bool ps1; + + /* If dest prefers source addressing, and source doesn't, swap + them */ + ps0 = CONSTANT_P (op0) || (MEM_P (op0) && REG_P (XEXP (op0, 0))); + ps1 = CONSTANT_P (op1) || (MEM_P (op1) && REG_P (XEXP (op1, 0))); + if (ps0 && !ps1) + { + rtx tmp = op0; + op0 = op1; + op1 = tmp; + code = swap_condition (code); + } + if (GT == code || GTU == code || LE == code || LEU == code) + { + if (CONSTANT_P (op1)) + { + if (GET_CODE (op1) == CONST_INT) + { + HOST_WIDE_INT new_bound = 1 + INTVAL (op1); + HOST_WIDE_INT new_bound_trunc; + + new_bound_trunc = + trunc_int_for_mode (new_bound, GET_MODE (op0)); + if ((new_bound == new_bound_trunc) + && ((0 != new_bound) || (code != GTU && code != LEU))) + { + op1 = GEN_INT (new_bound); + switch (code) + { + case GT: + code = GE; + break; + case LE: + code = LT; + break; + case GTU: + code = GEU; + break; + case LEU: + code = LTU; + break; + default: + gcc_unreachable (); + } + } + } + } + else + { + rtx tmp = op0; + op0 = op1; + op1 = tmp; + code = swap_condition (code); + } + } + + mode = GET_MODE (op0); + + gcc_assert (GET_MODE_CLASS (mode) == MODE_INT + || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT); + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD + && PSImode != mode) + { + enum rtx_code rcode = reverse_condition (code); + rtx fail = gen_label_rtx (); + rtx parts0[4]; + rtx parts1[4]; + int words; + int w; + + words = msp430_extract_multiword_operand (mode, op0, parts0); + msp430_extract_multiword_operand (mode, op1, parts1); + switch (code) + { + case EQ: + for (w = 0; w < words - 1; ++w) + expand_cbranch (rcode, parts0[w], parts1[w], fail); + expand_cbranch (code, parts0[w], parts1[w], loc); + emit_label (fail); + break; + case NE: + for (w = 0; w < words; ++w) + expand_cbranch (code, parts0[w], parts1[w], loc); + break; + case LT: + case LTU: + case GT: + case GTU: + for (w = words - 1; w > 0; --w) + { + expand_cbranch (code, parts0[w], parts1[w], loc); + expand_cbranch (NE, parts0[w], parts1[w], fail); + code = unsigned_condition (code); + } + expand_cbranch (code, parts0[0], parts1[0], loc); + emit_label (fail); + break; + case LE: + case LEU: + case GE: + case GEU: + for (w = words - 1; w > 0; --w) + { + expand_cbranch (rcode, parts0[w], parts1[w], fail); + expand_cbranch (rcode, parts1[w], parts0[w], loc); + rcode = unsigned_condition (rcode); + } + expand_cbranch (unsigned_condition (code), parts0[0], + parts1[0], loc); + emit_label (fail); + break; + + default: + gcc_unreachable (); + } + return; + } + if (QImode == mode) + emit_insn (gen_setccqi2 (op0, op1)); + else if (PSImode == mode) + emit_insn (gen_setccpsi2 (op0, op1)); + else + { + gcc_assert (HImode == mode); + emit_insn (gen_setcchi2 (op0, op1)); + } + cmp = gen_rtx_fmt_ee (code, CCmode, cc0_rtx, const0_rtx); + emit_jump_insn (gen_branchcc (loc, cmp)); +} + +void +msp430_expand_cbranch (rtx operands[]) +{ + enum rtx_code code = GET_CODE (operands[0]); + rtx op0 = operands[1]; + rtx op1 = operands[2]; + rtx loc = operands[3]; + + gcc_assert (rtx_equal_p (XEXP (operands[0], 0), op0)); + gcc_assert (rtx_equal_p (XEXP (operands[0], 1), op1)); + expand_cbranch (code, op0, op1, loc); +} + +const char * +msp430_output_branchcc (rtx insn, rtx operands[]) +{ + rtx loc = operands[0]; + enum rtx_code cmp = GET_CODE (operands[1]); + int dist = msp430_jump_dist (loc, insn); + int in_range = MSP430_JUMP_IN_RANGE (dist); + + /* If optimization deleted a test instruction that ensured SR.V has + the correct value for a jl/jge opcode, force the instruction to + be emitted. */ + if ((cmp == LT || cmp == GE || cmp == LE || cmp == GT) + && (!(cc_status.flags & (CC_EXPLICIT_COMPARE | CC_NO_OVERFLOW)))) + return 0; + + /* NB: Update the IF_THEN_ELSE block in adjust_pattern_length if + this changes. */ + switch (cmp) + { + case EQ: + return in_range ? "jeq\t%0" : "jne\t1f\n\tbr%@\t#%0\n1:\n"; + case NE: + return in_range ? "jne\t%0" : "jeq\t1f\n\tbr%@\t#%0\n1:\n"; + case LT: + return in_range ? "jl\t%0" : "jge\t1f\n\tbr%@\t#%0\n1:\n"; + case GE: + return in_range ? "jge\t%0" : "jl\t1f\n\tbr%@\t#%0\n1:\n"; + case LTU: + return in_range ? "jlo\t%0" : "jhs\t1f\n\tbr%@\t#%0\n1:\n"; + case GEU: + return in_range ? "jhs\t%0" : "jlo\t1f\n\tbr%@\t#%0\n1:\n"; + case LE: + return in_range ? "jeq\t%0\n\tjl\t%0" : + "jeq\t1f\n\tjge\t2f\n1:\tbr%@\t#%0\n2:\n"; + case GT: + return in_range ? "jeq\t1f\n\tjge\t%0\n1:\n" : + "jeq\t2f\n\tjl\t2f\n1:\tbr%@\t#%0\n2:\n"; + case LEU: + return in_range ? "jeq\t%0\n\tjlo\t%0" : + "jeq\t1f\n\tjhs\t2f\n1:\tbr%@\t#%0\n2:\n"; + case GTU: + return in_range ? "jeq\t1f\n\tjhs\t%0\n1:\n" : + "jeq\t2f\n\tjlo\t2f\n1:\tbr%@\t#%0\n2:\n"; + default: + break; + } + gcc_unreachable (); + return 0; +} + +bool +msp430_inhibited_return_fallthru_p (rtx insn) +{ + struct machine_function *mfp; + + gcc_assert (cfun); + mfp = cfun->machine; + gcc_assert (mfp); + gcc_assert (mfp->frame_flags & MSP430_FF_ready_for_return); + gcc_assert (mfp->frame_flags & MSP430_FF_inhibit_return); + + insn = next_nonnote_insn (insn); + gcc_assert (insn && BARRIER_P (insn)); + insn = next_nonnote_insn (insn); + if (NULL_RTX == insn) + return true; + gcc_assert (LABEL_P (insn)); + return false; +} + +/* 17.2 Driver -- no hooks */ + +/* 17.3 Run-time Target */ + +/* 17.4 Per-Function Data -- no hooks*/ + +/* 17.5: Storage Layout */ + +/* 17.6 Type Layout */ + +/* 17.7 Registers */ + +/* 17.8 Register Classes */ + +static int reg_class_tab[FIRST_VIRTUAL_REGISTER] = { + PC_REG, SP_REG, SR_REG, CG2_REG, /* fixed registers */ + FP_REG, /* maybe fixed reg */ + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, /* unassigned registers r5 - r15 */ + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, + SOFT_ARGP_REG, SOFT_FP_REG, /* fixed pseudo registers */ +}; + +int +msp430_regno_ok_for_base_p (int reg, int strict) +{ + if (strict && reg >= FIRST_PSEUDO_REGISTER && reg_renumber) + reg = reg_renumber[reg]; + if (reg < 0) + return 0; + if (!strict && reg > MSP430_MAX_GENERAL_REGNUM) + return 1; + return reg == STACK_POINTER_REGNUM || MSP430_GENERAL_REGISTER_NUM_P (reg); +} + +enum reg_class +msp430_regno_reg_class (int r) +{ + if (r < (int) (sizeof (reg_class_tab) / sizeof (reg_class_tab[0]))) + return (enum reg_class) reg_class_tab[r]; + + return NO_REGS; +} + +/* 17.9 Old Constraints */ + +/* 17.10 Stack and Calling */ +/* 17.10.5 Elimination */ + +static bool +msp430_frame_pointer_required (void) +{ + return cfun->machine->frame_pointer_required; +} + +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required + +static bool +msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED, const int to_reg) +{ + if (frame_pointer_needed) + return to_reg == HARD_FRAME_POINTER_REGNUM; + return true; +} + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE msp430_can_eliminate + +/* 17.10.7 Register Arguments */ +#undef TARGET_FUNCTION_ARG +/* Defined in msp430-function.c */ +rtx msp430_function_arg (cumulative_args_t, enum machine_mode, const_tree, + bool); +#define TARGET_FUNCTION_ARG msp430_function_arg +#undef TARGET_FUNCTION_ARG_ADVANCE +/* Defined in msp430-function.c */ +void msp430_function_arg_advance (cumulative_args_t, enum machine_mode, + const_tree, bool); +#define TARGET_FUNCTION_ARG_ADVANCE msp430_function_arg_advance + +static bool +msp430_valid_pointer_mode (enum machine_mode mode) +{ + return (mode == HImode || (TARGET_CPUX && mode == PSImode)); +} + +#undef TARGET_VALID_POINTER_MODE +#define TARGET_VALID_POINTER_MODE msp430_valid_pointer_mode + +static enum machine_mode +type_pointer_mode (tree to_type, enum machine_mode mode) +{ + tree d16; + tree d20; + + if (FUNCTION_TYPE == TREE_CODE (to_type)) + { + if (NULL_TREE == lookup_attribute (S_c16, TYPE_ATTRIBUTES (to_type)) + && (TARGET_C20 + || NULL_TREE != lookup_attribute (S_c20, + TYPE_ATTRIBUTES (to_type)))) + return PSImode; + return HImode; + } + d16 = lookup_attribute (S_d16, TYPE_ATTRIBUTES (to_type)); + d20 = lookup_attribute (S_d20, TYPE_ATTRIBUTES (to_type)); + gcc_assert (!d16 || !d20); + if (d16) + return HImode; + if (d20) + return PSImode; + gcc_assert (Pmode == ptr_mode || VOIDmode == ptr_mode); + gcc_assert (ptr_mode == mode); + return mode; +} + +static enum machine_mode +msp430_type_pointer_mode (tree to_type) +{ + return type_pointer_mode (to_type, ptr_mode); +} + +#undef TARGET_TYPE_POINTER_MODE +#define TARGET_TYPE_POINTER_MODE msp430_type_pointer_mode + +static enum machine_mode +msp430_type_address_mode (tree to_type) +{ + return type_pointer_mode (to_type, Pmode); +} + +#undef TARGET_TYPE_ADDRESS_MODE +#define TARGET_TYPE_ADDRESS_MODE msp430_type_address_mode + +static bool +msp430_scalar_mode_supported_p (enum machine_mode mode) +{ + return default_scalar_mode_supported_p (mode) || (TARGET_CPUX + && mode == PSImode); +} + +#undef TARGET_SCALAR_MODE_SUPPORTED_P +#define TARGET_SCALAR_MODE_SUPPORTED_P msp430_scalar_mode_supported_p + +/* 17.10.8 Scalar Return */ +static rtx +msp430_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +{ + int words = MSP430_MODE_NREGS (mode); + if (words > RETURN_REGISTERS_AVAILABLE) + internal_error ("Too many words (%d) for libcall register return", words); + return gen_rtx_REG (mode, (MSP430_RETURN_REGISTER_BASE + 1 - words)); +} + +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE msp430_libcall_value + +static rtx +msp430_function_value (const_tree type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + unsigned HOST_WIDE_INT bytes; + int words; + enum machine_mode tmpmode; + + if (TYPE_MODE (type) != BLKmode) + return msp430_libcall_value (TYPE_MODE (type), 0); + + /* Although we return reg:BLK, explow.c:hard_function_value will + override this to be an integral mode, and we have to round the + size up so the return register is compatible. */ + bytes = int_size_in_bytes (type); + tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT); + while ((tmpmode != VOIDmode) && (PSImode == tmpmode || GET_MODE_SIZE (tmpmode) < bytes)) + tmpmode = GET_MODE_WIDER_MODE (tmpmode); + gcc_assert (tmpmode != VOIDmode); + gcc_assert (tmpmode != PSImode); + words = (GET_MODE_SIZE (tmpmode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + if (words > RETURN_REGISTERS_AVAILABLE) + internal_error ("Too many words (%d) for block register return", words); + + return gen_rtx_REG (BLKmode, (MSP430_RETURN_REGISTER_BASE + 1 - words)); +} +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE msp430_function_value + +/* 17.10.9 Aggregate Return */ +/* Return in memory unless size is determined to be no greater than + * eight bytes. */ +static bool +msp430_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + if (TYPE_MODE (type) == BLKmode) + { + HOST_WIDE_INT size = int_size_in_bytes (type); + return (size == -1 + || size > (RETURN_REGISTERS_AVAILABLE * UNITS_PER_WORD)); + } + return false; +} + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY msp430_return_in_memory + +static void +msp430_encode_section_info (tree decl, rtx rtl, int new_decl_p) +{ + rtx symbol; + + default_encode_section_info (decl, rtl, new_decl_p); + /* Careful not to prod global register variables. */ + if (!MEM_P (rtl)) + return; + symbol = XEXP (rtl, 0); + if (GET_CODE (symbol) != SYMBOL_REF) + return; + if (SYMBOL_REF_FUNCTION_P (symbol)) + { + msp430_function_encode_symbol_flags (decl, symbol); + if (MSP430_SYMBOL_REF_C20_P (symbol)) + { + PUT_MODE (symbol, PSImode); + PUT_MODE (rtl, PSImode); + } + } +} + +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO msp430_encode_section_info + +/* 17.10.11 Function Entry */ +static void +msp430_asm_function_epilogue (FILE * file, + HOST_WIDE_INT size ATTRIBUTE_UNUSED) +{ + struct machine_function *mfp = cfun->machine; + if (mfp->inhibited_return_label != NULL) + ASM_OUTPUT_LABEL (file, mfp->inhibited_return_label); +} +#undef TARGET_ASM_FUNCTION_EPILOGUE +#define TARGET_ASM_FUNCTION_EPILOGUE msp430_asm_function_epilogue + +/* 17.10.13 Tail Calls */ + +/* 17.11 Varargs */ + +/* 17.12 Trampolines */ + +static void +msp430_asm_trampoline_template (FILE * fd) +{ + fprintf (fd, "; TRAMPOLINE HERE\n" + "; move context (either r1 or r4) to r6\n" + "; call function (0xf0f0 will be changed)\n"); + fprintf (fd, "\tmov #0xf0f0, r6\n"); + fprintf (fd, "\tbr #0xf0f0\n"); + fprintf (fd, "; END OF TRAMPOLINE\n\n"); +} + +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE msp430_asm_trampoline_template + +static void +msp430_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (m_tramp, 2)), + static_chain); + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (m_tramp, 6)), fnaddr); +} +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT msp430_trampoline_init + +/* 17.13 Library Calls */ +static void +msp430_init_libfuncs (void) +{ + libsym_mulqi3 = init_one_libfunc ("__mulqi3"); + set_optab_libfunc (smul_optab, QImode, "__mulqi3"); + + libsym_mulqihi3 = init_one_libfunc ("__mulqihi3"); + set_optab_libfunc (smul_widen_optab, HImode, "__mulqihi3"); + libsym_umulqihi3 = init_one_libfunc ("__umulqihi3"); + set_optab_libfunc (umul_widen_optab, HImode, "__umulqihi3"); + libsym_mulhi3 = init_one_libfunc ("__mulhi3"); + set_optab_libfunc (smul_optab, HImode, "__mulhi3"); + + libsym_mulhisi3 = init_one_libfunc ("__mulhisi3"); + set_optab_libfunc (smul_widen_optab, SImode, "__mulhisi3"); + libsym_umulhisi3 = init_one_libfunc ("__umulhisi3"); + set_optab_libfunc (umul_widen_optab, SImode, "__umulhisi3"); + libsym_mulsi3 = init_one_libfunc ("__mulsi3"); + set_optab_libfunc (smul_optab, SImode, "__mulsi3"); + + libsym_mulsidi3 = init_one_libfunc ("__mulsidi3"); + set_optab_libfunc (smul_widen_optab, DImode, "__mulsidi3"); + libsym_umulsidi3 = init_one_libfunc ("__umulsidi3"); + set_optab_libfunc (umul_widen_optab, DImode, "__umulsidi3"); + libsym_muldi3 = init_one_libfunc ("__muldi3"); + set_optab_libfunc (smul_optab, DImode, "__muldi3"); + + /* libcalls used for all divide and remainder operations */ + set_optab_libfunc (sdiv_optab, QImode, "__divqi3"); + set_optab_libfunc (sdiv_optab, HImode, "__divhi3"); + set_optab_libfunc (sdiv_optab, SImode, "__divsi3"); + set_optab_libfunc (sdiv_optab, DImode, "__divdi3"); + set_optab_libfunc (udiv_optab, QImode, "__udivqi3"); + set_optab_libfunc (udiv_optab, HImode, "__udivhi3"); + set_optab_libfunc (udiv_optab, SImode, "__udivsi3"); + set_optab_libfunc (udiv_optab, DImode, "__udivdi3"); + set_optab_libfunc (smod_optab, QImode, "__modqi3"); + set_optab_libfunc (smod_optab, HImode, "__modhi3"); + set_optab_libfunc (smod_optab, SImode, "__modsi3"); + set_optab_libfunc (smod_optab, DImode, "__moddi3"); + set_optab_libfunc (umod_optab, QImode, "__umodqi3"); + set_optab_libfunc (umod_optab, HImode, "__umodhi3"); + set_optab_libfunc (umod_optab, SImode, "__umodsi3"); + set_optab_libfunc (umod_optab, DImode, "__umoddi3"); + + libsym_ashlqi3 = init_one_libfunc ("__ashlqi3"); + set_optab_libfunc (ashl_optab, QImode, "__ashlqi3"); + libsym_ashrqi3 = init_one_libfunc ("__ashrqi3"); + set_optab_libfunc (ashr_optab, QImode, "__ashrqi3"); + libsym_lshrqi3 = init_one_libfunc ("__lshrqi3"); + set_optab_libfunc (lshr_optab, QImode, "__lshrqi3"); + libsym_ashlhi3 = init_one_libfunc ("__ashlhi3"); + set_optab_libfunc (ashl_optab, HImode, "__ashlhi3"); + libsym_ashrhi3 = init_one_libfunc ("__ashrhi3"); + set_optab_libfunc (ashr_optab, HImode, "__ashrhi3"); + libsym_lshrhi3 = init_one_libfunc ("__lshrhi3"); + set_optab_libfunc (lshr_optab, HImode, "__lshrhi3"); + libsym_ashlsi3 = init_one_libfunc ("__ashlsi3"); + set_optab_libfunc (ashl_optab, SImode, "__ashlsi3"); + libsym_ashrsi3 = init_one_libfunc ("__ashrsi3"); + set_optab_libfunc (ashr_optab, SImode, "__ashrsi3"); + libsym_lshrsi3 = init_one_libfunc ("__lshrsi3"); + set_optab_libfunc (lshr_optab, SImode, "__lshrsi3"); + libsym_ashldi3 = init_one_libfunc ("__ashldi3"); + set_optab_libfunc (ashl_optab, DImode, "__ashldi3"); + libsym_ashrdi3 = init_one_libfunc ("__ashrdi3"); + set_optab_libfunc (ashr_optab, DImode, "__ashrdi3"); + libsym_lshrdi3 = init_one_libfunc ("__lshrdi3"); + set_optab_libfunc (lshr_optab, DImode, "__lshrdi3"); + +} +#undef TARGET_INIT_LIBFUNCS +#define TARGET_INIT_LIBFUNCS msp430_init_libfuncs + +/* 17.14 Addressing Modes */ +static bool +msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x, bool strict) +{ +#if 0 + fprintf (stderr, "legitimate_address_p %s %d ", mode_name[mode], strict); + debug_rtx (x); +#endif + switch (GET_CODE (x)) + { + case REG: + return msp430_regno_ok_for_base_p (REGNO (x), strict); + case PLUS: + return REG_P (XEXP (x, 0)) + && msp430_legitimate_address_p (mode, XEXP (x, 0), strict) + && CONSTANT_ADDRESS_P (XEXP (x, 1)); + default: + return CONSTANT_ADDRESS_P (x); + } + gcc_unreachable (); +} +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p + +/* 17.15 Anchored Addresses */ + +/* 17.16 Condition Code */ + +void +msp430_notice_update_cc (rtx exp ATTRIBUTE_UNUSED, rtx insn) +{ + rtx set = single_set (insn); + rtx src; + enum attr_cc cc = get_attr_cc (insn); + + switch (cc) + { + case CC_UNDEF: + default: + gcc_unreachable (); + case CC_NONE: + if (set) + { + if (cc_status.value1 && modified_in_p (cc_status.value1, insn)) + cc_status.value1 = NULL_RTX; + if (cc_status.value2 && modified_in_p (cc_status.value2, insn)) + cc_status.value2 = NULL_RTX; + } + return; + case CC_CLOBBER: + CC_STATUS_INIT; + break; + case CC_N: + case CC_NZ: + case CC_NZC: + case CC_VNZC: + case CC_EXPLICIT: + CC_STATUS_INIT; + gcc_assert (set); + switch (cc) + { + case CC_N: + cc_status.flags |= CC_CLOBBER_V | CC_CLOBBER_Z | CC_CLOBBER_C; + break; + case CC_NZ: + cc_status.flags |= CC_CLOBBER_V | CC_CLOBBER_C; + break; + case CC_NZC: + cc_status.flags |= CC_NO_OVERFLOW; + break; + case CC_EXPLICIT: + cc_status.flags |= CC_EXPLICIT_COMPARE; + break; + default: + break; + } + + if (rtx_equal_p (cc0_rtx, SET_DEST (set))) + { + src = SET_SRC (set); + gcc_assert (COMPARE == GET_CODE (src)); + cc_status.value1 = src; + if (XEXP (src, 1) == const0_rtx) + cc_status.value2 = XEXP (src, 0); + } + else + { + cc_status.value1 = SET_DEST (set); + if (!side_effects_p (SET_SRC (set))) + cc_status.value2 = SET_SRC (set); + } + break; + } + return; +} + +/* 17.17 Costs */ +static bool +msp430_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, + int opno ATTRIBUTE_UNUSED, int *total, bool speed) +{ + enum machine_mode mode = GET_MODE (x); + int words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + bool rv; + + rv = true; + switch (code) + { + case CONST_INT: + { + int cwords = words * UNITS_PER_WORD; + cwords -= length_adjustment_for_int (INTVAL (x), mode); + *total = cwords; + break; + } + case SYMBOL_REF: + *total = COSTS_N_INSNS (words); + break; + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + { + rtx r_count = XEXP (x, 1); + int count; + + if (CONST_INT_P (r_count)) + count = INTVAL (r_count) & (GET_MODE_PRECISION (mode) - 1); + else + count = -1; + + if (msp430_enable_libcall_shift && speed && QImode != mode + && 0 > count) + break; + + if (0 > count) + { + *total = + COSTS_N_INSNS (shift_loop_overhead_words + + words * (1 << GET_MODE_SIZE (mode))); + break; + } + + *total = 0; + while (0 < count) + { + if (GET_MODE_PRECISION (mode) - 1 == count) + { + *total += COSTS_N_INSNS (2); + break; + } + if (count >= 48) + { + *total += words * COSTS_N_INSNS (1); + count -= 48; + words = 1; + continue; + } + if (count >= 32) + { + *total += words * COSTS_N_INSNS (1); + count -= 32; + words = 2; + continue; + } + if (count >= 16) + { + *total += words * COSTS_N_INSNS (1); + count -= 16; + } + if (count >= 8) + { + *total += + 3 * (words - 1) * COSTS_N_INSNS (1) + COSTS_N_INSNS (2); + count -= 8; + } + if (TARGET_CPUX && HImode == mode + && MSP430_CPUX_MULTISHIFT_COUNT_P (count)) + { + while (0 < count) + { + *total += COSTS_N_INSNS (speed ? count - 1 : 1); + count -= MSP430_CPUX_MULTISHIFT_MAX; + } + count = 0; + } + *total += count * words * COSTS_N_INSNS (1); + break; + } + break; + } + + case MULT: + { + rtx r_op2 = XEXP (x, 1); + if (msp430_mpy & mpy_for_hardware_multiply (mode, GET_MODE (r_op2))) + break; + *total = words * COSTS_N_INSNS (10); + if (speed) + { + int mf = GET_MODE_PRECISION (mode); + + if (CONST_INT_P (r_op2)) + { + HOST_WIDE_INT ival = + trunc_int_for_mode (INTVAL (r_op2), mode); + mf = 0; + while (ival) + { + ++mf; + ival = (unsigned HOST_WIDE_INT) ival >> 2; + } + } + *total *= mf; + } + break; + } + case DIV: + case UDIV: + case MOD: + case UMOD: + *total = words * COSTS_N_INSNS (20); + if (speed) + *total *= GET_MODE_BITSIZE (mode); + break; + default: + *total *= words; + rv = false; + break; + } + + return rv; +} +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS msp430_rtx_costs + +static int +msp430_address_costs (rtx x, bool speed) +{ + /* Nothing special now; at some point auto increment/decrement might + * affect this. */ + return rtx_cost (x, MEM, 0, speed); +} +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST msp430_address_costs + +/* 17.18 Scheduling */ + +/* 17.19 Sections */ + +section *msp430_near_text_section; +section *msp430_near_data_section; +section *msp430_near_readonly_data_section; +section *msp430_near_bss_section; +section *msp430_far_text_section; +section *msp430_far_data_section; +section *msp430_far_readonly_data_section; +section *msp430_far_bss_section; +section *msp430_any_text_section; +section *msp430_any_data_section; +section *msp430_any_readonly_data_section; +section *msp430_any_bss_section; + +static const char * const section_prefix[] = { + NULL, + ".near", + ".far", + ".any" +}; + +static void +msp430_asm_init_sections (void) +{ + if (! TARGET_CPUX) + return; + + msp430_near_text_section = get_section (".near" MSP430_TEXT_SECTION_NAME, SECTION_CODE, NULL_TREE); + msp430_near_data_section = get_section (".near" MSP430_DATA_SECTION_NAME, SECTION_WRITE, NULL_TREE); + msp430_near_readonly_data_section = get_section (".near" MSP430_READONLY_DATA_SECTION_NAME, 0, NULL_TREE); + msp430_near_bss_section = get_section (".near" MSP430_BSS_SECTION_NAME, SECTION_WRITE | SECTION_BSS, NULL_TREE); + + msp430_far_text_section = get_section (".far" MSP430_TEXT_SECTION_NAME, SECTION_CODE, NULL_TREE); + msp430_far_readonly_data_section = get_section (".far" MSP430_READONLY_DATA_SECTION_NAME, 0, NULL_TREE); +#if MSP430_NO_FAR_RAM + /* Until there are MSP430 chips with RAM above 64KB, use the base + * writable sections for far writable data. */ + msp430_far_data_section = data_section; + msp430_far_bss_section = bss_section; +#else + msp430_far_data_section = get_section (".far" MSP430_DATA_SECTION_NAME, SECTION_WRITE, NULL_TREE); + msp430_far_bss_section = get_section (".far" MSP430_BSS_SECTION_NAME, SECTION_WRITE | SECTION_BSS, NULL_TREE); +#endif + + msp430_any_text_section = get_section (".any" MSP430_TEXT_SECTION_NAME, SECTION_CODE, NULL_TREE); + msp430_any_data_section = get_section (".any" MSP430_DATA_SECTION_NAME, SECTION_WRITE, NULL_TREE); + msp430_any_readonly_data_section = get_section (".any" MSP430_READONLY_DATA_SECTION_NAME, 0, NULL_TREE); + msp430_any_bss_section = get_section (".any" MSP430_BSS_SECTION_NAME, SECTION_WRITE | SECTION_BSS, NULL_TREE); +} + +#undef TARGET_ASM_INIT_SECTIONS +#define TARGET_ASM_INIT_SECTIONS msp430_asm_init_sections + +static int +msp430_reloc_rw_mask (void) +{ + /* MSP430 does not support -fpic. The default behavior of this hook + quietly refers to flag_pic; in case that changes, or somebody + wants to support -fpic on MSP430, make it more clear that work + needs to be done. By ensuring this always returns zero, we + simplify the logic taken from categorize_decl_for_section in the + hook implementations below. */ + return 0; +} +#undef TARGET_ASM_RELOC_RW_MASK +#define TARGET_ASM_RELOC_RW_MASK msp430_reloc_rw_mask + +/* Return a nonzero value if DECL has a section attribute. */ +#define IN_NAMED_SECTION(DECL) \ + ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \ + && DECL_SECTION_NAME (DECL) != NULL_TREE) + +static bool +bss_initializer_p (const_tree decl) +{ + return (DECL_INITIAL (decl) == NULL + || DECL_INITIAL (decl) == error_mark_node + || (flag_zero_initialized_in_bss + /* Leave constant zeroes in .rodata so they + can be shared. */ + && !TREE_READONLY (decl) + && initializer_zerop (DECL_INITIAL (decl)))); +} + +static int +secregion_for_decl (const_tree decl) +{ + /* Force CPUX interrupts into explicitly near text */ + if (TARGET_CPUX + && FUNCTION_DECL == TREE_CODE (decl) + && NULL_TREE != lookup_attribute (S_interrupt, DECL_ATTRIBUTES (decl))) + return MSP430_SECTION_REGION_NEAR; + if (! TARGET_CPUX) + return MSP430_SECTION_REGION_DEFAULT; + if (VAR_OR_FUNCTION_DECL_P (decl)) + { + bool has_near_attr; + bool has_far_attr; + + has_near_attr = NULL_TREE != lookup_attribute (S_near, DECL_ATTRIBUTES (decl)); + has_far_attr = NULL_TREE != lookup_attribute (S_far, DECL_ATTRIBUTES (decl)); + gcc_assert(!(has_near_attr && has_far_attr)); + + if (has_near_attr) + return MSP430_SECTION_REGION_NEAR; + if (has_far_attr) + return MSP430_SECTION_REGION_FAR; + if (FUNCTION_DECL == TREE_CODE (decl)) + { + tree type_decls = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + + /* C16 must be in near memory. C20 does not have to be in + far memory. */ + if (NULL_TREE != lookup_attribute (S_c16, type_decls)) + return MSP430_SECTION_REGION_NEAR; + } + if (TARGET_C20 && FUNCTION_DECL == TREE_CODE (decl)) + return msp430_code_region; + if (TARGET_D20 && VAR_DECL == TREE_CODE (decl)) + return msp430_data_region; + } + if (TARGET_D20) + return msp430_data_region; + return MSP430_SECTION_REGION_DEFAULT; +} + +static int +secregion_from_section_name (const char * section_name) +{ + gcc_assert (section_name); + if (0 == strncmp (".near.", section_name, 6)) + return MSP430_SECTION_REGION_NEAR; + if (0 == strncmp (".far.", section_name, 5)) + return MSP430_SECTION_REGION_FAR; + if (0 == strncmp (".any.", section_name, 5)) + return MSP430_SECTION_REGION_ANY; + return MSP430_SECTION_REGION_DEFAULT; +} + +static const char * +standard_section_name (section *sect) +{ + if (text_section == sect) + return MSP430_TEXT_SECTION_NAME; + if (data_section == sect) + return MSP430_DATA_SECTION_NAME; + if (readonly_data_section == sect) + return MSP430_READONLY_DATA_SECTION_NAME; + if (bss_section == sect) + return MSP430_BSS_SECTION_NAME; + gcc_unreachable (); +} + +static section * +regioned_section_for_name (int secregion, + section *sect, + const char* suffix, + unsigned int flags, + tree decl) +{ + size_t len = 0; + char * name; + const char * prefix; + const char * section_name; + +#if MSP430_NO_FAR_RAM + if (MSP430_SECTION_REGION_FAR == secregion + && (data_section == sect || bss_section == sect)) + secregion = MSP430_SECTION_REGION_ANY; +#endif /* MSP430_NO_FAR_RAM */ + prefix = section_prefix[secregion]; + section_name = standard_section_name (sect); + if (prefix) + len += strlen (prefix); + len += strlen (section_name); + if (suffix) + len += strlen (suffix); + name = (char *) alloca (len + 1); + *name = 0; + if (prefix) + strcat (name, prefix); + strcat (name, section_name); + if (suffix) + strcat (name, suffix); + if (bss_section == sect) + flags |= SECTION_BSS; + gcc_assert(! (MSP430_SECTION_REGION_FAR == secregion && (data_section == sect || bss_section == sect))); + return get_section (name, flags, decl); +} + +static section * +regioned_section_for_region (int secregion, + section * sect) +{ + if (MSP430_SECTION_REGION_DEFAULT == secregion) + return sect; + gcc_assert (MSP430_SECTION_REGION_NEAR == secregion || MSP430_SECTION_REGION_FAR == secregion || MSP430_SECTION_REGION_ANY == secregion); + if (text_section == sect) + return MSP430_SECTION_REGION_NEAR == secregion ? msp430_near_text_section + : MSP430_SECTION_REGION_FAR == secregion ? msp430_far_text_section + : msp430_any_text_section; + if (readonly_data_section == sect) + return MSP430_SECTION_REGION_NEAR == secregion ? msp430_near_readonly_data_section + : MSP430_SECTION_REGION_FAR == secregion ? msp430_far_readonly_data_section + : msp430_any_readonly_data_section; + if (data_section == sect) + return MSP430_SECTION_REGION_NEAR == secregion ? msp430_near_data_section + : MSP430_SECTION_REGION_FAR == secregion ? msp430_far_data_section + : msp430_any_data_section; + if (bss_section == sect) + return MSP430_SECTION_REGION_NEAR == secregion ? msp430_near_bss_section + : MSP430_SECTION_REGION_FAR == secregion ? msp430_far_bss_section + : msp430_any_bss_section; + gcc_unreachable (); +} + +static section * +regioned_section_for_decl (const_tree decl, + section * sect) +{ + return regioned_section_for_region (secregion_for_decl (decl), sect); +} + +static section * +msp430_select_section (tree decl, int reloc ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) +{ + section *sect; + + gcc_assert (! IN_NAMED_SECTION (decl)); + if (FUNCTION_DECL == TREE_CODE (decl)) + gcc_unreachable (); + else if (STRING_CST == TREE_CODE (decl)) + { + if (current_function_decl + && DECL_SECTION_NAME (current_function_decl) + && flag_function_sections && flag_data_sections) + { + const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (current_function_decl)); + int secregion = secregion_from_section_name (name); + int decl_secregion = MSP430_SECTION_REGION_DEFAULT; + + if (MSP430_SECTION_REGION_DEFAULT != secregion) + { + name = strchr (name+1, '.'); + decl_secregion = secregion_for_decl (decl); + } + + if (0 != name && 0 == strncmp (".text.", name, 6)) + return regioned_section_for_name (decl_secregion, + readonly_data_section, name+5, + 0, decl); + } + sect = readonly_data_section; + } + else if (VAR_DECL == TREE_CODE (decl)) + { + if (bss_initializer_p (decl)) + sect = bss_section; + else if (! TREE_READONLY (decl) + || TREE_SIDE_EFFECTS (decl) + || ! TREE_CONSTANT (DECL_INITIAL (decl))) + sect = data_section; + else + sect = readonly_data_section; + } + else if (CONSTRUCTOR == TREE_CODE (decl)) + { + if (TREE_SIDE_EFFECTS (decl) + || ! TREE_CONSTANT (decl)) + sect = data_section; + else + sect = readonly_data_section; + } + else + sect = readonly_data_section; + + return regioned_section_for_decl (decl, sect); +} +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION msp430_select_section + +static void +msp430_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED) +{ + section *sect; + int secregion = secregion_for_decl (decl); + const char *region, *name; + char *string; + + if (FUNCTION_DECL == TREE_CODE (decl)) + sect = text_section; + else if (STRING_CST == TREE_CODE (decl)) + sect = readonly_data_section; + else if (VAR_DECL == TREE_CODE (decl)) + { + if (bss_initializer_p (decl)) + sect = bss_section; + else if (! TREE_READONLY (decl) + || TREE_SIDE_EFFECTS (decl) + || ! TREE_CONSTANT (DECL_INITIAL (decl))) + sect = data_section; + else + sect = readonly_data_section; + } + else if (CONSTRUCTOR == TREE_CODE (decl)) + { + if (TREE_SIDE_EFFECTS (decl) + || ! TREE_CONSTANT (decl)) + sect = data_section; + else + sect = readonly_data_section; + } + else + sect = readonly_data_section; + +#if MSP430_NO_FAR_RAM + if (MSP430_SECTION_REGION_FAR == secregion + && (data_section == sect || bss_section == sect)) + secregion = MSP430_SECTION_REGION_ANY; +#endif + + if (MSP430_SECTION_REGION_DEFAULT == secregion) + region = ""; + else if (MSP430_SECTION_REGION_NEAR == secregion) + region = ".near"; + else if (MSP430_SECTION_REGION_FAR == secregion) + region = ".far"; + else + { + gcc_assert (MSP430_SECTION_REGION_ANY == secregion); + region = ".any"; + } + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + name = targetm.strip_name_encoding (name); + + string = ACONCAT ((region, standard_section_name (sect), ".", name, NULL)); + + DECL_SECTION_NAME (decl) = build_string (strlen (string), string); +} +#undef TARGET_ASM_UNIQUE_SECTION +#define TARGET_ASM_UNIQUE_SECTION msp430_unique_section + +/* This function is invoked through + * target.asm_out.function_rodata_section() when emitting a jump + * table. The size of the addresses in the jump table are controlled + * by FUNCTION_MODE which follows TARGET_C20, but the placement of the + * table should follow the placement of the function to which it + * belongs. Always place the data in the default region; in medium + * memory model code could be in the far region but the jump table + * can't be because the pointer into it is limited to 16 bits. */ +static section * +msp430_function_rodata_section (tree decl) +{ + section * sect = readonly_data_section; + + gcc_assert (NULL_TREE != decl); + /* Follow default_function_rodata_section in cases where it looks + like the function was placed in a specific named section. */ + if (DECL_SECTION_NAME (decl) && flag_function_sections) + { + const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); + /* Skip prefix if it's a region encoding */ + if (MSP430_SECTION_REGION_DEFAULT != secregion_from_section_name (name)) + name = strchr (name+1, '.'); + if (0 != name && 0 == strncmp (".text.", name, 6)) + return regioned_section_for_name (MSP430_SECTION_REGION_DEFAULT, + sect, name+5, 0, decl); + } + /* Correct the default section if inconsistent with the address + space attributes. */ + return regioned_section_for_region (MSP430_SECTION_REGION_DEFAULT, sect); +} +#undef TARGET_ASM_FUNCTION_RODATA_SECTION +#define TARGET_ASM_FUNCTION_RODATA_SECTION msp430_function_rodata_section + +/* 17.20 PIC -- not supported */ + +/* 17.21 Assembler Format */ +/* 17.21.1 File Framework */ +static void +msp430_file_start (void) +{ + FILE *file = asm_out_file; + const struct tag_value_pair_t *mp; + + output_file_directive (file, main_input_filename); + if (msp430_mcu_name) + fprintf (file, "\t.arch %s\n", msp430_mcu_name); + mp = find_pair_by_value (msp430_cpu, cpu_tag_value_map); + if (mp) + fprintf (file, "\t.cpu %s\n", mp->tag); + mp = find_pair_by_value (msp430_mpy, mpy_tag_value_map); + if (mp) + fprintf (file, "\t.mpy %s\n", mp->tag); + if (TARGET_CPUX) + { + int elts = 0; + fprintf (file, "\t.cpux_target\t"); + if (TARGET_A20) + fprintf (file, "%sa20", elts++ ? "," : ""); + if (TARGET_C20) + fprintf (file, "%sc20", elts++ ? "," : ""); + if (TARGET_D20) + fprintf (file, "%sd20", elts++ ? "," : ""); + if (TARGET_SR20) + fprintf (file, "%ssr20", elts++ ? "," : ""); + if (TARGET_ISR20) + fprintf (file, "%sisr20", elts++ ? "," : ""); + if (0 == elts) + fprintf (file, "none"); + fputc ('\n', file); + } + fprintf (file, "\n"); +} +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START msp430_file_start + +#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE +#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true + +/* TARGET_ASM_NAMED_SECTION is defined in msp430.h */ + +static int +contains_pointers_p (tree type) +{ + switch (TREE_CODE (type)) + { + case POINTER_TYPE: + case REFERENCE_TYPE: + /* I'm not sure whether OFFSET_TYPE needs this treatment, + so I'll play safe and return 1. */ + case OFFSET_TYPE: + return 1; + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + tree fields; + /* For a type that has fields, see if the fields have pointers. */ + for (fields = TYPE_FIELDS (type); fields; fields = DECL_CHAIN (fields)) + if (TREE_CODE (fields) == FIELD_DECL + && contains_pointers_p (TREE_TYPE (fields))) + return 1; + return 0; + } + + case ARRAY_TYPE: + /* An array type contains pointers if its element type does. */ + return contains_pointers_p (TREE_TYPE (type)); + + default: + return 0; + } +} + +static section * +msp430_variable_section (tree decl, bool prefer_noswitch_p) +{ + int reloc; + bool has_as_attr; + + has_as_attr = (NULL_TREE != lookup_attribute (S_near, DECL_ATTRIBUTES (decl)) + || NULL_TREE != lookup_attribute (S_far, DECL_ATTRIBUTES (decl))); + if (DECL_COMMON (decl) && !has_as_attr) + { + /* If the decl has been given an explicit section name, or it resides + in a non-generic address space, then it isn't common, and shouldn't + be handled as such. */ + gcc_assert (DECL_SECTION_NAME (decl) == NULL && !has_as_attr); + if (DECL_THREAD_LOCAL_P (decl)) + return tls_comm_section; + else if (TREE_PUBLIC (decl) && bss_initializer_p (decl)) + return comm_section; + } + + if (DECL_INITIAL (decl) == error_mark_node) + reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0; + else if (DECL_INITIAL (decl)) + reloc = compute_reloc_for_constant (DECL_INITIAL (decl)); + else + reloc = 0; + + resolve_unique_section (decl, reloc, flag_data_sections); + if (IN_NAMED_SECTION (decl)) + return get_named_section (decl, NULL, reloc); + + if (!has_as_attr + && !DECL_THREAD_LOCAL_P (decl) + && !(prefer_noswitch_p && targetm.have_switchable_bss_sections) + && bss_initializer_p (decl)) + { + if (!TREE_PUBLIC (decl)) + return lcomm_section; + if (bss_noswitch_section) + return bss_noswitch_section; + } + + return targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl)); +} +#undef TARGET_ASM_VARIABLE_SECTION +#define TARGET_ASM_VARIABLE_SECTION msp430_variable_section + +static section * +msp430_function_section (tree decl, enum node_frequency freq ATTRIBUTE_UNUSED, + bool startup ATTRIBUTE_UNUSED, + bool exit ATTRIBUTE_UNUSED) +{ + gcc_assert (NULL_TREE != decl); + + /* Inline standard hot_function_section */ + if (DECL_SECTION_NAME (decl) != NULL_TREE + && targetm_common.have_named_sections) + return get_named_section (decl, NULL, 0); + gcc_assert (FUNCTION_DECL == TREE_CODE (decl)); + return regioned_section_for_decl (decl, text_section); +} +#undef TARGET_ASM_FUNCTION_SECTION +#define TARGET_ASM_FUNCTION_SECTION msp430_function_section + +unsigned int +msp430_section_type_flags (tree decl, const char *name, int reloc) +{ + unsigned int flags = default_section_type_flags (decl, name, reloc); + const char *suffix = strrchr (name, '.'); + + if (!strcmp (name, ".noinit") + || !strcmp (name, ".infomemnobits") + || (suffix && 0 == strcmp (suffix, ".bss"))) + { + if (!strcmp (name, ".infomemnobits")) + warning_at (DECL_SOURCE_LOCATION (decl), 0, + _(".infomemnobits is deprecated; use .infomem.bss")); + if (!decl + || (TREE_CODE (decl) == VAR_DECL + && DECL_INITIAL (decl) == NULL_TREE)) + flags |= SECTION_BSS; /* @nobits */ + else + warning_at (DECL_SOURCE_LOCATION (decl), 0, + "only uninitialized variables can be placed in a .bss section"); + } + + /* Default implementation called above handles most cases, but not + * bss which has to be inferred from the section name not decl + * features. That only applies to variable decls without + * initializers, though: somebody puts an initializer into an + * explicitly bss section and it'll complain, just like it + * should. */ + if (!decl + || (TREE_CODE (decl) == VAR_DECL + && bss_initializer_p (decl))) + { + size_t spi = 0; + while (!(flags & SECTION_BSS) + && spi < sizeof(section_prefix)/sizeof(*section_prefix)) + { + const char* p = name; + if (section_prefix[spi]) { + size_t prefix_len = strlen (section_prefix[spi]); + if (0 == strncmp(section_prefix[spi], p, prefix_len)) + p += prefix_len; + } + if (0 == strcmp(".bss", p) + || 0 == strncmp(".bss.", p, 5)) + flags |= SECTION_BSS; + ++spi; + } + } + + return flags; +} +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS msp430_section_type_flags + +/* 17.21.2 Data Output */ + +static bool +msp430_assemble_integer (rtx x, unsigned int size, int aligned_p) +{ + if (GET_MODE (x) != PSImode) + return default_assemble_integer (x, size, aligned_p); + fputs ("\t.long\t", asm_out_file); + output_addr_const (asm_out_file, x); + fputc ('\n', asm_out_file); + return true; +} +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER msp430_assemble_integer + +#undef TARGET_ASM_ALIGNED_HI_OP +#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" + +/* 17.21.4 Label Output */ + +void +msp430_asm_declare_function_name (FILE * file, const char *name, tree decl) +{ + struct machine_function *mfp = cfun->machine; + bool is_isr = NULL_TREE != mfp->interrupt; + int vector = -1; + + if (is_isr && (0 <= mfp->vector_offset)) + { + vector = mfp->vector_offset / 2; + if (0 < msp430_ivcnt && (vector >= msp430_ivcnt)) + { + error_at (DECL_SOURCE_LOCATION (decl), + _ + ("interrupt vector %d is beyond end of MCU vector table"), + vector); + vector = -1; + is_isr = false; + } + } + + ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); + fprintf (file, "/***********************\n"); + if (!is_isr) + fprintf (file, " * Function `"); + else if (0 > vector) + fprintf (file, " * Interrupt Sub-Routine `"); + else + fprintf (file, " * Interrupt Vector %d Service Routine `", vector); + assemble_name (file, name); + fprintf (file, "' %s\n ***********************/\n", + (cfun->machine->critical != NULL_TREE) + ? "(OS critical)" + : (cfun->machine->reentrant != NULL_TREE) ? "(reentrant)" : ""); + ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); + if (0 <= vector) + { + char isrname[32]; + size_t nw; + nw = snprintf (isrname, sizeof (isrname), "__isr_%u", vector); + gcc_assert (nw < sizeof (isrname)); + targetm.asm_out.globalize_label (file, isrname); + ASM_OUTPUT_LABEL (file, isrname); + } +} + +/* 17.21.7 Instruction Output */ + +static const char *trim_array[] = { "llo", "lhi", "hlo", "hhi" }; + +static void +print_sub_operand (FILE * file, rtx x, int code) +{ + + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + output_addr_const (file, x); + else if (GET_CODE (x) == CONST) + print_sub_operand (file, XEXP (x, 0), code); + else if (GET_CODE (x) == PLUS) + { + print_sub_operand (file, XEXP (x, 0), code); + fprintf (file, "+"); + print_sub_operand (file, XEXP (x, 1), code); + } + else if (GET_CODE (x) == CONST_INT) + fprintf (file, "%ld", INTVAL (x)); + else + gcc_unreachable (); +} + +static bool +msp430_print_operand_punct_valid_p (unsigned char code) +{ + return ('@' == code) || default_print_operand_punct_valid_p (code); +} + +#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P +#define TARGET_PRINT_OPERAND_PUNCT_VALID_P msp430_print_operand_punct_valid_p + +void +msp430_print_operand (FILE * file, rtx x, int code) +{ + int shift = 0; + + if ('@' == code) + { + if (TARGET_CPUX) + fputc ('a', file); + return; + } + + if (code >= 'A' && code <= 'D') + shift = code - 'A'; + else if (code != 0 && code != 'S') + gcc_unreachable (); + + if (REG_P (x)) + fputs (reg_names[REGNO (x) + shift], file); + else if (GET_CODE (x) == CONST_INT) + { + HOST_WIDE_INT intval = INTVAL (x); + + /* For improved ASM readability, omit #llo(const) for small constants */ + if (0 == code || (0 == shift && !(intval & ~0xFFFF))) + fprintf (file, "#%d", (int) intval); + else + fprintf (file, "#%s(%ld)", trim_array[shift], intval); + } + else if (GET_CODE (x) == MEM) + { + rtx addr = XEXP (x, 0); + + if (GET_CODE (addr) == POST_INC) + fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]); + else if (GET_CODE (addr) == REG) + { /* for X(Rn) */ + int regno = REGNO (addr); + const char *regname = reg_names[regno]; + + if (code == 'S' && regno == STACK_POINTER_REGNUM) + fprintf (file, "%d(%s)", UNITS_PER_WORD, regname); + else if (shift) + fprintf (file, "%d(%s)", shift * UNITS_PER_WORD, regname); + else + fprintf (file, "@%s", regname); + } + else if (GET_CODE (addr) == SYMBOL_REF) + { + fprintf (file, "&"); + output_addr_const (file, addr); + if (shift) + fprintf (file, "+%d", shift * UNITS_PER_WORD); + } + else if (GET_CODE (addr) == CONST || GET_CODE (addr) == CONST_INT) + { + fputc ('&', file); + output_addr_const (file, addr); + if (shift) + fprintf (file, "+%d", shift * UNITS_PER_WORD); + } + else if (GET_CODE (addr) == PLUS) + { + rtx base = XEXP (addr, 0); + rtx offset = XEXP (addr, 1); + int regno = REGNO (base); + const char *regname = reg_names[regno]; + + gcc_assert (REG_P (base)); + print_sub_operand (file, offset, code); + if (code == 'S' && regno == STACK_POINTER_REGNUM) + fprintf (file, "+%d(%s)", UNITS_PER_WORD, regname); + else + { + if (shift) + fprintf (file, "+%d", shift * UNITS_PER_WORD); + fprintf (file, "(%s)", regname); + } + } + else + gcc_unreachable (); + } + else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF + || GET_CODE (x) == CONST) + { + if (shift) + error (_("unable to get high part of constant")); + fprintf (file, "#"); + output_addr_const (file, x); + } + else if (GET_CODE (x) == CODE_LABEL) + output_addr_const (file, x); + else if (GET_CODE (x) == CONST_DOUBLE) + { + if (GET_MODE (x) == VOIDmode) /* FIXME: may be long long?? */ + { + if (shift < 2) + fprintf (file, "#%s(%ld)", trim_array[shift], + CONST_DOUBLE_LOW (x)); + else + fprintf (file, "#%s(%ld)", trim_array[shift - 2], + CONST_DOUBLE_HIGH (x)); + } + else if (GET_MODE (x) == SFmode || GET_MODE (x) == SImode) + { + long val; + REAL_VALUE_TYPE rv; + REAL_VALUE_FROM_CONST_DOUBLE (rv, x); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + asm_fprintf (file, "#%s(0x%lx)", trim_array[shift], val); + } + else + gcc_unreachable (); + } + else + gcc_unreachable (); +} + +/* 17.21.9 Assembler Commands for Exception Regions */ + +/* 17.25 Target Attributes */ + +static int +msp430_comp_type_attributes (const_tree type1, + const_tree type2) +{ + tree d16a = lookup_attribute (S_d16, TYPE_ATTRIBUTES (type1)); + tree d16b = lookup_attribute (S_d16, TYPE_ATTRIBUTES (type2)); + tree d20a = lookup_attribute (S_d20, TYPE_ATTRIBUTES (type1)); + tree d20b = lookup_attribute (S_d20, TYPE_ATTRIBUTES (type2)); + + if ((d16a || d16b) && (d20a || d20b)) + return 0; + if ((d16a != d16b) || (d20a != d20b)) + return 2; + return 1; +} +#undef TARGET_COMP_TYPE_ATTRIBUTES +#define TARGET_COMP_TYPE_ATTRIBUTES msp430_comp_type_attributes + +static tree +msp430_merge_type_attributes (tree type1, + tree type2) +{ + tree d16a = lookup_attribute (S_d16, TYPE_ATTRIBUTES (type1)); + tree d16b = lookup_attribute (S_d16, TYPE_ATTRIBUTES (type2)); + tree d20a = lookup_attribute (S_d20, TYPE_ATTRIBUTES (type1)); + tree d20b = lookup_attribute (S_d20, TYPE_ATTRIBUTES (type2)); + + /* Failure of these assertions is a mistake in user code which + * should be diagnosed. */ + if (((NULL_TREE == d16a) != (NULL_TREE == d16b)) + || ((NULL_TREE == d20a) != (NULL_TREE == d20b))) + error (_("merged types have inconsistent d16/d20 attributes")); + return merge_type_attributes (type1, type2); +} +#undef TARGET_MERGE_TYPE_ATTRIBUTES +#define TARGET_MERGE_TYPE_ATTRIBUTES msp430_merge_type_attributes + +/* We want the type, but modified to have the specified d16/d20 + * attribute. We can't use build_type_attribute_variant, because we + * also want the main type variant to be the same as the type without + * the attribute: otherwise &(int d16 v) is not type compatible with + * int*. Need to use this both for the implicit d16 added when a + * declaration is near, and when it appears explicitly as with the + * peripheral registers. */ +static tree +msp430_build_type_d_variant (tree ttype, + const char * d_string) +{ + tree ntype; + int quals = TYPE_QUALS (ttype); + tree attribute = TYPE_ATTRIBUTES (ttype); + char * d_string_u; + + /* Use the underscore variant of the attribute identifier */ + d_string_u = (char *) alloca (4 + 1 + strlen (d_string)); + sprintf (d_string_u, "__%s__", d_string); + attribute = tree_cons (get_identifier (d_string_u), NULL_TREE, attribute); + + ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED); + ntype = build_variant_type_copy (ttype); + TYPE_ATTRIBUTES (ntype) = attribute; + ntype = build_qualified_type (ntype, quals); + return ntype; +} + +static tree +handle_decl_attribute (tree * node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool * no_add) +{ + tree decl_attrs = DECL_ATTRIBUTES (*node); + tree type_attrs = TYPE_ATTRIBUTES (TREE_TYPE (*node)); + const char * propagated_attr_name = NULL; + tree conflicting_attr = NULL_TREE; + + if (MSP430_MATCH_ATTRIBUTE_NAME (S_near, name)) + { + conflicting_attr = lookup_attribute (S_far, decl_attrs); + if (!conflicting_attr && FUNCTION_DECL != TREE_CODE (*node)) + conflicting_attr = lookup_attribute (S_d20, type_attrs); + propagated_attr_name = S_d16; + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_far, name)) + { + conflicting_attr = lookup_attribute (S_near, decl_attrs); + if (!conflicting_attr && FUNCTION_DECL != TREE_CODE (*node)) + conflicting_attr = lookup_attribute (S_d16, type_attrs); + propagated_attr_name = S_d20; + } + else + { + if (TREE_CODE (*node) == FUNCTION_DECL) + return msp430_handle_fndecl_attribute (node, name, args, flags, no_add); + warning (OPT_Wattributes, _("%qE attribute ignored"), name); + *no_add = true; + return NULL_TREE; + } + if (conflicting_attr) + { + warning (OPT_Wattributes, _("%qE cannot combine with %qE"), name, + TREE_PURPOSE (conflicting_attr)); + *no_add = true; + return NULL_TREE; + } + + if (!*no_add && FUNCTION_DECL != TREE_CODE (*node) && propagated_attr_name) + TREE_TYPE (*node) = msp430_build_type_d_variant (TREE_TYPE (*node), propagated_attr_name); + + return NULL_TREE; +} + +static tree +handle_type_attribute (tree * node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool * no_add) +{ + tree type = *node; + tree type_attrs = TYPE_ATTRIBUTES (*node); + tree conflicting_attr = NULL; + tree new_node = NULL_TREE; + + if (MSP430_MATCH_ATTRIBUTE_NAME (S_a16, name) + || MSP430_MATCH_ATTRIBUTE_NAME (S_a20, name)) + { + if (!TARGET_CPUX) + { + warning (OPT_Wattributes, + _("%qE attribute ignored when MCU is not 430x-capable"), + name); + *no_add = true; + return NULL_TREE; + } + if (MSP430_MATCH_ATTRIBUTE_NAME (S_a16, name)) + conflicting_attr = lookup_attribute (S_a20, type_attrs); + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_a20, name)) + conflicting_attr = lookup_attribute (S_a16, type_attrs); + else + gcc_unreachable (); + + if (INTEGRAL_TYPE_P (type) + && SImode == TYPE_MODE (type) + && MSP430_MATCH_ATTRIBUTE_NAME (S_a20, name)) + { + gcc_assert (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)); + if (TYPE_UNSIGNED (type)) + new_node = msp430_a20_unsigned_type_node; + else + new_node = msp430_a20_integer_type_node; + } + else if (POINTER_TYPE_P (type)) + { + gcc_assert (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)); + if (MSP430_MATCH_ATTRIBUTE_NAME (S_a16, name)) + new_node = build_pointer_type_for_mode (TREE_TYPE (type), HImode, true); + else + new_node = build_pointer_type_for_mode (TREE_TYPE (type), PSImode, true); + } + else + { + error (_("%qE cannot be applied to %qT"), name, type); + *no_add = true; + } + if (new_node && TYPE_QUALS (type)) + new_node = build_qualified_type (new_node, TYPE_QUALS (type)); + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_c16, name) + || MSP430_MATCH_ATTRIBUTE_NAME (S_c20, name) + || MSP430_MATCH_ATTRIBUTE_NAME (S_d16, name) + || MSP430_MATCH_ATTRIBUTE_NAME (S_d20, name)) + { + if (!TARGET_CPUX) + { + warning (OPT_Wattributes, _("%qE requires CPUX-capable MCU"), name); + *no_add = true; + return NULL_TREE; + } + + if (MSP430_MATCH_ATTRIBUTE_NAME (S_c16, name) + || MSP430_MATCH_ATTRIBUTE_NAME (S_c20, name)) + { + new_node = *node; + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + new_node = build_variant_type_copy (new_node); + + if (TREE_CODE (new_node) == POINTER_TYPE + && (TREE_CODE (TREE_TYPE (new_node)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (new_node)) == METHOD_TYPE)) + { + type_attrs = TYPE_ATTRIBUTES (TREE_TYPE (new_node)); + TREE_TYPE (new_node) = build_type_attribute_variant + (TREE_TYPE (new_node), + tree_cons (name, args, + TYPE_ATTRIBUTES (TREE_TYPE (new_node)))); + *no_add = true; + } + else if (!(TREE_CODE (new_node) == FUNCTION_TYPE + || TREE_CODE (new_node) == METHOD_TYPE)) + { + type_attrs = NULL_TREE; + warning (OPT_Wattributes, _("%qE not handled on type %qT"), name, + type); + *no_add = true; + new_node = NULL_TREE; + } + + if (type_attrs) + { + if (MSP430_MATCH_ATTRIBUTE_NAME (S_c16, name)) + conflicting_attr = lookup_attribute (S_c20, type_attrs); + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_c20, name)) + conflicting_attr = lookup_attribute (S_c16, type_attrs); + else + gcc_unreachable (); + } + } + else + { + const char * propagated_attr_name; + + if (MSP430_MATCH_ATTRIBUTE_NAME (S_d16, name)) + { + conflicting_attr = lookup_attribute (S_d20, type_attrs); + propagated_attr_name = S_d16; + } + else if (MSP430_MATCH_ATTRIBUTE_NAME (S_d20, name)) + { + conflicting_attr = lookup_attribute (S_d16, type_attrs); + propagated_attr_name = S_d20; + } + else + gcc_unreachable (); + + if (TREE_CODE (*node) == FUNCTION_TYPE + || TREE_CODE (*node) == METHOD_TYPE) + { + warning (OPT_Wattributes, _("%qE not handled on type %qT"), name, + type); + *no_add = true; + } + else + { + gcc_assert (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)); + new_node = msp430_build_type_d_variant (*node, propagated_attr_name); + } + } + } + else + { + warning (OPT_Wattributes, _("%qE not handled on type %qT"), name, type); + *no_add = true; + new_node = NULL_TREE; + } + if (NULL_TREE != conflicting_attr) + { + warning (OPT_Wattributes, _("%qE cannot combine with %qE"), name, + TREE_PURPOSE (conflicting_attr)); + *no_add = true; + new_node = NULL_TREE; + } + if (new_node) + *node = new_node; + return NULL_TREE; +} + +const struct attribute_spec msp430_attribute_table[] = { + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ + {"signal", 0, 0, true, false, false, handle_decl_attribute, false}, + {S_interrupt, 0, 1, true, false, false, handle_decl_attribute, false}, + {"naked", 0, 0, true, false, false, handle_decl_attribute, false}, + {"task", 0, 0, true, false, false, handle_decl_attribute, false}, + {"wakeup", 0, 0, true, false, false, handle_decl_attribute, false}, + {"critical", 0, 0, true, false, false, handle_decl_attribute, false}, + {"reentrant", 0, 0, true, false, false, handle_decl_attribute, false}, + {"saveprologue", 0, 0, true, false, false, handle_decl_attribute, false}, + {"noint_hwmul", 0, 0, true, false, false, handle_decl_attribute, false}, + {"hosted", 0, 0, true, false, false, handle_decl_attribute, false}, + {"sr16", 0, 0, true, false, false, handle_decl_attribute, false}, + {"sr20", 0, 0, true, false, false, handle_decl_attribute, false}, + {S_near, 0, 0, true, false, false, handle_decl_attribute, false}, + {S_far, 0, 0, true, false, false, handle_decl_attribute, false}, + {S_a16, 0, 0, false, true, false, handle_type_attribute, false}, + {S_a20, 0, 0, false, true, false, handle_type_attribute, false}, + {S_c16, 0, 0, false, true, false, handle_type_attribute, false}, + {S_c20, 0, 0, false, true, false, handle_type_attribute, false}, + {S_d16, 0, 0, false, true, false, handle_type_attribute, false}, + {S_d20, 0, 0, false, true, false, handle_type_attribute, false}, + {NULL, 0, 0, false, false, false, NULL, false} +}; + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table + +/* Defined in msp430-function.c */ +#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P msp430_function_attribute_inlinable_p + +static rtx +gen_rtx_HWREG (enum machine_mode mode, const char *name) +{ + rtx ret = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (mode, name)); + MEM_VOLATILE_P (ret) = 1; + return ret; +} + +static struct machine_function * +msp430_init_machine_status (void) +{ + return ggc_alloc_cleared_machine_function (); +} + +static void +msp430_init_once (void) +{ + init_machine_status = msp430_init_machine_status; + + if (msp430_mpy & MSP430_MPY_TYPE_16) + { + mpy_b_rtx = gen_rtx_HWREG (QImode, "__MPY"); + mpys_b_rtx = gen_rtx_HWREG (QImode, "__MPYS"); + op2_b_rtx = gen_rtx_HWREG (QImode, "__OP2"); + reslo_b_rtx = gen_rtx_HWREG (QImode, "__RESLO"); + mpy_rtx = gen_rtx_HWREG (HImode, "__MPY"); + mpys_rtx = gen_rtx_HWREG (HImode, "__MPYS"); + op2_rtx = gen_rtx_HWREG (HImode, "__OP2"); + reslo_rtx = gen_rtx_HWREG (HImode, "__RESLO"); + reshi_rtx = gen_rtx_HWREG (HImode, "__RESHI"); + } + if (msp430_mpy & MSP430_MPY_TYPE_32) + { + mpy32l_rtx = gen_rtx_HWREG (HImode, "__MPY32L"); + mpy32h_rtx = gen_rtx_HWREG (HImode, "__MPY32H"); + mpys32l_rtx = gen_rtx_HWREG (HImode, "__MPYS32L"); + mpys32h_rtx = gen_rtx_HWREG (HImode, "__MPYS32H"); + op2l_rtx = gen_rtx_HWREG (HImode, "__OP2L"); + op2h_rtx = gen_rtx_HWREG (HImode, "__OP2H"); + res0_rtx = gen_rtx_HWREG (HImode, "__RES0"); + res1_rtx = gen_rtx_HWREG (HImode, "__RES1"); + res2_rtx = gen_rtx_HWREG (HImode, "__RES2"); + res3_rtx = gen_rtx_HWREG (HImode, "__RES3"); + } + return; +} + +static void +msp430_option_override (void) +{ + if (flag_pic) + error ("PIC not supported on msp430"); + + if (msp430_mcu_name) + { + char *up = strchr (msp430_mcu_name, '_'); + if (NULL != up) + *up = 0; + } + + if (!TARGET_CPUX) + { + if (MSP430_MEMORY_MODEL_NONE != msp430_memory_model) + error (_("mmemory-model requires CPUX-capable MCU")); + if (TARGET_SR20) + error (_("msr20 requires CPUX-capable MCU")); + if (TARGET_A20) + error (_("ma20 requires CPUX-capable MCU")); + if (TARGET_C20) + error (_("mc20 requires CPUX-capable MCU")); + if (TARGET_D20) + error (_("md20 requires CPUX-capable MCU")); + } + + /* GCC 4.7.x induction variable optimization misbehaves when + size_type and ptr_type have different precisions. */ + if (!!TARGET_D20 != !!TARGET_A20) + flag_ivopts = 0; + + flag_defer_pop = 0; + + msp430_init_once (); +} + +#undef TARGET_OPTION_OVERRIDE +#define TARGET_OPTION_OVERRIDE msp430_option_override + +/* 17.26 Emulated TLS */ +/* 17.27 MIPS Coprocessors -- not relevant */ +/* 17.28 PCH Target */ +/* 17.29 C++ ABI */ +/* 17.30 Named Address Spaces */ + +/* 17.31 Misc */ + +static void +msp430_build_common_tree_nodes (void) +{ + msp430_a20_integer_type_node = make_signed_type (20); + msp430_a20_unsigned_type_node = make_unsigned_type (20); +} +#undef TARGET_BUILD_COMMON_TREE_NODES +#define TARGET_BUILD_COMMON_TREE_NODES msp430_build_common_tree_nodes + +static int +msp430_size_type_precision (void) +{ + return TARGET_A20 ? 20 : 0; +} +#undef TARGET_SIZE_TYPE_PRECISION +#define TARGET_SIZE_TYPE_PRECISION msp430_size_type_precision + +static tree +msp430_size_type_tree (void) +{ + return TARGET_A20 ? msp430_a20_unsigned_type_node : NULL_TREE; +} +#undef TARGET_SIZE_TYPE_TREE +#define TARGET_SIZE_TYPE_TREE msp430_size_type_tree + +static tree +msp430_ptrdiff_type_tree (void) +{ + return TARGET_A20 ? msp430_a20_integer_type_node : NULL_TREE; +} +#undef TARGET_PTRDIFF_TYPE_TREE +#define TARGET_PTRDIFF_TYPE_TREE msp430_ptrdiff_type_tree + +static tree +msp430_c_common_type_for_size (unsigned int bits, int unsignedp) +{ + if (!TARGET_CPUX || 20 != bits) + return NULL_TREE; + return unsignedp ? msp430_a20_unsigned_type_node : msp430_a20_integer_type_node; +} +#undef TARGET_C_COMMON_TYPE_FOR_SIZE +#define TARGET_C_COMMON_TYPE_FOR_SIZE msp430_c_common_type_for_size + +static tree +msp430_c_common_signed_or_unsigned_type (int unsignedp, tree type) +{ + tree type1; + + if (!TARGET_CPUX) + return NULL_TREE; + type1 = TYPE_MAIN_VARIANT (type); + if (type1 == msp430_a20_integer_type_node || type1 == msp430_a20_unsigned_type_node) + return unsignedp ? msp430_a20_unsigned_type_node : msp430_a20_integer_type_node; + return NULL_TREE; +} +#undef TARGET_C_COMMON_SIGNED_OR_UNSIGNED_TYPE +#define TARGET_C_COMMON_SIGNED_OR_UNSIGNED_TYPE msp430_c_common_signed_or_unsigned_type + +/* Defined in msp430-c.c */ +bool +msp430_cpp_builtin_define_type_minmax (const char *min_macro, + const char *max_macro, + tree type); +/* If we're not linked with msp430-c.o, provide a default */ +bool __attribute__((__weak__)) +msp430_cpp_builtin_define_type_minmax (const char *min_macro ATTRIBUTE_UNUSED, + const char *max_macro ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED) +{ + return false; +} +#undef TARGET_CPP_BUILTIN_DEFINE_TYPE_MINMAX +#define TARGET_CPP_BUILTIN_DEFINE_TYPE_MINMAX msp430_cpp_builtin_define_type_minmax + +/* Defined in msp430-builtins.c */ +void msp430_init_builtins (void); +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS msp430_init_builtins + +/* Defined in msp430-builtins.c */ +rtx msp430_expand_builtin (tree, rtx, rtx, enum machine_mode, int); +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN msp430_expand_builtin + +/* Defined in msp430-function.c */ +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION msp430_set_current_function + +static bool +msp430_cannot_modify_jumps_p (void) +{ + if (reload_completed && cfun && cfun->machine) + return ! !(cfun->machine->frame_flags & MSP430_FF_inhibit_return); + return false; +} + +#undef TARGET_CANNOT_MODIFY_JUMPS_P +#define TARGET_CANNOT_MODIFY_JUMPS_P msp430_cannot_modify_jumps_p + + +/* 17.1 Target Structure */ +struct gcc_target targetm = TARGET_INITIALIZER; + +#include "gt-msp430.h" diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430.h gcc-4.7.0/gcc/config/msp430/msp430.h new file mode 100644 index 0000000..b740c28 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430.h @@ -0,0 +1,776 @@ +/* This work is partially financed by the European Commission under the + * Framework 6 Information Society Technologies Project + * "Wirelessly Accessible Sensor Populations (WASP)". + */ + +/* Definitions of target machine for GNU compiler, + for Texas Instruments MSP430 microcontrollers. + Copyright (C) 2001-2009 Free Software Foundation, Inc. + Contributed by Dmitry Diky + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef GCC_MSP430_H +#define GCC_MSP430_H + +/* The GCC internals manual (http://gcc.gnu.org/onlinedocs/gccint, but + * only if you're working on the trunk) defines the current standard + * back-end expectations. See Chapter 17 "Target Macros". + * + * Target macros and hooks should not be defined if the default + * behavior is correct for the platform. To make it clear that the + * maintainer is aware of the macro and has verified it, it may be + * defined to be its default in a comment with a prefix DEFAULT: to + * make it clear this is a comment, not droppings from disabled code + * (see, for example, PTR_DIFF_TYPE below). + */ + +/** Update this on each release */ +#define MSP430_MSPGCC_VERSION 20120911 + +#include "config/msp430/msp430-opts.h" + +#define TARGET_CPUX (msp430_cpu & MSP430_CPU_MSP430X) + +int msp430_current_function_noint_hwmul_function_p (void); +#define MSP430_NOINT_HWMUL (msp430_current_function_noint_hwmul_function_p()) + +/* 1 if the integral value can be produced by the MSP430 CG registers */ +#define MSP430_CG_INT_P(VALUE) \ + ((-1 == (VALUE)) \ + || (0 == (VALUE)) \ + || (1 == (VALUE)) \ + || (2 == (VALUE)) \ + || (4 == (VALUE)) \ + || (8 == (VALUE))) + +/* Maximum number of positions a single CPUX multi-position shift + * operation can take. */ +#define MSP430_CPUX_MULTISHIFT_MAX 4 + +/* 1 if the integral value can be the shift count in a CPUX + * multi-position shift operation. */ +#define MSP430_CPUX_MULTISHIFT_COUNT_P(VALUE) \ + (1 <= (VALUE) && (VALUE) <= MSP430_CPUX_MULTISHIFT_MAX) + +/* Maximum number of repetitions a single CPUX extension word repeat + * count supports. */ +#define MSP430_CPUX_REPEAT_MAX 16 + +/* 1 if the integral value can be the repeat count in a CPUX + * extension word */ +#define MSP430_CPUX_REPEAT_COUNT_P(VALUE) \ + (1 <= (VALUE) && (VALUE) <= MSP430_CPUX_REPEAT_MAX) + +/* GCC's version of this is private to attrib.c */ +#define MSP430_MATCH_ATTRIBUTE_NAME(_s,_t) \ + msp430_match_attribute_name (_s, strlen(_s), _t) + +/* 16.19.5 Insn Lengths */ +#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ + (LENGTH = msp430_adjust_insn_length (INSN, LENGTH)) + +/* Conservative guess whether jump is going to be in range. If false + positive, assembler or linker will reject. If false negative, code + will be larger than necessary. Err on the side of working code. + + Note that the distance is in units (bytes), not words; the + underlying instruction supports -1024 to 1022 as it stores the + offset in words as a signed 10-bit value. */ +#define MSP430_JUMP_IN_RANGE(_d) (-500 <= (_d) && (_d) <= 500) + +/* 17.1 Target Structure -- defined in msp430.c */ + +/* 17.2 Driver */ +/* On startup read the spec file that translates known MCUs into + * device-specific flags (note: this is an msp430 extension to the + * upstream driver). Also ensure we have -mcpu, -mmpy, and -mivcnt + * configurations derived from the mcu. */ +#define DRIVER_SELF_SPECS \ + "%:include-noerr(msp430mcu.spec)" \ + " %(msp430_cpu)" \ + " %(msp430_mpy)" \ + " %(msp430_ivcnt)" \ + " %(msp430_memmodel)" +/* Accept -posix; invoke a special function to + * rote-translate -mmcu options into preprocessor definition + * options. */ +#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %:msp430_mcucpp(%{mmcu=*:%*})" +/* Provide device-specific -mivcnt, -mcpu, -mmpy options. */ +#define CC1_SPEC "%{profile:-p} %{mcpu=*} %{mmpy=*} %{mivcnt=*}" +/* TODO: legacy value */ +#define CC1PLUS_SPEC "-fno-rtti -fno-exceptions" +/* Pass MCU-related options to the assembler. */ +#define ASM_SPEC "%{mcpu=*} %{mmcu=*}" +/* Do not add -lg when linking statically */ +#define LIB_SPEC "%{!shared:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}" +/* Use the msp430 linker emulation */ +#define LINK_SPEC "-m msp430" +/* Select the corresponding interrupt vector initializer based on + * mivcnt. */ +#define STARTFILE_SPEC \ + "%{mivcnt=16:crt0ivtbl16%O%s} " \ + "%{mivcnt=32:crt0ivtbl32%O%s} " \ + "%{mivcnt=64:crt0ivtbl64%O%s}" +/* Select between CRTs that retain the watchdog or disable it on reset */ +#define ENDFILE_SPEC \ + "%{mno-disable-watchdog|!mdisable-watchdog:-lcrt0; :-lcrt0dwdt}" +const char *msp430_mcucpp (int argc, const char **argv); +const char *msp430_mculdscriptpaths (int argc, const char **argv); +#define EXTRA_SPEC_FUNCTIONS \ + { "msp430_mcucpp", msp430_mcucpp }, \ + { "msp430_mculdscriptpaths", msp430_mculdscriptpaths }, +/* Default values when -mmcu not provided. We also need these to + * explicitly set flags that affect multilibs. */ +#define EXTRA_SPECS \ + { "msp430_cpu", "%{!mcpu=*:%{mcpu=430}}" }, \ + { "msp430_mpy", "%{!mmpy=*:%{mmpy=none}}" }, \ + { "msp430_ivcnt", "%{!mivcnt=*:%{mivcnt=16}}" }, \ + { "msp430_memmodel", "%{" \ + "mmemory-model=small:-ma16 -mc16 -md16 -msr20;" \ + "mmemory-model=medium:-ma16 -mc20 -md16 -msr20;" \ + "mmemory-model=large:-ma16 -mc20 -md20 -msr20;" \ + "mmemory-model=huge:-ma20 -md20 -mc20 -msr20;" \ + ":}" } +/* Override this. The value is essentially the default from gcc.c, + * but we need to be able to define a default linker script derived + * from the -mmcu parameter, and it has to be at the end; it doesn't + * work when placed after the emulation in LINK_SPEC. */ +#define LINK_COMMAND_SPEC "\ +%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ + %(linker) " \ + LINK_PLUGIN_SPEC \ + "%{flto|flto=*:%= (MSP430_ARG_REGISTER_BASE - MSP430_ARG_REGISTER_COUNT + 1) \ + && R <= MSP430_ARG_REGISTER_BASE) +/* 17.10.8 Scalar Return */ +/* TODO: Replace with target function */ +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == MSP430_RETURN_REGISTER_BASE) +/* 17.10.9 Aggregate Return */ +#define DEFAULT_PCC_STRUCT_RETURN 0 +/* 17.10.10 Caller Saves */ +/* 17.10.11 Function Entry */ +#define EPILOGUE_USES(REGNO) msp430_epilogue_uses(REGNO) +/* 17.10.12 Profiling */ +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "/* profiler %d */", LABELNO) +/* 17.10.13 Tail Calls */ +/* 17.10.14 Stack Smashing Protection */ + +/* 17.11 Varargs (no macros relevant) */ + +/* 17.12 Trampolines */ +#define TRAMPOLINE_SIZE 8 +#define TRAMPOLINE_ALIGNMENT BITS_PER_WORD + +/* 17.13 Library Calls */ +#define TARGET_LIB_INT_CMP_BIASED true + +/* 17.14 Addressing Modes */ +#define HAVE_POST_INCREMENT 1 +#define MAX_REGS_PER_ADDRESS 1 + +/* 17.15 Anchored Addresses */ + +/* 17.16 Condition Code */ +#define NOTICE_UPDATE_CC(EXP, INSN) msp430_notice_update_cc (EXP, INSN) + +/* Extend conditions.h to explicitly note cases where the carry flag + is invalid; these mostly are rotate-through-carry, and + multi-instruction operations on 32- or 64-bit values. (Note that + the standard CC_NO_OVERFLOW is being used to refer to SR.V being + reset.) */ +#define CC_CLOBBER_C 0x1000 + +/* Extend conditions.h to explicitly note cases where the zero flag is + invalid; these mostly are multi-instruction operations on 32- or + 64-bit values. */ +#define CC_CLOBBER_Z 0x2000 + +/* Extend conditions.h to explicitly note cases where the overflow + flag is invalid. */ +#define CC_CLOBBER_V 0x4000 + +/* Extend conditions.h to note when the comparison was actually + output. */ +#define CC_EXPLICIT_COMPARE 0x8000 + +/* 17.17 Costs */ +#define REGISTER_MOVE_COST(MODE, FROM, TO) ((MODE)==QImode ? 1 : \ + (MODE)==HImode ? 1 : \ + (MODE)==PSImode ? 1 : \ + (MODE)==SImode ? 2 : \ + (MODE)==SFmode ? 2 : 4) +#define MEMORY_MOVE_COST(MODE, CLASS, IN) ((MODE)==QImode ? 2 : \ + (MODE)==HImode ? 2 : \ + (MODE)==PSImode ? 4 : \ + (MODE)==SImode ? 4 : \ + (MODE)==SFmode ? 4 : 8) +#define BRANCH_COST(SPEED_P, PREDICTABLE_P) 0 +#define SLOW_BYTE_ACCESS 0 +#define NO_FUNCTION_CSE + +/* 17.18 Scheduling */ + +/* 17.19 Sections */ +/* See also 17.21.6 for CTORS/DTORS */ +#define MSP430_TEXT_SECTION_NAME ".text" +#define MSP430_DATA_SECTION_NAME ".data" +#define MSP430_READONLY_DATA_SECTION_NAME ".rodata" +#define MSP430_BSS_SECTION_NAME ".bss" + +/* Inhibit assignment of writable memory to far sections until we + * have MCUs that support such a thing. */ +#define MSP430_NO_FAR_RAM 1 + +#define TEXT_SECTION_ASM_OP "\t" MSP430_TEXT_SECTION_NAME +#define DATA_SECTION_ASM_OP "\t" MSP430_DATA_SECTION_NAME +#undef READONLY_DATA_SECTION_ASM_OP +#define READONLY_DATA_SECTION_ASM_OP "\t.section\t" MSP430_READONLY_DATA_SECTION_NAME +#define BSS_SECTION_ASM_OP "\t.section\t" MSP430_BSS_SECTION_NAME + +/* 17.20 PIC */ +/* Not supported on this platform at this time */ + +/* 17.21 Assembler Format */ +/* 17.21.1 File Framework */ +#define ASM_COMMENT_START " ; " +#define ASM_APP_ON "#APP\n" +#define ASM_APP_OFF "#NOAPP\n" +/* 17.21.2 Data Output */ +/* 17.21.3 Uninitialized Data */ +/* Inhibit output of labels not recognized by msp430 gas */ +#undef ASM_OUTPUT_ALIGNED_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ + do \ + { \ + const char *_name = targetm.strip_name_encoding (NAME); \ + if ('0' <= *_name && *_name <= '9') \ + break; \ + fprintf ((FILE), "%s", LOCAL_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), "\n"); \ + ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \ + } \ + while (0) + +/* 17.21.4 Label Output */ +#define GLOBAL_ASM_OP "\t.global\t" +#undef ASM_DECLARE_FUNCTION_NAME +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + msp430_asm_declare_function_name (FILE, NAME, DECL) +/* Here we must catch r0 - r15 used as variable names */ +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ + do{ \ + const char *p = NAME; \ + while(*p == '_') p++; \ + if(*p == 'r' || *p == 'R') \ + { \ + int val; \ + char *endptr; \ + p++; \ + val = strtol (p, &endptr, 10); \ + if(val >= 0 && val <= 15 && \ + *endptr == 0 ) \ + { \ + asm_fprintf ((FILE), "_%U%s", (NAME)); \ + } \ + else \ + asm_fprintf ((FILE), "%U%s", (NAME)); \ + } \ + else \ + asm_fprintf ((FILE), "%U%s", (NAME)); \ + } while(0) +/* 17.21.5 Initialization */ +/* 17.21.6 Macros for Initialization */ +#define HAS_INIT_SECTION 1 +/* The code that walks the [cd]tors list is not referenced in + * _reset_vector_ or _stop_progExec__; doing so here ensures that code + * is only linked in if it's actually needed. */ +#define CTORS_SECTION_ASM_OP GLOBAL_ASM_OP "__do_global_ctors\n\t.section\t.ctors" +#define DTORS_SECTION_ASM_OP GLOBAL_ASM_OP "__do_global_dtors\n\t.section\t.dtors" +/* 17.21.7 Instruction Output */ +#define REGISTER_NAMES \ + { \ + "r0", "r1", "r2", "r3", \ + "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", \ + "r12", "r13", "r14", "r15", \ + "argp", "sfp" \ + } +#define PRINT_OPERAND(STREAM, X, CODE) msp430_print_operand (STREAM, X, CODE) +#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ + do { \ + gcc_assert (MSP430_HARD_REGISTER_NUM_P(REGNO)); \ + fprintf (STREAM, "\tpush%sr%d", TARGET_CPUX ? "m.a\t#1, " : "\t", REGNO); \ + } while (0) +#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ + do { \ + gcc_assert (MSP430_HARD_REGISTER_NUM_P(REGNO)); \ + fprintf (STREAM, "\tpop%sr%d", TARGET_CPUX ? "m.a\t#1, " : "\t", REGNO); \ + } while (0) +/* 17.21.8 Dispatch Tables */ +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ + msp430_output_addr_vec_elt(STREAM, VALUE) +/* 17.21.9 Exception Region Output */ +/* 17.21.10 Alignment Output */ +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ + fprintf (STREAM, "\t.p2align %d,0\n", POWER) + +/* 17.22 Debugging Info */ +/* 17.22.1 All Debuggers */ +/* 17.22.2 DBX Options -- not supported */ +/* 17.22.3 DBX Hooks -- not supported */ +/* 17.22.4 File Names and DBX -- not supported */ +/* 17.22.5 SDB and DWARF */ +#define DWARF2_ADDR_SIZE (TARGET_CPUX ? 4 : 2) +/* 17.22.6 VMS Debug -- not supported */ + +/* 17.23 Floating Point */ +/* MSP430 doesn't have floating point, and its emulation uses IEEE. + * Presumably, none of this section is relevant. */ + +/* 17.24 Mode Switching */ +/* For things like configuring an FPU to single- or double-precision + * mode. Not currently relevant. */ + +/* 17.25 Target Attributes */ +/* These are all hooks */ + +/* 17.26 Emulated TLS */ +/* Thread Local Storage on a microcontroller? Please. */ + +/* 17.27 MIPS Coprocessors -- not relevant */ + +/* 17.28 PCH Target */ +/* Pre-compiled headers might be useful, but we're not using them + * now. */ + +/* 17.29 C++ ABI */ +/* These are all hooks */ + +/* 17.30 Named Address Spaces */ +/* This might be relevant when dealing with near versus far memory. + * It is specifically for use by embedded processors. */ + +/* 17.31 Misc */ +#define CASE_VECTOR_MODE FUNCTION_MODE +#define MOVE_MAX 2 +#define SHIFT_COUNT_TRUNCATED 1 +/* Can't truncate to 20-bit without doing work. Can truncate from it + * to lower precisions. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) (20 != (OUTPREC) && (OUTPREC) <= (INPREC)) +#define Pmode (TARGET_D20 ? PSImode : HImode) +#define FUNCTION_MODE (TARGET_C20 ? PSImode : HImode) +#define REGISTER_TARGET_PRAGMAS() do { \ + c_register_pragma_with_expansion (0, "vector", msp430_pr_vector); \ + } while (0) +#define DOLLARS_IN_IDENTIFIERS 0 + +enum msp430_frame_flags_e +{ + MSP430_FF_prologue_push_sr = 0x0001, + MSP430_FF_use_reti = 0x0002, + MSP430_FF_prologue_eint = 0x0004, + MSP430_FF_prologue_dint = 0x0008, + MSP430_FF_epilogue_eint = 0x0010, + MSP430_FF_epilogue_dint = 0x0020, + MSP430_FF_epilogue_exit_lpm = 0x0040, + MSP430_FF_epilogue_pop_sr = 0x0080, + MSP430_FF_use_frame_saver = 0x0100, + MSP430_FF_preserve_registers = 0x0200, + MSP430_FF_allocate_frame = 0x0400, + MSP430_FF_inhibit_return = 0x0800, + MSP430_FF_treat_as_main = 0x1000, + MSP430_FF_ready_for_return = 0x2000, + MSP430_FF_savereg_20 = 0x4000, + MSP430_FF_callret_20 = 0x8000 +}; + +#define MSP430_SYMBOL_FLAG_SR20 (SYMBOL_FLAG_MACH_DEP << 0) +#define MSP430_SYMBOL_REF_SR20_P(RTX) \ + ((SYMBOL_REF_FLAGS (RTX) & MSP430_SYMBOL_FLAG_SR20) != 0) +#define MSP430_SYMBOL_FLAG_C20 (SYMBOL_FLAG_MACH_DEP << 1) +#define MSP430_SYMBOL_REF_C20_P(RTX) \ + ((SYMBOL_REF_FLAGS (RTX) & MSP430_SYMBOL_FLAG_C20) != 0) + +/* Get the mode that should be used for saving callee-saved registers + * for the given machine_function pointer. */ +#define MSP430_SAVEREGS_MODE(_mfp) ((_mfp)->frame_flags & MSP430_FF_savereg_20 ? PSImode : HImode) + +struct GTY(()) machine_function +{ + int initialized; + tree signal; + tree interrupt; + tree naked; + tree task; + tree wakeup; + tree critical; + tree reentrant; + tree saveprologue; + tree noint_hwmul; + tree hosted; + + /* Aligned frame size as recorded in expand_prologue */ + int frame_size; + + /* Bit-mask indicating the registers saved in expand_prologue */ + unsigned int saved_regs_mask; + + /* Number of registers saved in expand_prologue */ + int saved_regs_count; + + /* Bit-mask from msp430_frame_flags_e */ + unsigned int frame_flags; + + /* Vector offset for interrupt: non-negative multiple of two. + * Negative indicates an unbound interrupt. Field valid only if + * interrupt is not null. */ + int vector_offset; + + /* Non-zero if we need the frame pointer (e.g., for a SR_IRQ + * builtin) */ + int frame_pointer_required; + + /* An internal label to be emitted at the end of the epilog, in + * functions that might inhibit a return but still have a return in + * the middle of the code. NULL unless frame_flags has + * MSP430_FF_inhibit_return set. */ + const char *inhibited_return_label; +}; + +enum msp430_tree_index +{ + MSP430_TI_A20_INTEGER_TYPE, + MSP430_TI_A20_UNSIGNED_TYPE, + MSP430_TI_MAX +}; + +extern GTY(()) tree msp430_global_trees[MSP430_TI_MAX]; + +#define msp430_a20_integer_type_node msp430_global_trees[MSP430_TI_A20_INTEGER_TYPE] +#define msp430_a20_unsigned_type_node msp430_global_trees[MSP430_TI_A20_UNSIGNED_TYPE] + +#endif /* GCC_MSP430_H */ diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430.md gcc-4.7.0/gcc/config/msp430/msp430.md new file mode 100644 index 0000000..1d13c1b --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430.md @@ -0,0 +1,1660 @@ +;; -*- Mode: Scheme -*- +;; Machine description for GNU compiler, +;; for Texas Instruments msp430 MCUs +;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +;; Contributed by Dmitry Diky +;; GCC 4.x port by Ivan Shcherbakov + +;; This work is partially financed by the European Commission under the +;; Framework 6 Information Society Technologies Project +;; "Wirelessly Accessible Sensor Populations (WASP)". + +; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +(include "constraints.md") +(include "predicates.md") + +;; Special characters after '%': +;; A No effect (add 0). +;; B Add 1 to REG number, 2 to MEM address or CONST_INT. +;; C 2 4 +;; D 3 6 +;; S Add 2 to memory address if using stack pointer (for pre_decr) + +(define_constants + [(REGNO_PC 0) + (REGNO_SP 1) + (REGNO_SR 2) + (REGNO_FP 4) + ] + ) + +(define_constants + [(UNSPEC_UNDEFINED 0) + (UNSPEC_BITTEST_FOR_CARRY 6) + (UNSPEC_PUSH_MULTI 20) + (UNSPEC_POP_MULTI 21) + (UNSPEC_PSI_NYBBLE 100) + (UNSPEC_LOAD_SP 105) + ] +) + +(define_constants + [(UNSPECV_UNDEFINED 0) + (UNSPECV_MPY_INHIBIT_INTR 100) + (UNSPECV_MPY_RESTORE_INTR 101) + (UNSPECV_NOP 200) + (UNSPECV_DINT 201) + (UNSPECV_EINT 202) + (UNSPECV_READ_STATUS_REGISTER 203) + (UNSPECV_WRITE_STATUS_REGISTER 204) + (UNSPECV_BIC_STATUS_REGISTER 205) + (UNSPECV_BIS_STATUS_REGISTER 206) + (UNSPECV_BIC_SR_IRQ 207) + (UNSPECV_BIS_SR_IRQ 208) + (UNSPECV_READ_STACK_POINTER 209) + (UNSPECV_WRITE_STACK_POINTER 210) + (UNSPECV_DELAY_CYCLES 211) + (UNSPECV_GET_INTERRUPT_STATE 212) + (UNSPECV_SET_INTERRUPT_STATE 213) + (UNSPECV_GET_WATCHDOG_CLEAR_VALUE 214) + (UNSPECV_SET_WATCHDOG_CLEAR_VALUE 215) + (UNSPECV_WATCHDOG_CLEAR 216) + (UNSPECV_RLA 300) + (UNSPECV_RRA 301) + (UNSPECV_RLC 302) + (UNSPECV_RRC 303) + (UNSPECV_RRU 304) + (UNSPECV_CLRC 305) + (UNSPECV_MWSHL8XOR 310) + (UNSPECV_MWSHR8XOR 311) + ] + ) + +; Instruction impact on condition code flags specific to MSP430 +; comparison-based jump instructions. Comparisons are equality (eq, +; ne), signed ordered (*gt, ge, lt, *le), and unsigned ordered (*gtu, +; geu, ltu, *leu) [* indicates a comparison not directly supported by +; a single msp430 instruction]. Where signed ordered are supported, +; so are unsigned ordered. +; +; undef : insn effect has not be categorized +; none : No change to flags +; clobber : Flags do not represent anything useful +; explicit : VNZC calculated explicitly by a comparison operation, as +; opposed to as a side effect of an operation. Side effect +; calculations can be wrong for MSP430 conditional jumps +; that reference the overflow flag (jge/jl). +; VNZC : All flags are valid for comparison between two values +; NZC : Flags are valid for equality and signed ordered comparisons +; with zero. Often C=~Z. As used here, V is expected to be +; cleared (CC_NO_OVERFLOW is set); thus this condition should +; not be used for dadd and rlam which leave its value undefined. +; NZ : Flags are valid for signed ordered comparisons with zero. V +; and C are clobbered. Used primarily in multi-word operations. +; N : Flags valid for signed ordered comparisons with zero, but not +; for equality with zero. V, C, and Z are clobbered. Used +; primarily in multi-word operations. +(define_attr "cc" "undef,none,clobber,explicit,VNZC,NZC,NZ,N" + (const_string "undef")) + +(define_attr "msp430_noint_hwmul" "" (symbol_ref "MSP430_NOINT_HWMUL")) + +; Instruction formats. Yes, it is irritating that format I (fmt1) has +; two operands, and format II (fmt2) has one. +; +; fmt1 : MSP430, three words : double-operand +; fmt2 : MSP430, two words : single-operand as dst +; fmt2s : MSP430, two words : single-operand as src +; emu1dd : MSP430 : fmt1 emulated dst, dst +; condjmp : MSP430, one word : conditional jump with 10-bit word offset +; fmt1x : MSP430X, four words : extension word, double-operand (fmt1) +; fmt2x : MSP430X, three words : extension word, single-operand (fmt2) +; fmt2xs : MSP430X, three words : extension word, single-operand as src (fmt2s) +; fmt2xn : MSP430X, two words: reg/count operand, single-operand src/dst +; fmta : MSP430X, two words : no extension word, single-operand +(define_attr "instr_format" + "undef,fmt1,fmt1x,emu1dd,emu1ddx,fmt2,fmt2x,fmt2s,fmt2xn,fmt2xs,condjmp,fmta" + (const_string "undef")) + +; Multiplier for basic instr_format-based length when template includes +; multiple instances of the same instruction. +(define_attr "instr_mult" + "" + (cond [(match_operand:SI 0 "" "") + (const_int 2) + (match_operand:SF 0 "" "") + (const_int 2) + (match_operand:DI 0 "" "") + (const_int 4)] + (const_int 1))) + +; Length is calculated in bytes, and depends in most cases solely on +; the instruction format and the number of times the base instruction +; appears in the output template (for multi-word operands). +(define_attr "length" "" + (cond [(eq_attr "instr_format" "fmt1x,emu1ddx") ; extension, insn, src word, dst word + (mult (const_int 8) (attr "instr_mult")) + (eq_attr "instr_format" "fmt1,emu1dd") ; insn, src word, dst word + (mult (const_int 6) (attr "instr_mult")) + (eq_attr "instr_format" "fmt2x,fmt2xs") ; extension, insn, dst/src word + (mult (const_int 6) (attr "instr_mult")) + (eq_attr "instr_format" "fmt2,fmt2s,fmt2xn,fmta") ; insn, dst/src word + (mult (const_int 4) (attr "instr_mult")) + (eq_attr "instr_format" "condjmp") ; insn (assume local jump) + (mult (const_int 2) (attr "instr_mult"))] + (const_int 0))) + +;; Appropriate mode for pointers +(define_mode_iterator P [(PSI "TARGET_D20") (HI "!TARGET_D20")]) + +;; Mnemonic suffix when operating in A20 mode (mova vs mov) +(define_mode_attr a20sfx + [(HI "") + (PSI "a")]) + +;; Operand size suffix when operating in A20 mode (rram vs rram.a) +(define_mode_attr a20dotsfx + [(HI "") + (PSI ".a")]) + +;; Operand size suffix when operating in A20 mode (pushx.a vs push) +(define_mode_attr a20xdotsfx + [(HI "") + (PSI "x.a")]) + +;; SI and SF as blobs are treated the same +(define_mode_iterator SISF [SI SF]) + +;; Modes to which QI can extend +(define_mode_iterator QIEXT [DI SI HI]) + +;; Modes to which HI can extend +(define_mode_iterator HIEXT [DI SI (PSI "TARGET_CPUX")]) + +;; Modes that can be pushed or popped on stack with standard RTL pattern +(define_mode_iterator StackableModes [DI SI (PSI "TARGET_CPUX") HI]) + +;; Integer modes that fit in a single register. PSI is explicitly excluded. +(define_mode_iterator INTRegModes [HI QI]) + +;; Integer modes for whole registers (16- and 20-bit variants) +(define_mode_iterator WordRegModes [(PSI "TARGET_CPUX") HI]) + +;; Integer modes that can be widened. PSI is explicitly excluded. +(define_mode_iterator WidenableINTModes [SI HI QI]) + +;; Integer modes +(define_mode_iterator INTModes [DI SI HI QI]) + +;; Integer modes including PSI if enabled +(define_mode_iterator INTRegModes20 [(PSI "TARGET_CPUX") HI QI]) +(define_mode_iterator INTModes20 [DI SI (PSI "TARGET_CPUX") HI QI]) + +;; All supported modes +(define_mode_iterator AllModes [DI SI SF (PSI "TARGET_CPUX") HI QI]) + +;; Operand constraints for INTModes iterators +(define_mode_attr INTModes_constraint_dst + [(QI "=rm") ; QImode goes to register or memory + (HI "=rm") ; HImode goes to register or memory + (PSI "=rm") ; PSImode goes to register or memory + (SI "=rm") ; SImode goes to register or memory + (DI "=rm")]) ; DImode goes to register or memory + +(define_mode_attr INTModes_constraint_src + [(QI "UmQi") ; QI, HI, PSI allow anything + (HI "UmQi") + (PSI "UmQi") + (SI "rmQi") ; SI, DI remove frame and stack pointer + (DI "rmQi")]) + +(define_mode_attr INTModes_constraint_matchdst + [(QI "0") + (HI "0") + (PSI "0") + (SI "0") + (DI "0")]) + +; Variant for commutative operations +(define_mode_attr INTModes_commutative_matchdst + [(QI "%0") + (HI "%0") + (PSI "%0") + (SI "%0") + (DI "%0")]) + +; Variants that allow operation on the frame and stack pointer for HImode +(define_mode_attr INTModes_frameok_dst + [(QI "=rm") ; QImode goes to register or memory + (HI "=Um") ; HImode allows frame and stack pointer + (PSI "=Um") ; PSImode allows frame and stack pointer + (SI "=rm") ; SImode goes to register or memory + (DI "=rm")]) ; DImode goes to register or memory + +(define_mode_attr INTModes_frameok_src + [(QI "UmQi") ; QI, HI allow anything + (HI "UmQi") + (PSI "UmQi") + (SI "rmQi") ; SI, DI remove frame and stack pointer + (DI "rmQi")]) + +; For LSW-first arithmetic on values that might be multiple words +(define_mode_attr INTModes_cc_VNZC + [(QI "VNZC") + (HI "VNZC") + (PSI "VNZC") + (SI "N") + (DI "N")]) + +(define_mode_attr INTModes_cc_NZC + [(QI "NZC") + (HI "NZC") + (PSI "NZC") + (SI "N") + (DI "N")]) + +(define_mode_attr INTModes_cc_NZ + [(QI "NZ") + (HI "NZ") + (PSI "NZ") + (SI "N") + (DI "N")]) + +; For MSW-first shift through carry on values that might be multiple words +(define_mode_attr INTModes_reversed_cc_NZ + [(QI "NZ") + (HI "NZ") + (PSI "NZ") + (SI "clobber") + (DI "clobber")]) + +; Next wider mode, in lower case +(define_mode_attr wider_mode + [(QI "hi") + (HI "si") + (SI "di")]) + +; Next wider mode, in upper case +(define_mode_attr WIDER_MODE + [(QI "HI") + (HI "SI") + (SI "DI")]) + +;; Instruction format adjustment for extension word +(define_mode_attr INTModes_instr_format_fmt1 + [(QI "fmt1") + (HI "fmt1") + (PSI "fmt1x") + (SI "fmt1") (SF "fmt1") + (DI "fmt1")]) +(define_mode_attr INTModes_instr_format_fmt2 + [(QI "fmt2") + (HI "fmt2") + (PSI "fmt2x") + (SI "fmt2") (SF "fmt2") + (DI "fmt2")]) + +;; ================== +;; Built-in functions + +; nop() +(define_insn "nop" + [(unspec_volatile [(const_int 0)] UNSPECV_NOP)] + "" + "nop" + [(set_attr "cc" "none") + (set_attr "length" "2") + ]) + +; dint() +(define_insn "dint" + [(unspec_volatile [(const_int 0)] UNSPECV_DINT) + (clobber (reg:HI REGNO_SR))] + "" + "dint" + [(set_attr "cc" "none") + (set_attr "length" "2") + ]) + +; eint() +(define_insn "eint" + [(unspec_volatile [(const_int 0)] UNSPECV_EINT) + (clobber (reg:HI REGNO_SR))] + "" + "eint" + [(set_attr "cc" "none") + (set_attr "length" "2") + ]) + +; read_status_register(retloc) +(define_insn "read_status_register" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (unspec_volatile:HI [(reg:HI REGNO_SR)] UNSPECV_READ_STATUS_REGISTER))] + "" + { return msp430x_ext_operand (operands[0], HImode) ? "movx\tr2, %0" : "mov\tr2, %0"; } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; get_interrupt_state(retloc) +; Yes, this is equivalent to read_status_register. +(define_insn "get_interrupt_state" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (unspec_volatile:HI [(reg:HI REGNO_SR)] UNSPECV_GET_INTERRUPT_STATE))] + "" + { return msp430x_ext_operand (operands[0], HImode) ? "movx\tr2, %0" : "mov\tr2, %0"; } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; write_status_register(sr_value) +(define_insn "write_status_register" + [(set (reg:HI REGNO_SR) + (unspec_volatile:HI [(match_operand:HI 0 "msp430_source_operand" "rmQi")] UNSPECV_WRITE_STATUS_REGISTER))] + "" + { return msp430x_ext_operand (operands[0], HImode) ? "movx\t%0, r2" : "mov\t%0, r2"; } + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt1")]) + +; set_interrupt_state(istate) +; Yes, this is equivalent to write_status_register. +(define_insn "set_interrupt_state" + [(set (reg:HI REGNO_SR) + (unspec_volatile:HI [(match_operand:HI 0 "msp430_source_operand" "rmQi")] UNSPECV_SET_INTERRUPT_STATE))] + "" + { return msp430x_ext_operand (operands[0], HImode) ? "movx\t%0, r2" : "mov\t%0, r2"; } + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt1")]) + +; bic_status_register(sr_value) +(define_insn "bic_status_register" + [(set (reg:HI REGNO_SR) + (unspec_volatile:HI [(match_operand:HI 0 "msp430_source_operand" "rmQi")] UNSPECV_BIC_STATUS_REGISTER))] + "" + { return msp430x_ext_operand (operands[0], HImode) ? "bicx\t%0, r2" : "bic\t%0, r2"; } + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt1")]) + +; bis_status_register(sr_value) +(define_insn "bis_status_register" + [(set (reg:HI REGNO_SR) + (unspec_volatile:HI [(match_operand:HI 0 "msp430_source_operand" "rmQi")] UNSPECV_BIS_STATUS_REGISTER))] + "" + { return msp430x_ext_operand (operands[0], HImode) ? "bisx\t%0, r2" : "bis\t%0, r2"; } + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt1")]) + +; bic_status_register_on_exit(stack_reference, status_value) +(define_insn "bic_status_register_on_exit" + [(set (match_operand:HI 0 "memory_operand" "=m") + (unspec_volatile:HI [(match_operand:HI 1 "msp430_source_operand" "rmQi")] UNSPECV_BIC_SR_IRQ))] + "" + { return msp430_output_template (HImode, operands, 1, "bic", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; bis_status_register_on_exit(stack_reference, status_value) +(define_insn "bis_status_register_on_exit" + [(set (match_operand:HI 0 "memory_operand" "=m") + (unspec_volatile:HI [(match_operand:HI 1 "msp430_source_operand" "rmQi")] UNSPECV_BIS_SR_IRQ))] + "" + { return msp430_output_template (HImode, operands, 1, "bis", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; read_stack_pointer(retloc) +(define_insn "*read_stack_pointer_" + [(set (match_operand:P 0 "nonimmediate_operand" "=rm") + (unspec_volatile: [(reg: REGNO_SP)] UNSPECV_READ_STACK_POINTER))] + "" + { + if (PSImode == mode) + { + if (msp430x_a20_operand (operands[0], VOIDmode)) + return "mova\tr1, %0"; + return "movx.a\tr1, %0"; + } + if (msp430x_ext_operand (operands[0], mode)) + return "movx\tr1, %0"; + return "mov\tr1, %0"; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_expand "read_stack_pointer" + [(match_operand 0 "" "")] + "" + { + if (GET_MODE (operands[0]) != Pmode) + debug_rtx (operands[0]); + gcc_assert (GET_MODE (operands[0]) == Pmode); + emit_insn (gen_rtx_SET (Pmode, operands[0], + gen_rtx_UNSPEC_VOLATILE (Pmode, gen_rtvec (1, stack_pointer_rtx), UNSPECV_READ_STACK_POINTER))); + DONE; + }) + +; write_stack_pointer(sr_value) +(define_insn "*write_stack_pointer_" + [(set (reg:P REGNO_SP) + (unspec_volatile: [(match_operand: 0 "msp430_source_operand" "rmQi")] UNSPECV_WRITE_STACK_POINTER))] + "" + { + if (PSImode == mode) + { + if (msp430x_a20_operand (operands[0], VOIDmode)) + return "mova\t%0, r1"; + return "movx.a\t%0, r1"; + } + if (msp430x_ext_operand (operands[0], mode)) + return "movx\t%0, r1"; + return "mov\t%0, r1"; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_expand "write_stack_pointer" + [(match_operand 0 "" "")] + "" + { + emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_UNSPEC_VOLATILE (Pmode, gen_rtvec (1, operands[0]), UNSPECV_WRITE_STACK_POINTER))); + DONE; + }) + +; delay_cycles_init(loopreg, count) +(define_insn "delay_cycles_init" + [(set (match_operand:HI 0 "register_operand" "=r") + (unspec_volatile:HI [(match_operand:HI 1 "const_int_operand" "i")] UNSPECV_DELAY_CYCLES)) + (clobber (match_dup 0))] + "" + "mov\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; delay_cycles_decr(loopreg) +(define_insn "delay_cycles_decr" + [(set (match_operand:HI 0 "register_operand" "+r") + (unspec_volatile:HI [(minus:HI (match_dup 0) (const_int 1))] UNSPECV_DELAY_CYCLES))] + "" + "dec\t%0" + [(set_attr "cc" "VNZC") + (set_attr "instr_format" "fmt1")]) + +; delay_cycles_jump(loophead) +(define_insn "delay_cycles_jump" + [(set (pc) + (if_then_else + (ne (unspec_volatile [(cc0)] UNSPECV_DELAY_CYCLES) (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "jne\t%0" + [(set_attr "cc" "none") + (set_attr "instr_format" "condjmp")]) + +; get_watchdog_clear_value(retloc) +(define_insn "get_watchdog_clear_value" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (unspec_volatile:HI [(const_int 0)] UNSPECV_GET_WATCHDOG_CLEAR_VALUE))] + "" + { + if (msp430x_ext_operand (operands[0], HImode)) + return "movx\t&__wdt_clear_value, %0"; + return "mov\t&__wdt_clear_value, %0"; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; set_watchdog_clear_value(retloc, value) +(define_insn "set_watchdog_clear_value" + [(unspec_volatile:HI [(match_operand:HI 0 "msp430_source_operand" "rmQi")] UNSPECV_SET_WATCHDOG_CLEAR_VALUE)] + "" + { + if (msp430x_ext_operand (operands[0], HImode)) + return "movx\t%0, &__wdt_clear_value"; + return "mov\t%0, &__wdt_clear_value"; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; watchdog_clear() +; NOTE: We assume __wdt_clear_value is in low memory +(define_insn "watchdog_clear" + [(unspec_volatile [(const_int 0)] UNSPECV_WATCHDOG_CLEAR)] + "" + "mov\t&__wdt_clear_value, &__WDTCTL" + [(set_attr "cc" "none") + (set_attr "length" "6") + ]) + +;; extendmn2 (sign extension) + +(define_insn "extend8bit1" + [(set (match_operand:WordRegModes 0 "nonimmediate_operand" "+rmQ") + (sign_extend: (subreg:QI (match_dup 0) 0)))] + "" + { return msp430_output_template (mode, operands, 0, "sxt", NULL, NULL); } + [(set_attr "cc" "NZC") + (set_attr "instr_format" "fmt2")]) + +(define_expand "extendsidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (sign_extend:DI (match_operand:SI 1 "general_operand" "")))] + "" + "msp430_expand_signextend (operands); DONE;") +(define_expand "extendpsisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (sign_extend:SI (match_operand:PSI 1 "general_operand" "")))] + "TARGET_CPUX" + "msp430_expand_signextend (operands); DONE;") +(define_expand "extendhi2" + [(set (match_operand:HIEXT 0 "nonimmediate_operand" "") + (sign_extend: (match_operand:HI 1 "general_operand" "")))] + "" + "msp430_expand_signextend (operands); DONE;") +(define_expand "extendqi2" + [(set (match_operand:QIEXT 0 "nonimmediate_operand" "") + (sign_extend: (match_operand:QI 1 "general_operand" "")))] + "" + "msp430_expand_signextend (operands); DONE;") + +;; zero_extendmn2 (zero extension) + +(define_expand "zero_extendsidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (zero_extend:DI (match_operand:SI 1 "general_operand" "")))] + "" + "msp430_expand_zeroextend (operands); DONE;") +(define_expand "zero_extendpsisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (zero_extend:SI (match_operand:PSI 1 "general_operand" "")))] + "TARGET_CPUX" + "msp430_expand_zeroextend (operands); DONE;") +(define_expand "zero_extendhi2" + [(set (match_operand:HIEXT 0 "nonimmediate_operand" "") + (zero_extend: (match_operand:HI 1 "general_operand" "")))] + "" + "msp430_expand_zeroextend (operands); DONE;") +(define_expand "zero_extendqi2" + [(set (match_operand:QIEXT 0 "nonimmediate_operand" "") + (zero_extend: (match_operand:QI 1 "general_operand" "")))] + "" + "msp430_expand_zeroextend (operands); DONE;") + +;; trunc +(define_insn "truncsipsi2" + [(set (match_operand:PSI 0 "register_operand" "=&r") + (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] + "TARGET_CPUX" + "mov\t%B1, %0\;and\t#15, %0\;clrc\;.rpt\t#5\;rrcx.a\t%0\;bisx.a\t%A1, %0" + [(set_attr "cc" "clobber") + (set_attr "length" "16")]) + +;; extend helper +(define_insn "psinybble2" + [(set (match_operand:PSI 0 "register_operand" "=r") + (unspec:PSI [(match_operand:PSI 1 "register_operand" "0")] UNSPEC_PSI_NYBBLE))] + "TARGET_CPUX" + ".rpt\t#5\;rlcx.a\t%0" + [(set_attr "cc" "clobber") + (set_attr "length" "4")]) + +;; bswap (standard rtl, not standard insn) + +(define_insn "*bswaphi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (bswap:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] + "" + { return msp430_output_template (HImode, operands, 0, "swpb", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2")]) + +(define_expand "bswaphi1" + [(set (match_operand:HI 0 "nonimmediate_operand" "+rm") + (bswap:HI (match_dup 0)))] + "" + "") + +;; movm + +(define_insn "*pushqi1" + [(set (mem:QI (pre_modify:P (reg: REGNO_SP) (plus: (reg: REGNO_SP) (const_int -2)))) + (match_operand:QI 0 "general_operand" "rmi"))] + "TARGET_CPUX || PSImode != mode" + { + if (msp430x_ext_operand (operands[0], QImode)) + return "pushx.b\t%S0"; + return "push.b\t%S0"; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s")]) + +(define_expand "pushqi1" + [(match_operand:QI 0 "" "")] + "" + { + emit_insn (gen_rtx_SET (QImode, + gen_rtx_MEM (QImode, gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, gen_rtx_PLUS (Pmode, stack_pointer_rtx, gen_int_mode (-2, Pmode)))), + operands[0])); + DONE; + }) + +(define_insn "loadqi2" + [(set (match_operand:WordRegModes 0 "register_operand" "=r") + (zero_extend: (match_operand:QI 1 "msp430_source_operand" "UmQi")))] + "" + { return msp430_output_template (QImode, operands, 1, "mov", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "storeqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=rm") + (subreg:QI (match_operand:HI 1 "register_operand" "r") 0))] + "" + { return msp430_output_template (QImode, operands, 1, "mov", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=rm") + (match_operand:QI 1 "msp430_source_operand" "UmQi"))] + "" + { return msp430_output_template (QImode, operands, 1, "mov", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; pushmhi2(num_regs, high_regno) +(define_insn "*pushm2_insn" + [(set (reg REGNO_SP) + (unspec [(match_operand 0 "const_int_operand" "i") + (match_operand 1 "const_int_operand" "N") + (reg:WordRegModes REGNO_SP)] + UNSPEC_PUSH_MULTI))] + "TARGET_CPUX || PSImode != mode" + { + rtx xoperands[2]; + xoperands[0] = operands[0]; + xoperands[1] = gen_rtx_REG (mode, INTVAL (operands[1])); + output_asm_insn ("pushm\t%0, %1", xoperands); + return ""; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2xn")]) + +(define_expand "pushm2" + [(match_operand 0 "const_int_operand" "i") + (match_operand 1 "const_int_operand" "N") + (reg:WordRegModes REGNO_SP)] + "TARGET_CPUX || PSImode != mode" + { + emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_UNSPEC (Pmode, + gen_rtvec (3, operands[0], operands[1], gen_rtx_REG (mode, REGNO_SP)), + UNSPEC_PUSH_MULTI))); + DONE; + }) + +; popmhi2(num_regs, high_regno) +(define_insn "*popm2_insn" + [(set (reg REGNO_SP) + (unspec [(match_operand 0 "const_int_operand" "i") + (match_operand 1 "const_int_operand" "N") + (reg:WordRegModes REGNO_SP)] + UNSPEC_POP_MULTI))] + "TARGET_CPUX || PSImode != mode" + { + rtx xoperands[2]; + xoperands[0] = operands[0]; + xoperands[1] = gen_rtx_REG (mode, INTVAL (operands[1])); + output_asm_insn ("popm\t%0, %1", xoperands); + return ""; + } + [(set_attr "cc" "clobber") ; "none" if r2 is not covered + (set_attr "instr_format" "fmt2xn")]) + +(define_expand "popm2" + [(match_operand 0 "const_int_operand" "i") + (match_operand 1 "const_int_operand" "N") + (reg:WordRegModes REGNO_SP)] + "TARGET_CPUX || PSImode != mode" + { + emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_UNSPEC (Pmode, + gen_rtvec (3, operands[0], operands[1], gen_rtx_REG (mode, REGNO_SP)), + UNSPEC_POP_MULTI))); + DONE; + }) + +(define_insn "*pushhi1" + [(set (mem:HI (pre_dec:P (reg: REGNO_SP))) + (match_operand:HI 0 "general_operand" "Wmi"))] + "TARGET_CPUX || PSImode != mode" + { + if (msp430x_ext_operand (operands[0], HImode)) + return "pushx\t%S0"; + return "push\t%S0"; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s")]) + +(define_insn "*pophi1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,w") + (mem:HI (post_inc:P (reg: REGNO_SP))))] + "TARGET_CPUX || PSImode != mode" + "pop\t%0" + [(set_attr "cc" "none,clobber") + (set_attr "instr_format" "fmt1")]) + + +(define_insn "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "=Um") + (match_operand:HI 1 "msp430_source_operand" "UmQi"))] + "" + { return msp430_output_template (HImode, operands, 1, "mov", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*pushpsi1" + [(set (mem:PSI (pre_dec:P (reg: REGNO_SP))) + (match_operand:PSI 0 "register_operand" "W"))] + "TARGET_CPUX && 1" /* Need && 1 to avoid conflation with pushx variant */ + "pushm.a\t#1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s")]) + +(define_insn "*pushxpsi1" + [(set (mem:PSI (pre_dec:P (reg: REGNO_SP))) + (match_operand:PSI 0 "general_operand" "mQi"))] + "TARGET_CPUX" + "pushx.a\t%0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2xs")]) + +(define_expand "push1" + [(match_operand:StackableModes 0 "" "")] + "TARGET_CPUX || PSImode != mode" + { + emit_insn (gen_rtx_SET (mode, + gen_rtx_MEM (mode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)), + operands[0])); + DONE; + } +) + +(define_expand "pop1" + [(match_operand:StackableModes 0 "" "")] + "TARGET_CPUX || PSImode != mode" + { + emit_insn (gen_rtx_SET (mode, operands[0], + gen_rtx_MEM (mode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)))); + DONE; + } +) + +(define_insn "*poppsi1" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,w") + (mem:PSI (post_inc:P (reg: REGNO_SP))))] + "TARGET_CPUX" + "popm.a\t#1, %0" + [(set_attr "cc" "none,clobber") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*movapsi" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=U,m") + (match_operand:PSI 1 "msp430_source_operand" "UmQi,U"))] + "TARGET_CPUX + && msp430x_a20_operand (operands[0], VOIDmode) + && msp430x_a20_operand (operands[1], VOIDmode)" + "mova\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmta")]) + +(define_insn "movpsi" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=Um") + (match_operand:PSI 1 "msp430_source_operand" "UmQi"))] + "TARGET_CPUX" + "movx.a\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*pushm1" + [(set (mem:SISF (pre_dec (reg REGNO_SP))) + (match_operand:SISF 0 "register_operand" "r"))] + "TARGET_CPUX" + "pushm\t#2, %B0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s") + (set_attr "instr_mult" "1")]) + +(define_insn "*push1" + [(set (mem:SISF (pre_dec (reg REGNO_SP))) + (match_operand:SISF 0 "general_operand" "ST,rmi"))] + "" + { + if (0 == which_alternative) + return "push\t2+%S0\;push\t2+%S0"; + return msp430_output_reverse_template (mode, operands, 0, "push", NULL, NULL); + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s") + (set_attr "instr_mult" "2")]) + +(define_insn "mov" + [(set (match_operand:SISF 0 "nonimmediate_operand" "=rm") + (match_operand:SISF 1 "msp430_source_operand" "rmQi"))] + "" + { + return msp430_mov_noclobber (operands); + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*pushmdi1" + [(set (mem:DI (pre_dec (reg REGNO_SP))) + (match_operand:DI 0 "register_operand" "r"))] + "TARGET_CPUX" + "pushm\t#4, %D0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s") + (set_attr "instr_mult" "1")]) + +(define_insn "*pushdi1" + [(set (mem:DI (pre_dec (reg REGNO_SP))) + (match_operand:DI 0 "general_operand" "ST,rmi"))] + "" + { + if (0 == which_alternative) + return "push\t6+%S0\;push\t6+%S0\;push\t6+%S0\;push\t6+%S0"; + return msp430_output_reverse_template (DImode, operands, 0, "push", NULL, NULL); + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s") + (set_attr "instr_mult" "4")]) + +(define_insn "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (match_operand:DI 1 "msp430_source_operand" "rmQi"))] + "" + { + return msp430_mov_noclobber (operands); + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + + +;; addm3, subm3 + +(define_split + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (plus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "const_int_operand" "")))] + "CONST_INT_P (operands[2]) && MSP430_CG_INT_P(-INTVAL (operands[2])) && !MSP430_CG_INT_P(INTVAL (operands[2]))" + [(set (match_dup 0) + (minus: (match_dup 1) + (match_dup 2)))] + { operands[2] = gen_int_mode (-INTVAL (operands[2]), mode); }) + +(define_split + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (minus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "const_int_operand" "")))] + "CONST_INT_P (operands[2]) && MSP430_CG_INT_P(-INTVAL (operands[2])) && !MSP430_CG_INT_P(INTVAL (operands[2]))" + [(set (match_dup 0) + (plus: (match_dup 1) + (match_dup 2)))] + { operands[2] = gen_int_mode (-INTVAL (operands[2]), mode); }) + +(define_insn "*addapsi3" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=U") + (plus:PSI (match_operand:PSI 1 "nonimmediate_operand" "%0") + (match_operand:PSI 2 "msp430_source_operand" "Ui")))] + "TARGET_CPUX && 1" /* Need && 1 to avoid conflation with addx variant */ + "adda\t%2, %0" + [(set_attr "cc" "VNZC") + (set_attr "instr_format" "fmta")]) + +(define_insn "add3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (plus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 2, "add", "addc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "")]) + +(define_insn "*subapsi3" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=U") + (minus:PSI (match_operand:PSI 1 "nonimmediate_operand" "0") + (match_operand:PSI 2 "msp430_source_operand" "Ui")))] + "TARGET_CPUX && 1" /* Need && 1 to avoid conflation with subx variant */ + "suba\t%2, %0" + [(set_attr "cc" "VNZC") + (set_attr "instr_format" "fmta")]) + +(define_insn "sub3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (minus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 2, "sub", "subc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "")]) + +;; one_cmplm2 (invert) + +(define_insn "one_cmpl2" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "=rm") + (not: (match_operand: 1 "nonimmediate_operand" "0")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 0, "inv", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "")]) + +;; negm2 + +(define_insn "negsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] + "" + { + if (msp430x_ext_operand (operands[0], SFmode)) + return "xorx\t#0x8000, %B0"; + return "xor\t#0x8000, %B0"; + } + [(set_attr "cc" "clobber") + (set_attr "length" "4,6")]) + +(define_expand "neg2" + [(match_operand:INTModes20 0 "nonimmediate_operand" "") + (match_operand: 1 "general_operand" "")] + "TARGET_CPUX || PSImode != mode" + { + emit_insn (gen_one_cmpl2 (operands[0], operands[1])); + emit_insn (gen_add3 (operands[0], operands[0], const1_rtx)); + DONE; + }) + +;; nandm3 (extension) + +(define_insn "*nand3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (and: (not: (match_operand: 1 "msp430_source_operand" "")) + (match_operand: 2 "general_operand" "")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 1, "bic", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "")]) + +; TODO peephole use bic with op2 inverted is CG-int +; TODO peephole andhi3 with 0xFF -> and.b or clr.b +; TODO convert multi-word to word, apply individual optimizations e.g. and -1 + +(define_insn "and3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (and: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 2, "and", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "")]) + +(define_insn "ior3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (ior: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 2, "bis", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "")]) + +(define_insn "xor3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (xor: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "TARGET_CPUX || PSImode != mode" + { return msp430_output_template (mode, operands, 2, "xor", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "")]) + +;; absm2 +(define_expand "abs2" + [(match_operand:INTModes20 0 "nonimmediate_operand" "") + (match_operand: 1 "general_operand" "")] + "TARGET_CPUX || PSImode != mode" + { + rtx test_ge = gen_rtx_GE (mode, operands[0], const0_rtx); + rtx dest_label = gen_label_rtx (); + + emit_move_insn (operands[0], operands[1]); + emit_jump_insn (gen_cbranch4 (test_ge, operands[0], const0_rtx, dest_label)); + emit_insn (gen_neg2 (operands[0], operands[0])); + emit_label (dest_label); + DONE; + }) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] + "" + { + if (msp430x_ext_operand (operands[0], SFmode)) + return "andx\t#0x7fff, %B0"; + return "and\t#0x7fff, %B0"; + } + [(set_attr "cc" "clobber,clobber") + (set_attr "length" "2,3")]) ; BAD LENGTH + +;; strlenm + +(define_expand "strlen" + [(match_operand:P 0 "nonimmediate_operand" "=rm") + (match_operand:BLK 1 "memory_operand" "m") + (match_operand:QI 2 "general_operand" "rmi") + (match_operand:QI 3 "const_int_operand" "i")] + "TARGET_CPUX || PSImode != mode" + { + rtx sp_rtx = gen_reg_rtx (Pmode); + rtx sp_deref_rtx = gen_rtx_MEM (QImode, sp_rtx); + rtx guard_rtx = operands[2]; + rtx loop_label = gen_label_rtx (); + rtx test_ne = gen_rtx_NE (QImode, sp_deref_rtx, guard_rtx); + + emit_move_insn (sp_rtx, XEXP (operands[1], 0)); + emit_insn (gen_subP3 (sp_rtx, sp_rtx, const1_rtx)); + emit_label (loop_label); + emit_insn (gen_addP3 (sp_rtx, sp_rtx, const1_rtx)); + emit_jump_insn (gen_cbranchqi4 (test_ne, sp_deref_rtx, guard_rtx, loop_label)); + emit_insn (gen_subP3 (operands[0], sp_rtx, XEXP (operands[1], 0))); + DONE; + }) + +;;======================================================================== +;; compare + +(define_expand "cbranch4" + [(set (cc0) (compare + (match_operand:INTModes20 1 "nonimmediate_operand") + (match_operand: 2 "general_operand"))) + (set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_CPUX || PSImode != mode" + { msp430_expand_cbranch (operands); DONE; }) + +(define_insn "*cmpapsi2" + [(set (cc0) (compare + (match_operand:PSI 0 "register_operand" "U") + (match_operand:PSI 1 "general_operand" "Ui")))] + "TARGET_CPUX && 1" /* Need && 1 to avoid conflation with cmpx variant */ + "cmpa\t%1, %0" + [(set_attr "cc" "explicit") + (set_attr "instr_format" "fmta")]) + +(define_insn "setcc2" + [(set (cc0) (compare + (match_operand:INTRegModes20 0 "nonimmediate_operand" "Um") + (match_operand: 1 "general_operand" "Umi")))] + "" + { return msp430_output_template (mode, operands, 1, "cmp", NULL, NULL); } + [(set_attr "cc" "explicit") + (set_attr "instr_format" "")]) + +(define_insn "bittest2" + [(set (cc0) (compare + (and:INTRegModes20 + (match_operand: 0 "nonimmediate_operand" "Um") + (match_operand: 1 "general_operand" "Umi")) + (const_int 0)))] + "" + { return msp430_output_template (mode, operands, 1, "bit", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "")]) + +(define_insn "branchcc" + [(set (pc) + (if_then_else + (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + { return msp430_output_branchcc (insn, operands); } + [(set_attr "cc" "none") + (set_attr "instr_format" "condjmp")]) + +;;============================================================================ +;; call +;; + +(define_insn "*call_insnpsi" + [(call (mem:PSI (match_operand:PSI 0 "general_operand" "rmi")) + (match_operand:HI 1 "immediate_operand" "X"))] + "msp430x_a20_operand (operands[0], VOIDmode)" + "calla\t%S0" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2s")]) + +(define_insn "*call_insnhi" + [(call (mem:HI (match_operand:HI 0 "general_operand" "rmi")) + (match_operand:HI 1 "immediate_operand" "X"))] + "" + "call\t%S0" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2s")]) + +(define_expand "call" + [(call (match_operand 0 "memory_operand" "") + (match_operand 1 "immediate_operand" ""))] + "" + { + operands[0] = msp430_prepare_call_address (operands[0]); + }) + +(define_insn "*call_value_insnpsi" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:PSI (match_operand:PSI 1 "general_operand" "rmi")) + (match_operand:HI 2 "immediate_operand" "X")))] + "msp430x_a20_operand (operands[1], VOIDmode)" + "calla\t%S1" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2s")]) + +(define_insn "*call_value_insnhi" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:HI (match_operand:HI 1 "general_operand" "rmi")) + (match_operand:HI 2 "immediate_operand" "X")))] + "" + "call\t%S1" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2s")]) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "immediate_operand" "")))] + "" + { + operands[1] = msp430_prepare_call_address (operands[1]); + }) + +;;======================================================================== +;; Multiplication + +(define_insn "*mpy_inhibit_intr_" + [(set (mem: (pre_dec: (reg:P REGNO_SP))) + (unspec_volatile: [(const_int 0)] UNSPECV_MPY_INHIBIT_INTR))] + "TARGET_CPUX || PSImode != mode" + "push\tr2\;dint\;nop" + [(set_attr "cc" "none") + (set_attr "length" "6")]) + +(define_expand "mpy_inhibit_intr" + [(const_int 0)] + "" + { + emit_insn (gen_rtx_SET (Pmode, + gen_rtx_MEM (Pmode, gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx)), + gen_rtx_UNSPEC_VOLATILE (Pmode, gen_rtvec (1, const0_rtx), UNSPECV_MPY_INHIBIT_INTR))); + DONE; + }) + +(define_insn "*mpy_restore_intr_" + [(set (mem: (post_inc: (reg:P REGNO_SP))) + (unspec_volatile: [(const_int 0)] UNSPECV_MPY_RESTORE_INTR))] + "TARGET_CPUX || PSImode != mode" + "pop\tr2" + [(set_attr "cc" "clobber") + (set_attr "length" "2")]) + +(define_expand "mpy_restore_intr" + [(const_int 0)] + "" + { + emit_insn (gen_rtx_SET (Pmode, + gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, stack_pointer_rtx)), + gen_rtx_UNSPEC_VOLATILE (Pmode, gen_rtvec (1, const0_rtx), UNSPECV_MPY_RESTORE_INTR))); + DONE; + }) + +(define_expand "mul3" + [(match_operand:INTModes 0 "nonimmediate_operand" "") + (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "general_operand" "")] + "" + "msp430_expand_mul (operands, 1); DONE;") + +(define_expand "mul3" + [(match_operand: 0 "nonimmediate_operand" "") + (match_operand:WidenableINTModes 1 "nonimmediate_operand" "") + (match_operand: 2 "general_operand" "")] + "" + "msp430_expand_mul (operands, 1); DONE;") + +(define_expand "umul3" + [(match_operand: 0 "nonimmediate_operand" "") + (match_operand:WidenableINTModes 1 "nonimmediate_operand" "") + (match_operand: 2 "general_operand" "")] + "" + "msp430_expand_mul (operands, 0); DONE;") + +;; All division currently supported by optabs + +;;======================================================================== +;; Shift + +;; NOTE: Order insn patterns so: +;; - Any really special case (e.g., ashrhi_15) +;; - Multi-position CPUX without extension comes first +;; - Single-position without CPUX +;; - Multi-position with CPUX + +;; Arithmetic shift left + +(define_expand "ashl3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (ashift: (match_operand: 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "msp430_expand_ashl (operands); DONE;") + +(define_expand "ashln2" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "") + (ashift: (match_dup 0) + (match_operand:QI 1 "const_int_operand" "")))] + "" + "") + +(define_insn "*ashl_m" + [(set (match_operand:WordRegModes 0 "register_operand" "=r") + (ashift: (match_operand: 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "M")))] + "TARGET_CPUX && CONST_INT_P(operands[2]) && MSP430_CPUX_MULTISHIFT_COUNT_P(INTVAL (operands[2]))" + "rlam\t%2, %0" + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2xn")]) + +(define_insn "ashl_1" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "+rm") + (ashift: (match_dup 0) (const_int 1))) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_template (mode, operands, 0, "rla", "rlc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "emu1dd")]) ; emulated add dst, dst + +(define_insn "*ashlx" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "=rm") + (ashift: (match_operand: 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "rL")))] + "TARGET_CPUX \ + && (REG_P (operands[0]) || (CONST_INT_P (operands[2]) && 1 == INTVAL (operands[2]))) \ + && (REG_P (operands[2]) || (CONST_INT_P (operands[2]) && MSP430_CPUX_REPEAT_COUNT_P(INTVAL (operands[2]))))" + { return msp430_output_cpux_template (mode, operands, 0, "rla", NULL, ".rpt\t%2"); } + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2x")]) ; emulated add dst, dst + +;; Arithmetic shift right + +(define_expand "ashr3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (ashiftrt: (match_operand: 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "msp430_expand_ashr (operands); DONE;") + +(define_expand "ashrn2" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "") + (ashiftrt: (match_dup 0) + (match_operand:QI 1 "const_int_operand" "")))] + "" + "") + +(define_insn "ashrhi_15" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (const_int 15)))] + "" + "swpb\t%0\;sxt\t%0\;swpb\t%0\;sxt\t%0" + [(set_attr "cc" "clobber") + (set_attr "instr_mult" "4") + (set_attr "instr_format" "fmt2")]) + +(define_insn "*ashr_m" + [(set (match_operand:WordRegModes 0 "register_operand" "=r") + (ashiftrt: (match_operand: 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "M")))] + "TARGET_CPUX && CONST_INT_P(operands[2]) && MSP430_CPUX_MULTISHIFT_COUNT_P(INTVAL (operands[2]))" + "rram\t%2, %0" + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2xn")]) + +(define_insn "ashr_1" + + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "+rm") + (ashiftrt: (match_dup 0) (const_int 1))) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_reverse_template (mode, operands, 0, "rra", "rrc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(define_insn "*ashrx" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "=rm") + (ashiftrt: (match_operand: 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "rL")))] + "TARGET_CPUX \ + && (REG_P (operands[0]) || (CONST_INT_P (operands[2]) && 1 == INTVAL (operands[2]))) \ + && (REG_P (operands[2]) || (CONST_INT_P (operands[2]) && MSP430_CPUX_REPEAT_COUNT_P(INTVAL (operands[2]))))" + { return msp430_output_cpux_template (mode, operands, 0, "rra", NULL, ".rpt\t%2"); } + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2x")]) + +;; Logical shift right + +(define_expand "lshr3" + [(set (match_operand:INTModes20 0 "nonimmediate_operand" "") + (lshiftrt: (match_operand: 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "msp430_expand_lshr (operands); DONE;") + +(define_expand "lshrn2" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "") + (lshiftrt: (match_dup 0) + (match_operand:QI 1 "const_int_operand" "")))] + "" + "") + +; lshr_1 does not include PSI because it has a prefix clrc insn, +; but the role is handled by lsrn_m. We just need a named unary +; expander to support the shift generation. +(define_expand "lshrpsi_1" + [(set (match_operand:PSI 0 "nonimmediate_operand" "") + (lshiftrt:PSI (match_dup 0) (const_int 1)))] + "TARGET_CPUX" + "") + +(define_insn "*lshr_m" + [(set (match_operand:WordRegModes 0 "register_operand" "=r") + (lshiftrt: (match_operand: 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "M")))] + "TARGET_CPUX && CONST_INT_P(operands[2]) && MSP430_CPUX_MULTISHIFT_COUNT_P(INTVAL (operands[2]))" + "rrum\t%2, %0" + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2xn")]) + +(define_insn "lshr_1" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "+rm") + (lshiftrt: (match_dup 0) (const_int 1))) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_reverse_template (mode, operands, 0, "rrc", NULL, "clrc"); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(define_insn "*lshrx" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "=rm") + (lshiftrt: (match_operand: 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "rL")))] + "TARGET_CPUX \ + && (REG_P (operands[0]) || (CONST_INT_P (operands[2]) && 1 == INTVAL (operands[2]))) \ + && (REG_P (operands[2]) || (CONST_INT_P (operands[2]) && MSP430_CPUX_REPEAT_COUNT_P(INTVAL (operands[2]))))" + { return msp430_output_cpux_template (mode, operands, 0, "rru", NULL, ".rpt\t%2"); } + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2x")]) + +;; Customized/special-handling rotate + +(define_insn "rla1" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "+rm") + (ashift: + (unspec_volatile [(match_dup 0)] UNSPECV_RLA) + (const_int 1)))] + "" + { return msp430_output_template (mode, operands, 0, "rla", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "emu1dd")]) ; emulated add dst, dst + +(define_insn "rlc1" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "+rm") + (unspec_volatile: [(match_dup 0)] UNSPECV_RLC)) + (use (reg:CC REGNO_SR)) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_template (mode, operands, 0, "rlc", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "emu1dd")]) ; emulated add dst, dst + +(define_insn "rra1" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "+rm") + (ashiftrt: + (unspec_volatile [(match_dup 0)] UNSPECV_RRA) + (const_int 1)))] + "" + { return msp430_output_reverse_template (mode, operands, 0, "rra", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(define_insn "rrc1" + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "+rm") + (unspec_volatile: [(match_dup 0)] UNSPECV_RRC)) + (use (reg:CC REGNO_SR)) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_reverse_template (mode, operands, 0, "rrc", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(define_insn "*rruhi1_x" + [(set (match_operand:HI 0 "nonimmediate_operand" "+r") + (lshiftrt:HI + (unspec_volatile [(match_dup 0)] UNSPECV_RRU) + (const_int 1)))] + "TARGET_CPUX" + "rrum\t#1, %0" + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2")]) + +(define_insn "rru1" + [(set (match_operand:INTRegModes 0 "nonimmediate_operand" "+rm") + (lshiftrt: + (unspec_volatile [(match_dup 0)] UNSPECV_RRU) + (const_int 1))) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_reverse_template (mode, operands, 0, "rrc", NULL, "clrc"); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +;; Miscellaneous shift helpers +(define_insn "clrc" + [(unspec_volatile [(const_int 0)] UNSPECV_CLRC)] + "" + "clrc" + [(set_attr "cc" "clobber") + (set_attr "length" "2") + ]) + +(define_insn "mwshl8xor" + [(set (match_operand:HI 0 "register_operand" "+r") + (unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r")] UNSPECV_MWSHL8XOR)) + (use (match_dup 0))] + "" + "xor.b\t%1, %0\;xor\t%1, %0\;swpb\t%0" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2")]) + +(define_insn "mwshr8xor" + [(set (match_operand:HI 0 "register_operand" "+r") + (unspec_volatile:HI [(match_operand:HI 1 "register_operand" "+r")] UNSPECV_MWSHR8XOR)) + (use (match_dup 0)) + (use (match_dup 1)) + (clobber (match_dup 1))] + "" + "swpb\t%1\;xor.b\t%1, %0\;xor\t%1, %0" + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2")]) + +;; ===================================================================== +;; single bit extract + +(define_expand "extzv" + [(match_operand:HI 0 "nonimmediate_operand" "") ; destination + (match_operand:QI 1 "nonimmediate_operand" "") ; packed value + (match_operand:HI 2 "const_int_operand" "") ; width + (match_operand:HI 3 "const_int_operand" "")] ; starting bit + "" + { + if (msp430_expand_extract (operands, false)) + DONE; + FAIL; + }) + +(define_insn "bittestforcarry2" + [(set + (reg:CC REGNO_SR) + (unspec:CC + [(match_operand:INTRegModes 0 "nonimmediate_operand" "Um") + (match_operand: 1 "general_operand" "Umi")] + UNSPEC_BITTEST_FOR_CARRY))] + "" + { return msp430_output_template (mode, operands, 1, "bit", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt1")]) + +;;======================================================================= +;; various BRANCH insns... + +;; Unconditional jump instruction. +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + { + int dist = msp430_jump_dist (operands[0], insn); + if (MSP430_JUMP_IN_RANGE (dist)) + return "jmp\t%0"; + return "br%@\t#%0"; + } + [(set_attr "cc" "none") + (set_attr "length" "2")]) + +; indirect jump +(define_insn "*indirect_jump20" + [(set (pc) (match_operand:PSI 0 "general_operand" "rmi"))] + "msp430x_a20_operand (operands[0], VOIDmode)" + "bra\t%0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*indirect_jump16" + [(set (pc) (match_operand:HI 0 "general_operand" "rmi"))] + "!msp430x_ext_operand(operands[0], VOIDmode)" + "br\t%0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_expand "indirect_jump" + [(set (pc) (match_operand 0 "general_operand" "rmi"))] + "" + "") + +;; Table helper +(define_insn "*tablejump20" + [(set (pc) (match_operand:PSI 0 "general_operand" "rmi")) + (use (label_ref (match_operand 1 "" "")))] + "msp430x_a20_operand (operands[0], VOIDmode)" + "bra\t%0\t; %1" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "tablejump16" + [(set (pc) (match_operand:HI 0 "general_operand" "rmi")) + (use (label_ref (match_operand 1 "" "")))] + "!msp430x_ext_operand(operands[0], VOIDmode)" + "br\t%0\t; %1" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_expand "tablejump" + [(parallel + [(set (pc) (match_operand 0 "general_operand" "rmi")) + (use (label_ref (match_operand 1 "" "")))])] + "" + "") + +;; return insn +(define_insn "*return_inhibited_fallthru" + [(return)] + "(reload_completed && cfun && cfun->machine + && (cfun->machine->frame_flags & MSP430_FF_ready_for_return) + && (cfun->machine->frame_flags & MSP430_FF_inhibit_return) + && msp430_inhibited_return_fallthru_p (insn))" + "" + [(set_attr "cc" "none") + (set_attr "length" "0")]) + +(define_insn "*return_inhibited_no_fallthru" + [(return)] + "(reload_completed && cfun && cfun->machine + && (cfun->machine->frame_flags & MSP430_FF_ready_for_return) + && (cfun->machine->frame_flags & MSP430_FF_inhibit_return))" + { + struct machine_function *mfp; + gcc_assert (cfun); + mfp = cfun->machine; + gcc_assert (mfp); + gcc_assert (NULL != mfp->inhibited_return_label); + fprintf (asm_out_file, "\tbr%s\t#", TARGET_CPUX ? "a" : ""); + assemble_name (asm_out_file, mfp->inhibited_return_label); + return "\n"; + } + [(set_attr "cc" "none") + (set_attr "length" "4")]) + +(define_insn "*return_pop_sr" + [(return)] + "(reload_completed && cfun && cfun->machine + && (cfun->machine->frame_flags & MSP430_FF_ready_for_return) + && (cfun->machine->frame_flags & MSP430_FF_use_reti))" + "reti" + [(set_attr "cc" "none") + (set_attr "length" "2")]) + +(define_insn "return" + [(return)] + "(reload_completed && cfun && cfun->machine + && (cfun->machine->frame_flags & MSP430_FF_ready_for_return))" + { + if (cfun->machine->frame_flags & MSP430_FF_callret_20) + return "reta"; + return "ret"; + } + [(set_attr "cc" "none") + (set_attr "length" "2")]) + +(define_expand "prologue" + [(const_int 0)] + "" + "msp430_expand_prologue (); DONE;") + +(define_expand "epilogue" + [(const_int 0)] + "" + "msp430_expand_epilogue (); DONE;") + +(include "peephole.md") diff --git gcc-4.7.0.orig/gcc/config/msp430/msp430.opt gcc-4.7.0/gcc/config/msp430/msp430.opt new file mode 100644 index 0000000..7f0b75d --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/msp430.opt @@ -0,0 +1,167 @@ +; Options for the MSP430 port of the compiler. +; Converted from msp430.c (gcc 3.2.3 port) + +; For every option from this file (such as PROF_STD), a corresponding command-line option is checked and an internal GCC flag is set. +; To check such flag one should use the TARGET_xxx macro (such as TARGET_PROF_STD). +; This replaces the deprecated #define TARGET_SWITCHES syntax +; String options are defined similarily and replace the #define TARGET_OPTIONS syntax + +;; This work is partially financed by the European Commission under the +;; Framework 6 Information Society Technologies Project +;; "Wirelessly Accessible Sensor Populations (WASP)". + +HeaderInclude +config/msp430/msp430-opts.h + +Enum +Name(cpu_type) Type(enum msp430_cpu_e) +CPU: Recognized MSP430 CPU architectures + +EnumValue +Enum(cpu_type) String(430) Value(MSP430_CPU_MSP430) + +EnumValue +Enum(cpu_type) String(430x) Value(MSP430_CPU_MSP430X) + +EnumValue +Enum(cpu_type) String(430xv2) Value(MSP430_CPU_MSP430XV2) + +Enum +Name(mpy_type) Type(enum msp430_mpy_e) +MPY: Recognized MSP430 hardware multiplier types + +EnumValue +Enum(mpy_type) String(none) Value(MSP430_MPY_NONE) + +EnumValue +Enum(mpy_type) String(16) Value(MSP430_MPY_16) + +EnumValue +Enum(mpy_type) String(16se) Value(MSP430_MPY_16SE) + +EnumValue +Enum(mpy_type) String(32) Value(MSP430_MPY_32) + +EnumValue +Enum(mpy_type) String(32dw) Value(MSP430_MPY_32DW) + +Enum +Name(iv_type) Type(int) +IVCNT: Recognized interrupt vector lengths + +EnumValue +Enum(iv_type) String(16) Value(16) + +EnumValue +Enum(iv_type) String(32) Value(32) + +EnumValue +Enum(iv_type) String(64) Value(64) + +Enum +Name(memory_model_type) Type(enum msp430_memory_model_e) +MEMORY_MODEL: Simplified interface to memory models (supersdes other options) + +EnumValue +Enum(memory_model_type) String(none) Value(MSP430_MEMORY_MODEL_NONE) + +EnumValue +Enum(memory_model_type) String(small) Value(MSP430_MEMORY_MODEL_SMALL) + +EnumValue +Enum(memory_model_type) String(medium) Value(MSP430_MEMORY_MODEL_MEDIUM) + +EnumValue +Enum(memory_model_type) String(large) Value(MSP430_MEMORY_MODEL_LARGE) + +EnumValue +Enum(memory_model_type) String(huge) Value(MSP430_MEMORY_MODEL_HUGE) + +Enum +Name(section_region_type) Type(enum msp430_section_region_e) +REGION: Control placement of objects in memory + +EnumValue +Enum(section_region_type) String(near) Value(MSP430_SECTION_REGION_NEAR) + +EnumValue +Enum(section_region_type) String(far) Value(MSP430_SECTION_REGION_FAR) + +EnumValue +Enum(section_region_type) String(any) Value(MSP430_SECTION_REGION_ANY) + +mnoint-hwmul +Target Report Mask(NOINT_HWMUL) +Assume interrupt routine does not do hardware multiply + +mdisable-watchdog +Target Var(msp430_disable_watchdog) Init(0) +Link the crt0 modules that disable the watchdog on startup + +misr20 +Target Report Mask(ISR20) +Preserve 20-bit values in registers saved in interrupt handlers + +msr16 +Target Report RejectNegative Negative(msr20) InverseMask(SR20) +Preserve 16-bit values in callee-saved registers in all functions (cancels -msr20) + +msr20 +Target Report RejectNegative Negative(msr16) Mask(SR20) +Preserve 20-bit values in callee-saved registers in all functions + +ma16 +Target Report RejectNegative Negative(ma20) InverseMask(A20) +Use 16-bit types for size_t and ptrdiff_t (cancels -ma20) + +ma20 +Target Report RejectNegative Negative(ma16) Mask(A20) +Use 20-bit types for size_t and ptrdiff_t + +mc16 +Target Report RejectNegative Negative(mc20) InverseMask(C20) +Default functions to use 16-bit call/return interface (cancels -mc20) + +mc20 +Target Report RejectNegative Negative(mc16) Mask(C20) +Default functions to use 20-bit call/return interface + +md16 +Target Report RejectNegative Negative(md20) InverseMask(D20) +Default size for data pointers is 16 bits (cancels -md20) + +md20 +Target Report RejectNegative Negative(md16) Mask(D20) +Default size for data pointers is 20 bits + +menable-libcall-shift +Target Var(msp430_enable_libcall_shift) Init(0) +Use library routines for non-constant shifts + +mmcu= +Target RejectNegative Joined Var(msp430_mcu_name) +-mmcu=MCU Select the target MCU (values from msp430mcu) + +mcpu= +Target RejectNegative Joined Enum(cpu_type) Var(msp430_cpu) Init(MSP430_CPU_MSP430) +-mcpu=CPU Specify the CPU architecture (e.g., 430x) + +mmpy= +Target RejectNegative Joined Enum(mpy_type) Var(msp430_mpy) Init(MSP430_MPY_NONE) +-mmpy=MPY Specify the available hardware multiplier + +mivcnt= +Target RejectNegative Joined Enum(iv_type) Var(msp430_ivcnt) Init(16) +-mivcnt=IVCNT Specify the number of interrupt vectors on the chip + +mmemory-model= +Target RejectNegative Joined Enum(memory_model_type) Var(msp430_memory_model) Init(MSP430_MEMORY_MODEL_NONE) +-mmemory-model=MEMORY_MODEL Simplified specification of code, data, and size ranges + +mcode-region= +Target RejectNegative Joined Enum(section_region_type) Var(msp430_code_region) Init(MSP430_SECTION_REGION_ANY) +-mcode-region=REGION Override default placement of code when -mc20 in effect + +mdata-region= +Target RejectNegative Joined Enum(section_region_type) Var(msp430_data_region) Init(MSP430_SECTION_REGION_ANY) +-mdata-region=REGION Override default placement of data when -md20 in effect diff --git gcc-4.7.0.orig/gcc/config/msp430/peephole.md gcc-4.7.0/gcc/config/msp430/peephole.md new file mode 100644 index 0000000..c696ff2 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/peephole.md @@ -0,0 +1,254 @@ +;; -*- Mode: Scheme -*- +;; Machine description for GNU compiler, +;; for Texas Instruments msp430 MCUs +;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +;; Contributed by Dmitry Diky +;; GCC 4.x port by Ivan Shcherbakov + +;; This work is partially financed by the European Commission under the +;; Framework 6 Information Society Technologies Project +;; "Wirelessly Accessible Sensor Populations (WASP)". + +; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; Gratuitous route through register for RMW on memory with reg operand +;; mov &m1, r0; op g3, r0; mov r0, &m1 => op g3, &m1 [r0 dead] +; see testsuite volpeep_reg.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_dup 0) + (match_operator: 2 "msp430_rmw_operator" + [(match_dup 0) + (match_operand: 3 "general_operand" "")])) + (set (match_dup 1) (match_dup 0))] + "peep2_reg_dead_p (3, operands[0])" + [(set (match_dup 1) + (match_op_dup 2 [(match_dup 1) (match_dup 3)]))] + "") + +;; Gratuitous route through register for RMW on memory with non-reg operand +;; mov &m1, r0; mov &m3, r2; op r0, r2; mov r2, &m1 => op &m3, &m1 [r0 dead, r2 dead] +; see testsuite volpeep_volmem.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_operand: 2 "register_operand" "") + (match_operand: 3 "nonimmediate_operand" "")) + (set (match_dup 2) + (match_operator: 4 "msp430_rmw_operator" + [(match_dup 2) + (match_dup 0)])) + (set (match_dup 1) (match_dup 2))] + "peep2_reg_dead_p (4, operands[0]) && peep2_reg_dead_p (4, operands[2])" + [(set (match_dup 1) + (match_op_dup 4 [(match_dup 1) (match_dup 3)]))] + "") + +;; Same as above but with operands swapped (used for sub) +;; mov &m1, r0; mov &m3, r2; op r2, r0; mov r0, &m1 => op &m3, &m1 +; see testsuite volpeep_volmem.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_operand: 2 "register_operand" "") + (match_operand: 3 "nonimmediate_operand" "")) + (set (match_dup 0) + (match_operator: 4 "msp430_rmw_operator" + [(match_dup 0) + (match_dup 2)])) + (set (match_dup 1) (match_dup 0))] + "peep2_reg_dead_p (4, operands[0]) && peep2_reg_dead_p (4, operands[2])" + [(set (match_dup 1) + (match_op_dup 4 [(match_dup 1) (match_dup 3)]))] + "") + +;; Assignment to volatile memory through a cast constant pointer +;; mov #c1, r0; mov @r0, r2; op3 g4, r2; mov r2, @r0 => op3 g4, &c1 [r0 dead, r2 dead] +; see testsuite vwa4.c, sf3559978.c +(define_peephole2 + [(set (match_operand 0 "pmode_register_operand" "") + (match_operand 1 "immediate_operand" "")) + (set (match_operand:INTRegModes 2 "register_operand" "") + (mem: (match_dup 0))) + (set (match_dup 2) + (match_operator: 3 "msp430_rmw_operator" + [(match_dup 2) + (match_operand: 4 "general_operand" "")])) + (set (mem: (match_dup 0)) (match_dup 2))] + "peep2_reg_dead_p (4, operands[0]) && peep2_reg_dead_p (4, operands[2])" + [(set (mem: (match_dup 1)) + (match_op_dup 3 [(mem: (match_dup 1)) (match_dup 4)]))] + "") + + +;; mov &m1, r0; mov &m3, r2; op r2, r0; mov r0, &m1 => mov &m3, r2; op r2, &m1 [r0 dead, r2 live] +; see testsuite volpeep_mem.c; vwa_error.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_operand: 2 "register_operand" "") + (match_operand: 3 "nonimmediate_operand" "")) + (set (match_dup 0) + (match_operator: 4 "msp430_rmw_operator" + [(match_dup 0) + (match_dup 2)])) + (set (match_dup 1) (match_dup 0))] + "peep2_reg_dead_p (4, operands[0]) + && (! ((MEM == GET_CODE (operands[3]) + || ASM_OPERANDS == GET_CODE (operands[3]) + || ASM_INPUT == GET_CODE (operands[3])) + && MEM_VOLATILE_P (operands[3]))) + && ! peep2_reg_dead_p (4, operands[2])" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 1) + (match_op_dup 4 [(match_dup 1) (match_dup 2)]))] + "") + +;; mov &m1, r0; mov &m3, r2; nand r2, r0; mov r0, &m1 => nand &m3, &m1 [r0 dead, r2 dead] +; see testsuite volpeep_volmem.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_operand: 2 "register_operand" "") + (match_operand: 3 "nonimmediate_operand" "")) + (set (match_dup 0) + (and: (not: (match_dup 2)) + (match_dup 0))) + (set (match_dup 1) (match_dup 0))] + "peep2_reg_dead_p (4, operands[0]) && peep2_reg_dead_p (4, operands[2])" + [(set (match_dup 1) + (and: (not: (match_dup 3)) (match_dup 1)))] + "") + +;; mov &m1, r0; nand g2, r0; mov r0, &m1 => nand g2, &m1 [r0 dead] +; see testsuite volpeep_reg.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_dup 0) + (and: (not: (match_operand: 2 "general_operand" "")) + (match_dup 0))) + (set (match_dup 1) (match_dup 0))] + "peep2_reg_dead_p (3, operands[0])" + [(set (match_dup 1) + (and: (not: (match_dup 2)) (match_dup 1)))] + "") + +;; mov &m1, r0; op r0, x2 => op &m1, x2 [r0 dead] +; transiently checked with vwa5.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_operand: 2 "nonimmediate_operand" "") + (match_operator: 3 "msp430_rmw_operator" + [(match_dup 2) + (match_dup 0)]))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (match_op_dup 3 [(match_dup 2) (match_dup 1)]))] + "") + +;; mov &m1, r0; nand r0, &m2 => nand &m1, &m2 [r0 dead] +; see testsuite volpeep_volmem.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_operand: 2 "nonimmediate_operand" "") + (and: (not: (match_dup 0)) + (match_dup 2)))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (and: (not: (match_dup 1)) (match_dup 2)))] + "") + +;; mov &m1, r0; mov r0 &m2; => mov &m1, &m2 [r0 dead] +; see testsuite volpeep_volmem.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "general_operand" "")) + (set (match_operand: 2 "nonimmediate_operand" "") + (match_dup 0))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) (match_dup 1))] + "") + +;; mov $r2, r0 ; mov r0, g2 => mov $r2, g2 [r0 dead] +; see testsuite builtins_read_sr.c +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (unspec_volatile:HI [(reg:HI REGNO_SR)] UNSPECV_READ_STATUS_REGISTER)) + (set (match_operand:HI 2 "nonimmediate_operand" "") + (match_dup 0))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) (unspec_volatile:HI [(reg:HI REGNO_SR)] UNSPECV_READ_STATUS_REGISTER))] + "") + +;; mov $r1, r0 ; mov r0, g2 => mov $r1, g2 [r0 dead] +; see testsuite builtins_sp.c +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (unspec_volatile:HI [(reg:HI REGNO_SP)] UNSPECV_READ_STACK_POINTER)) + (set (match_operand:HI 2 "nonimmediate_operand" "") + (match_dup 0))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) (unspec_volatile:HI [(reg:HI REGNO_SP)] UNSPECV_READ_STACK_POINTER))] + "") + +;; mov m1, r0; and g2, r0 ; cmp r0, 0 ; jeq => bit g2, m1 ; jeq [r0 dead] +; see testsuite sf3296698.c +(define_peephole2 + [(set (match_operand:INTRegModes 0 "register_operand" "") + (match_operand: 1 "nonimmediate_operand" "")) + (set (match_dup 0) + (and: + (match_dup 0) + (match_operand: 2 "general_operand" ""))) + (set (cc0) + (compare (match_dup 0) + (const_int 0))) + (set (pc) + (if_then_else (match_operator: 3 "equality_operator" + [(cc0) (const_int 0)]) + (match_operand 4 "" "") + (match_operand 5 "" "")))] + "peep2_reg_dead_p (4, operands[0])" + [(set (cc0) + (compare (and: (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (pc) + (if_then_else (match_operator: 3 "equality_operator" + [(cc0) (const_int 0)]) + (match_operand 4 "" "") + (match_operand 5 "" "")))] + "") + +;; and #c, g0 => nand #c2, g0 [where c2 == ~c and c is CG] +(define_peephole2 + [(set (match_operand:INTRegModes20 0 "nonimmediate_operand" "") + (and: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "const_int_operand" "")))] + "rtx_equal_p (operands[0], operands[1]) && MSP430_CG_INT_P (~ INTVAL (operands[2]))" + [(set (match_dup 0) + (and: (not: (match_operand: 3 "" "")) + (match_dup 1)))] + { + operands[3] = GEN_INT (trunc_int_for_mode (~ INTVAL (operands[2]), mode)); + }) + + diff --git gcc-4.7.0.orig/gcc/config/msp430/predicates.md gcc-4.7.0/gcc/config/msp430/predicates.md new file mode 100644 index 0000000..0ee6367 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/predicates.md @@ -0,0 +1,125 @@ +;; -*- Mode: Scheme -*- +;; Predicate definitions for MSP430 +;; Copyright (C) 2006 Free Software Foundation, Inc. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 2, or (at your +;; option) any later version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;; This work is partially financed by the European Commission under the +;; Framework 6 Information Society Technologies Project +;; "Wirelessly Accessible Sensor Populations (WASP)". + +;; Identify operators for which MSP430 provides a read-modify-write +;; solution in one instruction. +(define_predicate "msp430_rmw_operator" + (match_code "and,ior,xor,plus,minus")) + +;; Identify a post-increment memory operand (such is not a memory_operand) +(define_predicate "msp430_post_inc_operand" + (and (match_code "mem") + (match_code "post_inc" "0") + (match_code "reg" "00"))) + +;; Extend general operand to also allow post-increment memory references +(define_predicate "msp430_source_operand" + (ior (match_operand 0 "general_operand") + (match_operand 0 "msp430_post_inc_operand"))) + +;; A constant integer that fits in a signed 16-bit offset. +(define_predicate "msp430x_int16_operand" + (and (match_code "const_int") + (match_test "-32768 <= INTVAL (op)") + (match_test "INTVAL (op) <= 32767"))) + +;; For MSP430 indexed mode, the base is in a 16-bit or 20-bit register +;; and the offset is a signed 16-bit value. In many cases when GCC +;; generates this pattern, the base is the constant offset and the +;; offset is in the register. In this situation, symbolic references +;; to low memory at or above 0x8000 will produce the wrong address +;; because it would sign-extend. Identify index operations where the +;; offset is not a signed 16-bit constant. +(define_predicate "msp430x_unsafe_indexed_address_operand" + (and (match_code "plus") + (match_code "reg" "0") + (not (match_test "msp430x_int16_operand (XEXP (op, 1), mode)")))) + +;; Any memory operand that would require the CPUX extension word +;; version of a standard instruction to resolve as an operand. +;; Specifically, memory operands involving 20-bit addresses that are +;; not expressible as a signed 16-bit offset. +;; +(define_predicate "msp430x_unsafe_indexed_memory_operand" + (and (match_code "mem") + (match_test "GET_MODE (XEXP (op, 0)) == PSImode") + (match_test "msp430x_unsafe_indexed_address_operand (XEXP (op, 0), PSImode)"))) + +;; An operand suitable for use in an CPUX address-mode instruction. +;; Rules out only indexed registers where the offset is not a signed +;; 16-bit constant; 20-bit symbols and constants, registers, and +;; indirect registers are fine. +;; +;; Note that this check does not actually verify that the memory +;; address is PSImode. Unlike msp430x_ext_memory_operand, we assume +;; that this is not responsible for detecting that 20-bit addresses +;; might be necessary, just for determining whether resolving them +;; involves using an indexed register. This restriction is necessary +;; because most GCC label_ref instances are Pmode which may be HImode. +;; If this check insisted that the reference use a 20-bit pointer, the +;; code for table jumps and indirect calls through dispatch tables +;; would improperly generate a 16-bit instruction which would fail +;; when the relocations were resolved. +(define_predicate "msp430x_a20_operand" + (not (and (match_code "mem") + (match_test "msp430x_unsafe_indexed_address_operand (XEXP (op, 0), VOIDmode)")))) + +;; An operand which, when used as a 20-bit memory address, requires +;; that an instruction that provides an extension word be used. +(define_predicate "msp430x_ext_address_operand" + (ior (match_code "symbol_ref") + (match_code "label_ref") + (and (match_code "const_int") + (not (match_test "msp430x_int16_operand (op, mode)"))) + (and (match_code "const") ; symbol plus offset, usually + (match_test "msp430x_ext_address_operand (XEXP (op, 0), mode)")) + (and (match_code "plus") + (ior (match_test "msp430x_ext_address_operand (XEXP (op, 0), PSImode)") + (match_test "msp430x_ext_address_operand (XEXP (op, 1), PSImode)"))))) + +;; A memory operand that requires an extension word for 20-bit access. +(define_predicate "msp430x_ext_memory_operand" + (and (match_code "mem") + (match_test "GET_MODE (XEXP (op, 0)) == PSImode") + (match_test "msp430x_ext_address_operand (XEXP (op, 0), PSImode)"))) + +;; Any operand that would require the CPUX version of a standard +;; instruction to resolve as an operand. At this time, we only check +;; for memory operands; register operands are fine, as are constants +;; that may appear too large here because the mode is larger than a +;; word, but will be correctly truncated to a signed 16-bit value on +;; emission. +;; +;; Do not use this for CPUX address mode instructions like mova. +;; 20-bit symbol references are acceptable there. Use +;; msp430x_a20_operand to check for invalid indexed register use in +;; address mode instructions. +(define_predicate "msp430x_ext_operand" + (match_test "msp430x_ext_memory_operand (op, mode)")) + +;; Identify identity comparisons +(define_special_predicate "equality_operator" + (match_code "eq,ne")) + diff --git gcc-4.7.0.orig/gcc/config/msp430/t-msp430 gcc-4.7.0/gcc/config/msp430/t-msp430 new file mode 100644 index 0000000..9d792a8 --- /dev/null +++ gcc-4.7.0/gcc/config/msp430/t-msp430 @@ -0,0 +1,50 @@ +EXTRA_MULTILIB_PARTS += $(T)libcrt0.a +EXTRA_MULTILIB_PARTS += $(T)libcrt0dwdt.a +EXTRA_PARTS += crt0ivtbl16$(objext) crt0ivtbl32$(objext) crt0ivtbl64$(objext) + +# We do not create a multilib for 430xv2, since it is identical to 430x +# except in terms of instruction timings. It maps to 430x. +TM_MSP430_CPU=430/430x + +# Although 16se, 32, and 32dw are valid options, they do not provide +# sufficient benefit to warrant their use in multilibs, and are treated as +# equivalent to 16. See SF 3497685. +TM_MSP430_MPY=none/16 + +MULTILIB_OPTIONS = \ + mcpu=$(subst /,/mcpu=,$(TM_MSP430_CPU)) \ + mmpy=$(subst /,/mmpy=,$(TM_MSP430_MPY)) \ + msr20 \ + mc20 \ + md20 \ + ma20 +MULTILIB_MATCHES = \ + mcpu?430x=mcpu?430xv2 \ + mmpy?16=mmpy?16se \ + mmpy?16=mmpy?32 \ + mmpy?16=mmpy?32dw +MULTILIB_EXCLUSIONS = \ + !mcpu=430x/msr20 \ + !mcpu=430x/md20 \ + !mcpu=430x/mc20 \ + !msr20/md20 \ + !msr20/mc20 \ + !md20/ma20 + +msp430-builtins.o: $(srcdir)/config/msp430/msp430-builtins.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/msp430/msp430-builtins.c + +msp430-function.o: $(srcdir)/config/msp430/msp430-function.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/msp430/msp430-function.c + +msp430-c.o: $(srcdir)/config/msp430/msp430-c.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/msp430/msp430-c.c + +msp430-gcc.o: $(srcdir)/config/msp430/msp430-gcc.c $(CONFIG_H) $(TM_H) $(C_COMMON_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(DRIVER_DEFINES) \ + -DPREFIX=\"$(prefix)\" \ + $(srcdir)/config/msp430/msp430-gcc.c diff --git gcc-4.7.0.orig/gcc/configure gcc-4.7.0/gcc/configure index e2a0aea..120a9d3 100755 --- gcc-4.7.0.orig/gcc/configure +++ gcc-4.7.0/gcc/configure @@ -25919,6 +25919,7 @@ esac # version to the per-target configury. case "$cpu_type" in alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze | mips \ + | msp430 \ | pa | rs6000 | score | sparc | spu | tilegx | tilepro | xstormy16 | xtensa) insn="nop" ;; diff --git gcc-4.7.0.orig/gcc/configure.ac gcc-4.7.0/gcc/configure.ac index 39302ad..84f51cd 100644 --- gcc-4.7.0.orig/gcc/configure.ac +++ gcc-4.7.0/gcc/configure.ac @@ -4106,6 +4106,7 @@ esac # version to the per-target configury. case "$cpu_type" in alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze | mips \ + | msp430 \ | pa | rs6000 | score | sparc | spu | tilegx | tilepro | xstormy16 | xtensa) insn="nop" ;; diff --git gcc-4.7.0.orig/gcc/convert.c gcc-4.7.0/gcc/convert.c index dbe2c7e..2993388 100644 --- gcc-4.7.0.orig/gcc/convert.c +++ gcc-4.7.0/gcc/convert.c @@ -774,6 +774,7 @@ convert_to_integer (tree type, tree expr) (Otherwise would recurse infinitely in convert. */ if (TYPE_PRECISION (typex) != inprec) { + tree otypex = typex; /* Don't do unsigned arithmetic where signed was wanted, or vice versa. Exception: if both of the original operands were @@ -811,10 +812,12 @@ convert_to_integer (tree type, tree expr) typex = unsigned_type_for (typex); else typex = signed_type_for (typex); - return convert (type, - fold_build2 (ex_form, typex, - convert (typex, arg0), - convert (typex, arg1))); + + if (TYPE_PRECISION (otypex) == TYPE_PRECISION (typex)) + return convert (type, + fold_build2 (ex_form, typex, + convert (typex, arg0), + convert (typex, arg1))); } } } diff --git gcc-4.7.0.orig/gcc/coverage.c gcc-4.7.0/gcc/coverage.c index ce8b175..14fe52f 100644 --- gcc-4.7.0.orig/gcc/coverage.c +++ gcc-4.7.0/gcc/coverage.c @@ -131,7 +131,8 @@ static void coverage_obj_finish (VEC(constructor_elt,gc) *); tree get_gcov_type (void) { - return lang_hooks.types.type_for_size (GCOV_TYPE_SIZE, false); + enum machine_mode mode = smallest_mode_for_size (GCOV_TYPE_SIZE, MODE_INT); + return lang_hooks.types.type_for_mode (mode, false); } /* Return the type node for gcov_unsigned_t. */ @@ -139,7 +140,8 @@ get_gcov_type (void) static tree get_gcov_unsigned_t (void) { - return lang_hooks.types.type_for_size (32, true); + enum machine_mode mode = smallest_mode_for_size (32, MODE_INT); + return lang_hooks.types.type_for_mode (mode, true); } static hashval_t diff --git gcc-4.7.0.orig/gcc/cselib.c gcc-4.7.0/gcc/cselib.c index 56f2b7f..3b7aa93 100644 --- gcc-4.7.0.orig/gcc/cselib.c +++ gcc-4.7.0/gcc/cselib.c @@ -2523,8 +2523,7 @@ cselib_record_sets (rtx insn) sets[i].src_elt = cselib_lookup (src, GET_MODE (dest), 1, VOIDmode); if (MEM_P (dest)) { - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest)); + enum machine_mode address_mode = MEM_ADDRESS_MODE (dest); sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), address_mode, 1, diff --git gcc-4.7.0.orig/gcc/doc/tm.texi gcc-4.7.0/gcc/doc/tm.texi index 91e4b04..411a4b8 100644 --- gcc-4.7.0.orig/gcc/doc/tm.texi +++ gcc-4.7.0/gcc/doc/tm.texi @@ -1325,6 +1325,58 @@ Return machine mode to be used for @code{_Unwind_Word} type. The default is to use @code{word_mode}. @end deftypefn +@deftypefn {Target Hook} void TARGET_BUILD_COMMON_TREE_NODES (void) +Define target-specific types needed for basic functionality like +@code{size_type_node}. It is invoked from @code{build_common_tree_nodes} +after the standard types are defined, but before @code{SIZE_TYPE} is +referenced. +@end deftypefn + +@deftypefn {Target Hook} int TARGET_SIZE_TYPE_PRECISION (void) +Specify the precision of @code{SIZE_TYPE} when that macro references a +target-specific built-in type that does not have one of the hard-coded +names. The hook should return zero if @code{SIZE_TYPE} matches a standard +name. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_SIZE_TYPE_TREE (void) +Return the main variant type node corresponding to @code{SIZE_TYPE} when +that macro references a target-specific built-in type that does not have one +of the hard-coded names; this will be used as @code{size_type_node}. The +hook should return zero if @code{SIZE_TYPE} matches a standard name. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_PTRDIFF_TYPE_TREE (void) +Return the main variant type node corresponding to @code{PTRDIFF_TYPE} when +that macro references a target-specific built-in type that does not have one +of the hard-coded names; this will be used as @code{ptrdiff_type_node}. The +hook should return zero if @code{PTRDIFF_TYPE} matches a standard name. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_C_COMMON_TYPE_FOR_SIZE (unsigned int @var{bits}, int @var{unsignedp}) +Back-door to intercept type lookups for non-standard core types. This is +invoked from @code{c_common_type_for_size}, and if it returns a +non-@code{NULL} node that node should be the main variant of an integer type +with @var{bits} precision that is unsigned if @var{unsignedp} is nonzero, +otherwise signed. When @code{NULL} is returned the common lookup is used. +@end deftypefn + +@deftypefn {Target Hook} tree TARGET_C_COMMON_SIGNED_OR_UNSIGNED_TYPE (int @var{unsignedp}, tree @var{type}) +Back-door to intercept type lookups for non-standard core types. This is +invoked from @code{c_common_signed_or_unsigned_type}, and if it returns a +non-@code{NULL} node that node should be the type that is the same as +@var{type} except unsigned or signed according to @var{unsignedp}. When +@code{NULL} is returned the common algorithm is used. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_CPP_BUILTIN_DEFINE_TYPE_MINMAX (const char *@var{min_macro}, const char *@var{max_macro}, tree @var{type}) +Back-door to define preprocessor min/max macro values for non-standard core +types. This is invoked from @code{builtin_define_type_minmax} from +@file{c-cppbuiltin.c} to bypass the limited set of pre-defined extrema. +Return non-zero if the type was recognized and @code{cpp_define} invoked as +required. +@end deftypefn + @defmac ROUND_TOWARDS_ZERO If defined, this macro should be true if the prevailing rounding mode is towards zero. @@ -4304,6 +4356,22 @@ hook returns true for both @code{ptr_mode} and @code{Pmode}. Define this to return nonzero if the memory reference @var{ref} may alias with the system C library errno location. The default version of this hook assumes the system C library errno location is either a declaration of type int or accessed by dereferencing a pointer to int. @end deftypefn +@deftypefn {Target Hook} {enum machine_mode} TARGET_TYPE_POINTER_MODE (tree @var{to_type}) +Define this to return the machine mode to use for pointers to @var{to_type}. The default version of this hook defers to @code{TARGET_ADDR_SPACE_POINTER_MODE}. +@end deftypefn + +@deftypefn {Target Hook} {enum machine_mode} TARGET_TYPE_ADDRESS_MODE (tree @var{to_type}) +Define this to return the machine mode to use for addresses of @var{to_type}. The default version of this hook defers to @code{TARGET_ADDR_SPACE_ADDRESS_MODE}. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_TYPE_VALID_POINTER_MODE (enum machine_mode @var{mode}, tree @var{to_type}) +Define this to return nonzero if the port can handle pointers with machine mode @var{mode} to @var{to_type}. This target hook is the same as the @code{TARGET_VALID_POINTER_MODE} target hook, except that it considers the type referenced. The default version of this hook extracts the address space and uses @code{TARGET_ADDR_SPACE_VALID_POINTER_MODE}. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_DEFAULT_POINTER_ADDRESS_MODES_P (void) +If a target implements @code{TARGET_TYPE_POINTER_MODE}, @code{TARGET_TYPE_ADDRESS_MODE}, @code{TARGET_ADDR_SPACE_POINTER_MODE}, or @code{TARGET_ADDR_SPACE_ADDRESS_MODE}, define this to return true when the pointer mode will always match @code{Pmode} and the address mode will always match @code{ptr_mode}. If not defined, this will return false if any of those hooks are defined. +@end deftypefn + @deftypefn {Target Hook} bool TARGET_SCALAR_MODE_SUPPORTED_P (enum machine_mode @var{mode}) Define this to return nonzero if the port is prepared to handle insns involving scalar mode @var{mode}. For a scalar mode to be @@ -7104,6 +7172,12 @@ section names for mergeable constant data. Define this macro to override the string if a different section name should be used. @end deftypevr +@deftypefn {Target Hook} {const char *} TARGET_ASM_DECL_MERGEABLE_RODATA_PREFIX (tree @var{decl}) +Return the prefix to construct section names for mergeable constant data +associated with @samp{DECL_SECTION_NAME (@var{decl})}. +The default version of this references @code{TARGET_ASM_MERGEABLE_RODATA_PREFIX}. +@end deftypefn + @deftypefn {Target Hook} {section *} TARGET_ASM_TM_CLONE_TABLE_SECTION (void) Return the section that should be used for transactional memory clone tables. @end deftypefn @@ -7406,6 +7480,15 @@ is non-NULL, it is the @code{VAR_DECL} or @code{FUNCTION_DECL} with which this section is associated. @end deftypefn +@deftypefn {Target Hook} {section *} TARGET_ASM_VARIABLE_SECTION (tree @var{decl}, bool @var{prefer_noswitch_p}) +Return preferred (sub)section for @var{decl}. Main purpose of this hook is +to allow the target to actually control the section, which +@code{TARGET_ASM_SELECT_SECTION} does not. The default implementation makes +a guess among various standard sections based on the decl address space and +various flags, and falls back to @code{TARGET_ASM_VARIABLE_SECTION} if it +doesn't like something else better. +@end deftypefn + @deftypefn {Target Hook} {section *} TARGET_ASM_FUNCTION_SECTION (tree @var{decl}, enum node_frequency @var{freq}, bool @var{startup}, bool @var{exit}) Return preferred text (sub)section for function @var{decl}. Main purpose of this function is to separate cold, normal and hot diff --git gcc-4.7.0.orig/gcc/doc/tm.texi.in gcc-4.7.0/gcc/doc/tm.texi.in index 0ebc15d..165536a 100644 --- gcc-4.7.0.orig/gcc/doc/tm.texi.in +++ gcc-4.7.0/gcc/doc/tm.texi.in @@ -1313,6 +1313,58 @@ Return machine mode to be used for @code{_Unwind_Word} type. The default is to use @code{word_mode}. @end deftypefn +@hook TARGET_BUILD_COMMON_TREE_NODES +Define target-specific types needed for basic functionality like +@code{size_type_node}. It is invoked from @code{build_common_tree_nodes} +after the standard types are defined, but before @code{SIZE_TYPE} is +referenced. +@end deftypefn + +@hook TARGET_SIZE_TYPE_PRECISION +Specify the precision of @code{SIZE_TYPE} when that macro references a +target-specific built-in type that does not have one of the hard-coded +names. The hook should return zero if @code{SIZE_TYPE} matches a standard +name. +@end deftypefn + +@hook TARGET_SIZE_TYPE_TREE +Return the main variant type node corresponding to @code{SIZE_TYPE} when +that macro references a target-specific built-in type that does not have one +of the hard-coded names; this will be used as @code{size_type_node}. The +hook should return zero if @code{SIZE_TYPE} matches a standard name. +@end deftypefn + +@hook TARGET_PTRDIFF_TYPE_TREE +Return the main variant type node corresponding to @code{PTRDIFF_TYPE} when +that macro references a target-specific built-in type that does not have one +of the hard-coded names; this will be used as @code{ptrdiff_type_node}. The +hook should return zero if @code{PTRDIFF_TYPE} matches a standard name. +@end deftypefn + +@hook TARGET_C_COMMON_TYPE_FOR_SIZE +Back-door to intercept type lookups for non-standard core types. This is +invoked from @code{c_common_type_for_size}, and if it returns a +non-@code{NULL} node that node should be the main variant of an integer type +with @var{bits} precision that is unsigned if @var{unsignedp} is nonzero, +otherwise signed. When @code{NULL} is returned the common lookup is used. +@end deftypefn + +@hook TARGET_C_COMMON_SIGNED_OR_UNSIGNED_TYPE +Back-door to intercept type lookups for non-standard core types. This is +invoked from @code{c_common_signed_or_unsigned_type}, and if it returns a +non-@code{NULL} node that node should be the type that is the same as +@var{type} except unsigned or signed according to @var{unsignedp}. When +@code{NULL} is returned the common algorithm is used. +@end deftypefn + +@hook TARGET_CPP_BUILTIN_DEFINE_TYPE_MINMAX +Back-door to define preprocessor min/max macro values for non-standard core +types. This is invoked from @code{builtin_define_type_minmax} from +@file{c-cppbuiltin.c} to bypass the limited set of pre-defined extrema. +Return non-zero if the type was recognized and @code{cpp_define} invoked as +required. +@end deftypefn + @defmac ROUND_TOWARDS_ZERO If defined, this macro should be true if the prevailing rounding mode is towards zero. @@ -7025,6 +7077,12 @@ otherwise. @hook TARGET_ASM_MERGEABLE_RODATA_PREFIX +@hook TARGET_ASM_DECL_MERGEABLE_RODATA_PREFIX +Return the prefix to construct section names for mergeable constant data +associated with @samp{DECL_SECTION_NAME (@var{decl})}. +The default version of this references @code{TARGET_ASM_MERGEABLE_RODATA_PREFIX}. +@end deftypefn + @hook TARGET_ASM_TM_CLONE_TABLE_SECTION @hook TARGET_ASM_SELECT_RTX_SECTION @@ -7316,6 +7374,15 @@ is non-NULL, it is the @code{VAR_DECL} or @code{FUNCTION_DECL} with which this section is associated. @end deftypefn +@hook TARGET_ASM_VARIABLE_SECTION +Return preferred (sub)section for @var{decl}. Main purpose of this hook is +to allow the target to actually control the section, which +@code{TARGET_ASM_SELECT_SECTION} does not. The default implementation makes +a guess among various standard sections based on the decl address space and +various flags, and falls back to @code{TARGET_ASM_VARIABLE_SECTION} if it +doesn't like something else better. +@end deftypefn + @hook TARGET_ASM_FUNCTION_SECTION Return preferred text (sub)section for function @var{decl}. Main purpose of this function is to separate cold, normal and hot diff --git gcc-4.7.0.orig/gcc/dojump.c gcc-4.7.0/gcc/dojump.c index 91bebee..6745200 100644 --- gcc-4.7.0.orig/gcc/dojump.c +++ gcc-4.7.0/gcc/dojump.c @@ -444,36 +444,6 @@ do_jump (tree exp, rtx if_false_label, rtx if_true_label, int prob) /* Lowered by gimplify.c. */ gcc_unreachable (); - case COMPONENT_REF: - case BIT_FIELD_REF: - case ARRAY_REF: - case ARRAY_RANGE_REF: - { - HOST_WIDE_INT bitsize, bitpos; - int unsignedp; - enum machine_mode mode; - tree type; - tree offset; - int volatilep = 0; - - /* Get description of this reference. We don't actually care - about the underlying object here. */ - get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode, - &unsignedp, &volatilep, false); - - type = lang_hooks.types.type_for_size (bitsize, unsignedp); - if (! SLOW_BYTE_ACCESS - && type != 0 && bitsize >= 0 - && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp)) - && have_insn_for (COMPARE, TYPE_MODE (type))) - { - do_jump (fold_convert (type, exp), if_false_label, if_true_label, - prob); - break; - } - goto normal; - } - case MINUS_EXPR: /* Nonzero iff operands of minus differ. */ code = NE_EXPR; diff --git gcc-4.7.0.orig/gcc/dse.c gcc-4.7.0/gcc/dse.c index a9fe924..7955c66 100644 --- gcc-4.7.0.orig/gcc/dse.c +++ gcc-4.7.0/gcc/dse.c @@ -1170,8 +1170,7 @@ canon_address (rtx mem, HOST_WIDE_INT *offset, cselib_val **base) { - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); + enum machine_mode address_mode = MEM_ADDRESS_MODE (mem); rtx mem_address = XEXP (mem, 0); rtx expanded_address, address; int expanded; diff --git gcc-4.7.0.orig/gcc/dwarf2out.c gcc-4.7.0/gcc/dwarf2out.c index 63c46c0..b33f252 100644 --- gcc-4.7.0.orig/gcc/dwarf2out.c +++ gcc-4.7.0/gcc/dwarf2out.c @@ -11549,7 +11549,7 @@ get_address_mode (rtx mem) enum machine_mode mode = GET_MODE (XEXP (mem, 0)); if (mode != VOIDmode) return mode; - return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); + return MEM_ADDRESS_MODE (mem); } /* The following routine converts the RTL for a variable or parameter diff --git gcc-4.7.0.orig/gcc/emit-rtl.c gcc-4.7.0/gcc/emit-rtl.c index a95c146..064f9d9 100644 --- gcc-4.7.0.orig/gcc/emit-rtl.c +++ gcc-4.7.0/gcc/emit-rtl.c @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "target.h" #include "tree-flow.h" +#include "optabs.h" struct target_rtl default_target_rtl; #if SWITCHABLE_TARGET @@ -257,6 +258,8 @@ mem_attrs_htab_hash (const void *x) return (p->alias ^ (p->align * 1000) ^ (p->addrspace * 4000) + ^ (p->pointer_mode * 7000) + ^ (p->address_mode * 13000) ^ ((p->offset_known_p ? p->offset : 0) * 50000) ^ ((p->size_known_p ? p->size : 0) * 2500000) ^ (size_t) iterative_hash_expr (p->expr, 0)); @@ -274,6 +277,8 @@ mem_attrs_eq_p (const struct mem_attrs *p, const struct mem_attrs *q) && (!p->size_known_p || p->size == q->size) && p->align == q->align && p->addrspace == q->addrspace + && p->pointer_mode == q->pointer_mode + && p->address_mode == q->address_mode && (p->expr == q->expr || (p->expr != NULL_TREE && q->expr != NULL_TREE && operand_equal_p (p->expr, q->expr, 0)))); @@ -693,6 +698,14 @@ validate_subreg (enum machine_mode omode, enum machine_mode imode, if (offset >= isize) return false; + /* The subreg cannot stretch beyond what the reg can hold (at least + * not if it's a real register). */ + if (reg && REG_P (reg) + && MODE_PARTIAL_INT == GET_MODE_CLASS (imode) + && GET_MODE_PRECISION (imode) < (BITS_PER_UNIT * offset + + GET_MODE_BITSIZE (omode))) + return false; + /* ??? This should not be here. Temporarily continue to allow word_mode subregs of anything. The most common offender is (subreg:SI (reg:DF)). Generally, backends are doing something sketchy but it'll take time to @@ -1431,6 +1444,21 @@ operand_subword_force (rtx op, unsigned int offset, enum machine_mode mode) } result = operand_subword (op, offset, 1, mode); + if (! result && MODE_PARTIAL_INT == GET_MODE_CLASS (mode)) + { + enum machine_mode wider_mode; + rtx wide_op; + enum insn_code icode; + + wider_mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0); + gcc_assert (wider_mode != mode); + gcc_assert (GET_MODE_SIZE (wider_mode) == GET_MODE_SIZE (mode)); + wide_op = gen_reg_rtx (wider_mode); + icode = convert_optab_handler (zext_optab, wider_mode, mode); + gcc_assert (icode != CODE_FOR_nothing); + emit_unop_insn (icode, wide_op, op, UNKNOWN); + result = operand_subword (wide_op, offset, 1, wider_mode); + } gcc_assert (result); return result; @@ -1859,6 +1887,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* Now set the attributes we computed above. */ attrs.addrspace = as; + attrs.pointer_mode = targetm.addr_space.pointer_mode(as); + attrs.address_mode = targetm.addr_space.address_mode(as); set_mem_attrs (ref, &attrs); } @@ -1894,6 +1924,21 @@ set_mem_addr_space (rtx mem, addr_space_t addrspace) set_mem_attrs (mem, &attrs); } +/* Set the machine modes for pointers to and addresses of MEM. */ + +void +set_mem_pointer_address_modes (rtx mem, enum machine_mode pointer_mode, + enum machine_mode address_mode) +{ + struct mem_attrs attrs; + + attrs = *get_mem_attrs (mem); + attrs.pointer_mode = pointer_mode; + attrs.address_mode = address_mode; + set_mem_attrs (mem, &attrs); +} + + /* Set the alignment of MEM to ALIGN bits. */ void @@ -2070,7 +2115,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, /* Convert a possibly large offset to a signed value within the range of the target address space. */ - address_mode = targetm.addr_space.address_mode (attrs.addrspace); + address_mode = attrs.address_mode; pbits = GET_MODE_BITSIZE (address_mode); if (HOST_BITS_PER_WIDE_INT > pbits) { @@ -2156,7 +2201,7 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) struct mem_attrs attrs, *defattrs; attrs = *get_mem_attrs (memref); - address_mode = targetm.addr_space.address_mode (attrs.addrspace); + address_mode = attrs.address_mode; new_rtx = simplify_gen_binary (PLUS, address_mode, addr, offset); /* At this point we don't know _why_ the address is invalid. It @@ -2344,6 +2389,8 @@ set_mem_attrs_for_spill (rtx mem) attrs.expr = get_spill_slot_decl (true); attrs.alias = MEM_ALIAS_SET (DECL_RTL (attrs.expr)); attrs.addrspace = ADDR_SPACE_GENERIC; + attrs.pointer_mode = targetm.addr_space.pointer_mode(attrs.addrspace); + attrs.address_mode = targetm.addr_space.address_mode(attrs.addrspace); /* We expect the incoming memory to be of the form: (mem:MODE (plus (reg sfp) (const_int offset))) @@ -5577,6 +5624,8 @@ init_emit_regs (void) attrs = ggc_alloc_cleared_mem_attrs (); attrs->align = BITS_PER_UNIT; attrs->addrspace = ADDR_SPACE_GENERIC; + attrs->pointer_mode = targetm.addr_space.pointer_mode(attrs->addrspace); + attrs->address_mode = targetm.addr_space.address_mode(attrs->addrspace); if (mode != BLKmode) { attrs->size_known_p = true; diff --git gcc-4.7.0.orig/gcc/emit-rtl.h gcc-4.7.0/gcc/emit-rtl.h index bc91193..661a15f 100644 --- gcc-4.7.0.orig/gcc/emit-rtl.h +++ gcc-4.7.0/gcc/emit-rtl.h @@ -29,6 +29,10 @@ extern void set_mem_align (rtx, unsigned int); /* Set the address space of MEM to ADDRSPACE. */ extern void set_mem_addr_space (rtx, addr_space_t); +/* Set the machine modes for pointers to and addresses of MEM. */ +extern void set_mem_pointer_address_modes (rtx, enum machine_mode, + enum machine_mode); + /* Set the expr for MEM to EXPR. */ extern void set_mem_expr (rtx, tree); diff --git gcc-4.7.0.orig/gcc/except.c gcc-4.7.0/gcc/except.c index 8d56e10..6e91cc2 100644 --- gcc-4.7.0.orig/gcc/except.c +++ gcc-4.7.0/gcc/except.c @@ -1120,7 +1120,7 @@ sjlj_emit_function_enter (rtx dispatch_label) calling it directly. Thus, we must call assemble_external_libcall here, as we can not depend on emit_library_call to do it for us. */ assemble_external_libcall (personality); - mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs); + mem = adjust_address (fc, FUNCTION_MODE, sjlj_fc_personality_ofs); emit_move_insn (mem, personality); mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs); diff --git gcc-4.7.0.orig/gcc/explow.c gcc-4.7.0/gcc/explow.c index 11dffed..50180ba 100644 --- gcc-4.7.0.orig/gcc/explow.c +++ gcc-4.7.0/gcc/explow.c @@ -839,8 +839,7 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, enum machine_mode mode, case REFERENCE_TYPE: case POINTER_TYPE: *punsignedp = POINTERS_EXTEND_UNSIGNED; - return targetm.addr_space.address_mode - (TYPE_ADDR_SPACE (TREE_TYPE (type))); + return targetm.type_address_mode (TREE_TYPE (type)); break; #endif diff --git gcc-4.7.0.orig/gcc/expmed.c gcc-4.7.0/gcc/expmed.c index 09a933d..07b9fd9 100644 --- gcc-4.7.0.orig/gcc/expmed.c +++ gcc-4.7.0/gcc/expmed.c @@ -1454,13 +1454,14 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, * (int) BITS_PER_WORD)) : (int) i * BITS_PER_WORD); rtx target_part = operand_subword (target, wordnum, 1, VOIDmode); - rtx result_part - = extract_bit_field (op0, MIN (BITS_PER_WORD, + rtx result_part; + + gcc_assert (target_part); + result_part = extract_bit_field (op0, MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD), bitnum + bit_offset, 1, false, target_part, mode, word_mode); - gcc_assert (target_part); if (result_part != target_part) emit_move_insn (target_part, result_part); @@ -1687,6 +1688,24 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, unsigned HOST_WIDE_INT bitnum, int unsignedp, bool packedp, rtx target, enum machine_mode mode, enum machine_mode tmode) { + if (packedp && MEM_P (str_rtx) && MODE_PARTIAL_INT == GET_MODE_CLASS (mode)) + { + enum machine_mode wider_mode; + rtx wide_extracted; + rtx wide_str_rtx; + + wider_mode = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 0); + gcc_assert (wider_mode != mode); + gcc_assert (GET_MODE_SIZE (wider_mode) == GET_MODE_SIZE (mode)); + + wide_str_rtx = shallow_copy_rtx (str_rtx); + PUT_MODE (wide_str_rtx, wider_mode); + wide_extracted = extract_bit_field (wide_str_rtx, bitsize, bitnum, + unsignedp, packedp, NULL_RTX, + wider_mode, wider_mode); + return extract_bit_field (wide_extracted, bitsize, bitnum, unsignedp, + packedp, target, mode, tmode); + } return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, packedp, target, mode, tmode, true); } @@ -2174,9 +2193,9 @@ expand_shift_1 (enum tree_code code, enum machine_mode mode, rtx shifted, { if (CONST_INT_P (op1) && ((unsigned HOST_WIDE_INT) INTVAL (op1) >= - (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))) + (unsigned HOST_WIDE_INT) GET_MODE_PRECISION (mode))) op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) - % GET_MODE_BITSIZE (mode)); + % GET_MODE_PRECISION (mode)); else if (GET_CODE (op1) == SUBREG && subreg_lowpart_p (op1) && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (op1)))) diff --git gcc-4.7.0.orig/gcc/expr.c gcc-4.7.0/gcc/expr.c index a3ace7a..3fc41a5 100644 --- gcc-4.7.0.orig/gcc/expr.c +++ gcc-4.7.0/gcc/expr.c @@ -421,38 +421,48 @@ convert_move (rtx to, rtx from, int unsignedp) xImode for all MODE_PARTIAL_INT modes they use, but no others. */ if (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT) { - enum machine_mode full_mode - = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT); + convert_optab tab; - gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode) - != CODE_FOR_nothing); + if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode)) + tab = unsignedp ? zext_optab : sext_optab; + else + tab = trunc_optab; + + if (CODE_FOR_nothing == convert_optab_handler (tab, to_mode, from_mode)) + { + enum machine_mode full_mode + = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT); - if (full_mode != from_mode) - from = convert_to_mode (full_mode, from, unsignedp); - emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode), - to, from, UNKNOWN); - return; + gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode) + != CODE_FOR_nothing); + + if (full_mode != from_mode) + from = convert_to_mode (full_mode, from, unsignedp); + emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode), + to, from, UNKNOWN); + return; + } + /* else proceed to integer conversions below */ } if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT) { rtx new_from; enum machine_mode full_mode = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT); + convert_optab ctab = unsignedp ? zext_optab : sext_optab; + enum insn_code icode; - gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode) - != CODE_FOR_nothing); + icode = convert_optab_handler (ctab, full_mode, from_mode); + gcc_assert (icode != CODE_FOR_nothing); if (to_mode == full_mode) { - emit_unop_insn (convert_optab_handler (sext_optab, full_mode, - from_mode), - to, from, UNKNOWN); + emit_unop_insn (icode, to, from, UNKNOWN); return; } new_from = gen_reg_rtx (full_mode); - emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode), - new_from, from, UNKNOWN); + emit_unop_insn (icode, new_from, from, UNKNOWN); /* else proceed to integer conversions below. */ from_mode = full_mode; @@ -868,8 +878,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, unsigned int align, int endp) { struct move_by_pieces_d data; - enum machine_mode to_addr_mode, from_addr_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (from)); + enum machine_mode to_addr_mode; + enum machine_mode from_addr_mode = MEM_ADDRESS_MODE (from); rtx to_addr, from_addr = XEXP (from, 0); unsigned int max_size = MOVE_MAX_PIECES + 1; enum insn_code icode; @@ -880,7 +890,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, data.from_addr = from_addr; if (to) { - to_addr_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to)); + to_addr_mode = MEM_ADDRESS_MODE (to); to_addr = XEXP (to, 0); data.to = to; data.autinc_to @@ -932,7 +942,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, data.autinc_from = 1; data.explicit_inc_from = -1; } - if (USE_LOAD_POST_INCREMENT (mode) && ! data.autinc_from) + if (USE_LOAD_POST_INCREMENT (mode) && ! data.reverse && ! data.autinc_from) { data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr); data.autinc_from = 1; @@ -1434,10 +1444,8 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, unsigned int align ATTRIBUTE_UNUSED) { rtx cmp_label, top_label, iter, x_addr, y_addr, tmp; - enum machine_mode x_addr_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); - enum machine_mode y_addr_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (y)); + enum machine_mode x_addr_mode = MEM_ADDRESS_MODE (x); + enum machine_mode y_addr_mode = MEM_ADDRESS_MODE (y); enum machine_mode iter_mode; iter_mode = GET_MODE (size); @@ -2444,8 +2452,7 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len, rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode), void *constfundata, unsigned int align, bool memsetp, int endp) { - enum machine_mode to_addr_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to)); + enum machine_mode to_addr_mode = MEM_ADDRESS_MODE (to); struct store_by_pieces_d data; if (len == 0) @@ -2530,8 +2537,7 @@ static void store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, unsigned int align ATTRIBUTE_UNUSED) { - enum machine_mode to_addr_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (data->to)); + enum machine_mode to_addr_mode = MEM_ADDRESS_MODE (data->to); rtx to_addr = XEXP (data->to, 0); unsigned int max_size = STORE_MAX_PIECES + 1; enum insn_code icode; @@ -4598,19 +4604,21 @@ expand_assignment (tree to, tree from, bool nontemporal) && ((icode = optab_handler (movmisalign_optab, mode)) != CODE_FOR_nothing)) { - addr_space_t as - = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0)))); + tree to_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))); + addr_space_t as = TYPE_ADDR_SPACE (to_type); struct expand_operand ops[2]; + enum machine_mode pointer_mode; enum machine_mode address_mode; rtx reg, op0, mem; reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL); reg = force_not_mem (reg); + pointer_mode = targetm.type_pointer_mode (to_type); + address_mode = targetm.type_address_mode (to_type); if (TREE_CODE (to) == MEM_REF) { tree base = TREE_OPERAND (to, 0); - address_mode = targetm.addr_space.address_mode (as); op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL); op0 = convert_memory_address_addr_space (address_mode, op0, as); if (!integer_zerop (TREE_OPERAND (to, 1))) @@ -4619,23 +4627,20 @@ expand_assignment (tree to, tree from, bool nontemporal) = immed_double_int_const (mem_ref_offset (to), address_mode); op0 = simplify_gen_binary (PLUS, address_mode, op0, off); } - op0 = memory_address_addr_space (mode, op0, as); - mem = gen_rtx_MEM (mode, op0); - set_mem_attributes (mem, to, 0); - set_mem_addr_space (mem, as); } else if (TREE_CODE (to) == TARGET_MEM_REF) { struct mem_address addr; get_address_description (to, &addr); op0 = addr_for_mem_ref (&addr, as, true); - op0 = memory_address_addr_space (mode, op0, as); - mem = gen_rtx_MEM (mode, op0); - set_mem_attributes (mem, to, 0); - set_mem_addr_space (mem, as); } else gcc_unreachable (); + op0 = memory_address_addr_space (mode, op0, as); + mem = gen_rtx_MEM (mode, op0); + set_mem_attributes (mem, to, 0); + set_mem_addr_space (mem, as); + set_mem_pointer_address_modes (mem, pointer_mode, address_mode); if (TREE_THIS_VOLATILE (to)) MEM_VOLATILE_P (mem) = 1; @@ -4687,17 +4692,19 @@ expand_assignment (tree to, tree from, bool nontemporal) && ((icode = optab_handler (movmisalign_optab, mode)) != CODE_FOR_nothing)) { + enum machine_mode pointer_mode; enum machine_mode address_mode; rtx op0; struct expand_operand ops[2]; - addr_space_t as = TYPE_ADDR_SPACE - (TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0)))); tree base = TREE_OPERAND (tem, 0); + tree to_type = TREE_TYPE (TREE_TYPE (base)); + addr_space_t as = TYPE_ADDR_SPACE (to_type); misalignp = true; to_rtx = gen_reg_rtx (mode); - address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.type_pointer_mode (to_type); + address_mode = targetm.type_address_mode (to_type); op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL); op0 = convert_memory_address_addr_space (address_mode, op0, as); if (!integer_zerop (TREE_OPERAND (tem, 1))) @@ -4710,6 +4717,7 @@ expand_assignment (tree to, tree from, bool nontemporal) mem = gen_rtx_MEM (mode, op0); set_mem_attributes (mem, tem, 0); set_mem_addr_space (mem, as); + set_mem_pointer_address_modes (mem, pointer_mode, address_mode); if (TREE_THIS_VOLATILE (tem)) MEM_VOLATILE_P (mem) = 1; @@ -4759,8 +4767,7 @@ expand_assignment (tree to, tree from, bool nontemporal) } offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); - address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx)); + address_mode = MEM_ADDRESS_MODE (to_rtx); if (GET_MODE (offset_rtx) != address_mode) offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); @@ -5297,10 +5304,8 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); else { - enum machine_mode pointer_mode - = targetm.addr_space.pointer_mode (MEM_ADDR_SPACE (target)); - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (target)); + enum machine_mode pointer_mode = MEM_POINTER_MODE (target); + enum machine_mode address_mode = MEM_ADDRESS_MODE (target); /* Compute the size of the data to copy from the string. */ tree copy_size @@ -5866,8 +5871,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) offset_rtx = expand_normal (offset); gcc_assert (MEM_P (to_rtx)); - address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx)); + address_mode = MEM_ADDRESS_MODE (to_rtx); if (GET_MODE (offset_rtx) != address_mode) offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); @@ -5893,8 +5897,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (TYPE_PRECISION (type) < BITS_PER_WORD) { - type = lang_hooks.types.type_for_size - (BITS_PER_WORD, TYPE_UNSIGNED (type)); + type = lang_hooks.types.type_for_mode + (word_mode, TYPE_UNSIGNED (type)); value = fold_convert (type, value); } @@ -6435,6 +6439,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, { tree type = TREE_TYPE (exp); if (INTEGRAL_TYPE_P (type) + /* TODO: GET_MODE_PRECISION? */ && TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type)) && bitsize == TYPE_PRECISION (type)) { @@ -7623,9 +7628,10 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, if (POINTER_TYPE_P (TREE_TYPE (exp))) { - as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); - address_mode = targetm.addr_space.address_mode (as); - pointer_mode = targetm.addr_space.pointer_mode (as); + tree to_type = TREE_TYPE (TREE_TYPE (exp)); + as = TYPE_ADDR_SPACE (to_type); + address_mode = targetm.type_address_mode (to_type); + pointer_mode = targetm.type_pointer_mode (to_type); } /* We can get called with some Weird Things if the user does silliness @@ -9352,18 +9358,23 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case TARGET_MEM_REF: { - addr_space_t as - = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))); + tree to_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))); + addr_space_t as = TYPE_ADDR_SPACE (to_type); + enum machine_mode pointer_mode; + enum machine_mode address_mode; struct mem_address addr; enum insn_code icode; unsigned int align; + pointer_mode = targetm.type_pointer_mode (to_type); + address_mode = targetm.type_address_mode (to_type); get_address_description (exp, &addr); op0 = addr_for_mem_ref (&addr, as, true); op0 = memory_address_addr_space (mode, op0, as); temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); set_mem_addr_space (temp, as); + set_mem_pointer_address_modes (temp, pointer_mode, address_mode); align = get_object_or_type_alignment (exp); if (mode != BLKmode && align < GET_MODE_ALIGNMENT (mode) @@ -9387,10 +9398,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case MEM_REF: { - addr_space_t as - = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))); - enum machine_mode address_mode; tree base = TREE_OPERAND (exp, 0); + tree to_type = TREE_TYPE (TREE_TYPE (base)); + addr_space_t as = TYPE_ADDR_SPACE (to_type); + enum machine_mode pointer_mode; + enum machine_mode address_mode; gimple def_stmt; enum insn_code icode; unsigned align; @@ -9429,7 +9441,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, bit_offset), target, tmode, modifier); } - address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.type_pointer_mode (to_type); + address_mode = targetm.type_address_mode (to_type); base = TREE_OPERAND (exp, 0); if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR))) { @@ -9451,6 +9464,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); set_mem_addr_space (temp, as); + set_mem_pointer_address_modes (temp, pointer_mode, address_mode); if (TREE_THIS_VOLATILE (exp)) MEM_VOLATILE_P (temp) = 1; if (mode != BLKmode @@ -9780,8 +9794,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, gcc_assert (MEM_P (op0)); - address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (op0)); + address_mode = MEM_ADDRESS_MODE (op0); if (GET_MODE (offset_rtx) != address_mode) offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); @@ -10726,7 +10739,6 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range, { struct expand_operand ops[5]; enum machine_mode index_mode = SImode; - int index_bits = GET_MODE_BITSIZE (index_mode); rtx op1, op2, index; if (! HAVE_casesi) @@ -10753,7 +10765,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range, { if (TYPE_MODE (index_type) != index_mode) { - index_type = lang_hooks.types.type_for_size (index_bits, 0); + index_type = lang_hooks.types.type_for_mode (index_mode, 0); index_expr = fold_convert (index_type, index_expr); } diff --git gcc-4.7.0.orig/gcc/fold-const.c gcc-4.7.0/gcc/fold-const.c index 6492f11..e3c604c 100644 --- gcc-4.7.0.orig/gcc/fold-const.c +++ gcc-4.7.0/gcc/fold-const.c @@ -7831,7 +7831,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) && inter_prec >= inside_prec && (inter_float || inter_vec || inter_unsignedp == inside_unsignedp) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type)) && ! final_ptr && (! final_vec || inter_prec == inside_prec)) @@ -7865,7 +7865,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) == (final_unsignedp && final_prec > inter_prec)) && ! (inside_ptr && inter_prec != final_prec) && ! (final_ptr && inside_prec != inter_prec) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type))) return fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 0)); } diff --git gcc-4.7.0.orig/gcc/gcc.c gcc-4.7.0/gcc/gcc.c index cc6a08e..3ccadee 100644 --- gcc-4.7.0.orig/gcc/gcc.c +++ gcc-4.7.0/gcc/gcc.c @@ -260,6 +260,7 @@ static const char *replace_outfile_spec_function (int, const char **); static const char *remove_outfile_spec_function (int, const char **); static const char *version_compare_spec_function (int, const char **); static const char *include_spec_function (int, const char **); +static const char *include_noerr_spec_function (int, const char **); static const char *find_file_spec_function (int, const char **); static const char *find_plugindir_spec_function (int, const char **); static const char *print_asm_header_spec_function (int, const char **); @@ -1253,6 +1254,7 @@ static const struct spec_function static_spec_functions[] = { "remove-outfile", remove_outfile_spec_function }, { "version-compare", version_compare_spec_function }, { "include", include_spec_function }, + { "include-noerr", include_noerr_spec_function }, { "find-file", find_file_spec_function }, { "find-plugindir", find_plugindir_spec_function }, { "print-asm-header", print_asm_header_spec_function }, @@ -8048,6 +8050,29 @@ include_spec_function (int argc, const char **argv) return NULL; } +/* %:include_noerr builtin spec function. This differs from + %include_noerr in that it can be nested inside a spec, and thus be + %conditionalized or referenced in DRIVER_SELF_SPECS. It takes one + %argument, the filename, and looks for it in the startfile path. + %The result is always NULL, i.e. an empty expansion. */ + +static const char * +include_noerr_spec_function (int argc, const char **argv) +{ + char *file; + + if (argc != 1) + abort (); + + file = find_a_file (&startfile_prefixes, argv[0], R_OK, true); + if (file) + read_specs (file, FALSE); + else if (verbose_flag) + fnotice (stderr, "could not find specs file %s\n", argv[0]); + + return NULL; +} + /* %:find-file spec function. This function replaces its argument by the file found thru find_file, that is the -print-file-name gcc program option. */ diff --git gcc-4.7.0.orig/gcc/genmodes.c gcc-4.7.0/gcc/genmodes.c index 8b6f5bc..7d87608 100644 --- gcc-4.7.0.orig/gcc/genmodes.c +++ gcc-4.7.0/gcc/genmodes.c @@ -360,7 +360,6 @@ complete_mode (struct mode_data *m) m->bytesize = m->component->bytesize; m->ncomponents = 1; - m->component = 0; /* ??? preserve this */ break; case MODE_COMPLEX_INT: @@ -823,7 +822,13 @@ calc_wider_mode (void) sortbuf[i] = 0; for (j = 0; j < i; j++) - sortbuf[j]->next = sortbuf[j]->wider = sortbuf[j + 1]; + { + sortbuf[j]->next = sortbuf[j + 1]; + if (c == MODE_PARTIAL_INT) + sortbuf[j]->wider = sortbuf[j]->component; + else + sortbuf[j]->wider = sortbuf[j]->next; + } modes[c] = sortbuf[0]; } @@ -1120,7 +1125,8 @@ emit_mode_inner (void) for_all_modes (c, m) tagged_printf ("%smode", - m->component ? m->component->name : void_mode->name, + c != MODE_PARTIAL_INT && m->component + ? m->component->name : void_mode->name, m->name); print_closer (); diff --git gcc-4.7.0.orig/gcc/hooks.c gcc-4.7.0/gcc/hooks.c index ae59c33..eea685c 100644 --- gcc-4.7.0.orig/gcc/hooks.c +++ gcc-4.7.0/gcc/hooks.c @@ -71,6 +71,14 @@ bool hook_bool_const_int_const_int_true (const int a ATTRIBUTE_UNUSED, return true; } +bool +hook_bool_constcharptr_constcharptr_tree_false (const char * s0 ATTRIBUTE_UNUSED, + const char * s1 ATTRIBUTE_UNUSED, + tree t ATTRIBUTE_UNUSED) +{ + return false; +} + /* Generic hook that takes (enum machine_mode) and returns false. */ bool hook_bool_mode_false (enum machine_mode mode ATTRIBUTE_UNUSED) @@ -169,6 +177,12 @@ default_can_output_mi_thunk_no_vcall (const_tree a ATTRIBUTE_UNUSED, } int +hook_int_void_0 (void) +{ + return 0; +} + +int hook_int_uint_mode_1 (unsigned int a ATTRIBUTE_UNUSED, enum machine_mode b ATTRIBUTE_UNUSED) { @@ -329,6 +343,13 @@ hook_constcharptr_const_tree_null (const_tree t ATTRIBUTE_UNUSED) } tree +hook_tree_int_tree_null (int i ATTRIBUTE_UNUSED, + tree t ATTRIBUTE_UNUSED) +{ + return NULL; +} + +tree hook_tree_tree_int_treep_bool_null (tree t0 ATTRIBUTE_UNUSED, int i ATTRIBUTE_UNUSED, tree *p ATTRIBUTE_UNUSED, @@ -351,6 +372,13 @@ hook_tree_tree_tree_tree_null (tree t0 ATTRIBUTE_UNUSED, return NULL; } +tree +hook_tree_uint_int_null (unsigned int u ATTRIBUTE_UNUSED, + int i ATTRIBUTE_UNUSED) +{ + return NULL; +} + /* Generic hook that takes a rtx and returns a NULL string. */ const char * hook_constcharptr_const_rtx_null (const_rtx r ATTRIBUTE_UNUSED) @@ -380,6 +408,13 @@ hook_constcharptr_int_const_tree_const_tree_null (int i ATTRIBUTE_UNUSED, return NULL; } +/* Generic hook that returns a NULL_TREE */ +tree +hook_tree_void_null (void) +{ + return NULL; +} + /* Generic hook that takes a const_tree and returns NULL_TREE. */ tree hook_tree_const_tree_null (const_tree t ATTRIBUTE_UNUSED) diff --git gcc-4.7.0.orig/gcc/hooks.h gcc-4.7.0/gcc/hooks.h index 2e10d1f..2b561a8 100644 --- gcc-4.7.0.orig/gcc/hooks.h +++ gcc-4.7.0/gcc/hooks.h @@ -30,6 +30,7 @@ extern bool hook_bool_void_true (void); extern bool hook_bool_bool_false (bool); extern bool hook_bool_bool_gcc_optionsp_false (bool, struct gcc_options *); extern bool hook_bool_const_int_const_int_true (const int, const int); +extern bool hook_bool_constcharptr_constcharptr_tree_false (const char *, const char *, tree); extern bool hook_bool_mode_false (enum machine_mode); extern bool hook_bool_mode_true (enum machine_mode); extern bool hook_bool_mode_const_rtx_false (enum machine_mode, const_rtx); @@ -69,19 +70,26 @@ extern void hook_void_tree_treeptr (tree, tree *); extern void hook_void_int_int (int, int); extern void hook_void_gcc_optionsp (struct gcc_options *); +extern int hook_int_void_0 (void); extern int hook_int_uint_mode_1 (unsigned int, enum machine_mode); extern int hook_int_const_tree_0 (const_tree); extern int hook_int_const_tree_const_tree_1 (const_tree, const_tree); extern int hook_int_rtx_0 (rtx); extern int hook_int_rtx_bool_0 (rtx, bool); +extern tree hook_tree_void_null (void); + extern tree hook_tree_const_tree_null (const_tree); +extern tree hook_tree_int_tree_null (int, tree); + extern tree hook_tree_tree_tree_null (tree, tree); extern tree hook_tree_tree_tree_tree_null (tree, tree, tree); extern tree hook_tree_tree_tree_tree_3rd_identity (tree, tree, tree); extern tree hook_tree_tree_int_treep_bool_null (tree, int, tree *, bool); +extern tree hook_tree_uint_int_null (unsigned int, int); + extern unsigned hook_uint_void_0 (void); extern bool default_can_output_mi_thunk_no_vcall (const_tree, HOST_WIDE_INT, diff --git gcc-4.7.0.orig/gcc/ifcvt.c gcc-4.7.0/gcc/ifcvt.c index e4e13ab..804ebb5 100644 --- gcc-4.7.0.orig/gcc/ifcvt.c +++ gcc-4.7.0/gcc/ifcvt.c @@ -1520,8 +1520,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info) && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b) && if_info->branch_cost >= 5) { - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (a)); + enum machine_mode address_mode = MEM_ADDRESS_MODE (a); a = XEXP (a, 0); b = XEXP (b, 0); @@ -1673,7 +1672,11 @@ noce_try_cmove_arith (struct noce_if_info *if_info) MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b))); gcc_assert (MEM_ADDR_SPACE (if_info->a) == MEM_ADDR_SPACE (if_info->b)); + gcc_assert (MEM_POINTER_MODE (if_info->a) == MEM_POINTER_MODE (if_info->b)); + gcc_assert (MEM_ADDRESS_MODE (if_info->a) == MEM_ADDRESS_MODE (if_info->b)); set_mem_addr_space (tmp, MEM_ADDR_SPACE (if_info->a)); + set_mem_pointer_address_modes (tmp, MEM_POINTER_MODE (if_info->a), + MEM_ADDRESS_MODE (if_info->a)); noce_emit_move_insn (if_info->x, tmp); } diff --git gcc-4.7.0.orig/gcc/ira-lives.c gcc-4.7.0/gcc/ira-lives.c index f639e12..f48d7d2 100644 --- gcc-4.7.0.orig/gcc/ira-lives.c +++ gcc-4.7.0/gcc/ira-lives.c @@ -956,16 +956,14 @@ process_single_reg_class_operands (bool in_p, int freq) if (! in_p && recog_data.operand_type[i] != OP_OUT && recog_data.operand_type[i] != OP_INOUT) continue; - cl = single_reg_operand_class (i); - if (cl == NO_REGS) - continue; operand_a = NULL; if (GET_CODE (operand) == SUBREG) operand = SUBREG_REG (operand); - if (REG_P (operand) + cl = single_reg_operand_class (i); + if (cl != NO_REGS && REG_P (operand) && (regno = REGNO (operand)) >= FIRST_PSEUDO_REGISTER) { enum reg_class aclass; @@ -1015,13 +1013,30 @@ process_single_reg_class_operands (bool in_p, int freq) a = OBJECT_ALLOCNO (obj); if (a != operand_a) { - /* We could increase costs of A instead of making it - conflicting with the hard register. But it works worse - because it will be spilled in reload in anyway. */ - IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), - reg_class_contents[cl]); - IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), - reg_class_contents[cl]); + if (cl != NO_REGS) + { + /* We could increase costs of A instead of making it + conflicting with the hard register. But it works worse + because it will be spilled in reload in anyway. */ + IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), + reg_class_contents[cl]); + IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), + reg_class_contents[cl]); + } + else if (REG_P (operand) + && (regno = REGNO (operand)) < FIRST_PSEUDO_REGISTER) + { + int nregs = hard_regno_nregs[regno][GET_MODE (operand)]; + int r; + + for (r = 0; r < nregs; ++r) + { + SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), + regno+r); + SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), + regno+r); + } + } } } } diff --git gcc-4.7.0.orig/gcc/machmode.h gcc-4.7.0/gcc/machmode.h index 4a3f6f5..6137c70 100644 --- gcc-4.7.0.orig/gcc/machmode.h +++ gcc-4.7.0/gcc/machmode.h @@ -166,6 +166,7 @@ extern const unsigned char mode_class[NUM_MACHINE_MODES]; /* Nonzero if CLASS modes can be widened. */ #define CLASS_HAS_WIDER_MODES_P(CLASS) \ (CLASS == MODE_INT \ + || CLASS == MODE_PARTIAL_INT \ || CLASS == MODE_FLOAT \ || CLASS == MODE_DECIMAL_FLOAT \ || CLASS == MODE_COMPLEX_FLOAT \ diff --git gcc-4.7.0.orig/gcc/optabs.c gcc-4.7.0/gcc/optabs.c index fd353d7..561d2ca0 100644 --- gcc-4.7.0.orig/gcc/optabs.c +++ gcc-4.7.0/gcc/optabs.c @@ -8183,7 +8183,7 @@ maybe_legitimize_operand_same_code (enum insn_code icode, unsigned int opno, enum machine_mode mode; last = get_last_insn (); - mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); + mode = MEM_ADDRESS_MODE (mem); mem = replace_equiv_address (mem, copy_to_mode_reg (mode, addr)); if (insn_operand_matches (icode, opno, mem)) { diff --git gcc-4.7.0.orig/gcc/output.h gcc-4.7.0/gcc/output.h index bc8c9d9..19989e8 100644 --- gcc-4.7.0.orig/gcc/output.h +++ gcc-4.7.0/gcc/output.h @@ -591,7 +591,6 @@ extern section *get_unnamed_section (unsigned int, void (*) (const void *), const void *); extern section *get_section (const char *, unsigned int, tree); extern section *get_named_section (tree, const char *, int); -extern section *get_variable_section (tree, bool); extern void place_block_symbol (rtx); extern rtx get_section_anchor (struct object_block *, HOST_WIDE_INT, enum tls_model); diff --git gcc-4.7.0.orig/gcc/reload.c gcc-4.7.0/gcc/reload.c index 8420c80..d272eeb 100644 --- gcc-4.7.0.orig/gcc/reload.c +++ gcc-4.7.0/gcc/reload.c @@ -3982,7 +3982,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, enum machine_mode address_mode; address_mode = GET_MODE (XEXP (recog_data.operand[i], 0)); if (address_mode == VOIDmode) - address_mode = targetm.addr_space.address_mode (as); + address_mode = MEM_ADDRESS_MODE (recog_data.operand[i]); operand_reloadnum[i] = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX, diff --git gcc-4.7.0.orig/gcc/rtl.h gcc-4.7.0/gcc/rtl.h index b1b681b..5f610ba 100644 --- gcc-4.7.0.orig/gcc/rtl.h +++ gcc-4.7.0/gcc/rtl.h @@ -163,6 +163,12 @@ typedef struct GTY(()) mem_attrs /* The address space that the memory reference uses. */ unsigned char addrspace; + /* The machine mode used for pointers to this memory. */ + enum machine_mode pointer_mode; + + /* The machine mode used for addresses of this memory. */ + enum machine_mode address_mode; + /* True if OFFSET is known. */ bool offset_known_p; @@ -1368,6 +1374,12 @@ do { \ /* For a MEM rtx, the address space. */ #define MEM_ADDR_SPACE(RTX) (get_mem_attrs (RTX)->addrspace) +/* For a MEM rtx, the mode used for pointers to MEM. */ +#define MEM_POINTER_MODE(RTX) (get_mem_attrs (RTX)->pointer_mode) + +/* For a MEM rtx, the mode used for addresses of MEM. */ +#define MEM_ADDRESS_MODE(RTX) (get_mem_attrs (RTX)->address_mode) + /* For a MEM rtx, true if its MEM_SIZE is known. */ #define MEM_SIZE_KNOWN_P(RTX) (get_mem_attrs (RTX)->size_known_p) diff --git gcc-4.7.0.orig/gcc/rtlanal.c gcc-4.7.0/gcc/rtlanal.c index 7c4a49b..f13fcb4 100644 --- gcc-4.7.0.orig/gcc/rtlanal.c +++ gcc-4.7.0/gcc/rtlanal.c @@ -3965,7 +3965,7 @@ nonzero_bits1 (const_rtx x, enum machine_mode mode, const_rtx known_x, /* As we do not know which address space the pointer is refering to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ - if (target_default_pointer_address_modes_p () + if (targetm.default_pointer_address_modes_p () && POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && REG_POINTER (x)) nonzero &= GET_MODE_MASK (ptr_mode); @@ -4475,7 +4475,7 @@ num_sign_bit_copies1 (const_rtx x, enum machine_mode mode, const_rtx known_x, /* As we do not know which address space the pointer is refering to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ - if (target_default_pointer_address_modes_p () + if (targetm.default_pointer_address_modes_p () && ! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode && REG_POINTER (x)) return GET_MODE_PRECISION (Pmode) - GET_MODE_PRECISION (ptr_mode) + 1; diff --git gcc-4.7.0.orig/gcc/sched-deps.c gcc-4.7.0/gcc/sched-deps.c index 33a6996..719b97d 100644 --- gcc-4.7.0.orig/gcc/sched-deps.c +++ gcc-4.7.0/gcc/sched-deps.c @@ -2444,8 +2444,7 @@ sched_analyze_1 (struct deps_desc *deps, rtx x, rtx insn) if (sched_deps_info->use_cselib) { - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest)); + enum machine_mode address_mode = MEM_ADDRESS_MODE (dest); t = shallow_copy_rtx (dest); cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, @@ -2606,8 +2605,7 @@ sched_analyze_2 (struct deps_desc *deps, rtx x, rtx insn) if (sched_deps_info->use_cselib) { - enum machine_mode address_mode - = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t)); + enum machine_mode address_mode = MEM_ADDRESS_MODE (t); t = shallow_copy_rtx (t); cselib_lookup_from_insn (XEXP (t, 0), address_mode, 1, diff --git gcc-4.7.0.orig/gcc/sel-sched-dump.c gcc-4.7.0/gcc/sel-sched-dump.c index 27b06ad..61add16 100644 --- gcc-4.7.0.orig/gcc/sel-sched-dump.c +++ gcc-4.7.0/gcc/sel-sched-dump.c @@ -957,7 +957,7 @@ debug_mem_addr_value (rtx x) enum machine_mode address_mode; gcc_assert (MEM_P (x)); - address_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + address_mode = MEM_ADDRESS_MODE (x); t = shallow_copy_rtx (x); if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t))) diff --git gcc-4.7.0.orig/gcc/simplify-rtx.c gcc-4.7.0/gcc/simplify-rtx.c index bba565d..c3f1898 100644 --- gcc-4.7.0.orig/gcc/simplify-rtx.c +++ gcc-4.7.0/gcc/simplify-rtx.c @@ -1142,7 +1142,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) /* As we do not know which address space the pointer is refering to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ - if (target_default_pointer_address_modes_p () + if (targetm.default_pointer_address_modes_p () && ! POINTERS_EXTEND_UNSIGNED && mode == Pmode && GET_MODE (op) == ptr_mode && (CONSTANT_P (op) @@ -1235,7 +1235,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) /* As we do not know which address space the pointer is refering to, we can do this only if the target does not support different pointer or address modes depending on the address space. */ - if (target_default_pointer_address_modes_p () + if (targetm.default_pointer_address_modes_p () && POINTERS_EXTEND_UNSIGNED > 0 && mode == Pmode && GET_MODE (op) == ptr_mode && (CONSTANT_P (op) diff --git gcc-4.7.0.orig/gcc/stor-layout.c gcc-4.7.0/gcc/stor-layout.c index a1ac000..e0da46a 100644 --- gcc-4.7.0.orig/gcc/stor-layout.c +++ gcc-4.7.0/gcc/stor-layout.c @@ -375,6 +375,13 @@ smallest_mode_for_size (unsigned int size, enum mode_class mclass) { enum machine_mode mode; + /* Prefer exact matches in MODE_PARTIAL_INT if looking in MODE_INT */ + if (mclass == MODE_INT) + for (mode = GET_CLASS_NARROWEST_MODE (MODE_PARTIAL_INT); + mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) + if (GET_MODE_PRECISION (mode) == size) + return mode; + /* Get the first mode which has at least this size, in the specified class. */ for (mode = GET_CLASS_NARROWEST_MODE (mclass); mode != VOIDmode; @@ -1927,15 +1934,12 @@ layout_type (tree type) { enum machine_mode mode = TYPE_MODE (type); if (TREE_CODE (type) == REFERENCE_TYPE && reference_types_internal) - { - addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); - mode = targetm.addr_space.address_mode (as); - } + mode = targetm.type_address_mode (TREE_TYPE (type)); TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (mode)); TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (mode)); TYPE_UNSIGNED (type) = 1; - TYPE_PRECISION (type) = GET_MODE_BITSIZE (mode); + TYPE_PRECISION (type) = GET_MODE_PRECISION (mode); } break; @@ -2198,16 +2202,20 @@ initialize_sizetypes (void) int precision, bprecision; /* Get sizetypes precision from the SIZE_TYPE target macro. */ - if (strcmp (SIZE_TYPE, "unsigned int") == 0) - precision = INT_TYPE_SIZE; - else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) - precision = LONG_TYPE_SIZE; - else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) - precision = LONG_LONG_TYPE_SIZE; - else if (strcmp (SIZE_TYPE, "short unsigned int") == 0) - precision = SHORT_TYPE_SIZE; - else - gcc_unreachable (); + precision = targetm.size_type_precision(); + if (!precision) + { + if (strcmp (SIZE_TYPE, "unsigned int") == 0) + precision = INT_TYPE_SIZE; + else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) + precision = LONG_TYPE_SIZE; + else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) + precision = LONG_LONG_TYPE_SIZE; + else if (strcmp (SIZE_TYPE, "short unsigned int") == 0) + precision = SHORT_TYPE_SIZE; + else + gcc_unreachable (); + } bprecision = MIN (precision + BITS_PER_UNIT_LOG + 1, MAX_FIXED_MODE_SIZE); @@ -2464,7 +2472,7 @@ get_mode_bounds (enum machine_mode mode, int sign, enum machine_mode target_mode, rtx *mmin, rtx *mmax) { - unsigned size = GET_MODE_BITSIZE (mode); + unsigned size = GET_MODE_PRECISION (mode); unsigned HOST_WIDE_INT min_val, max_val; gcc_assert (size <= HOST_BITS_PER_WIDE_INT); diff --git gcc-4.7.0.orig/gcc/target.def gcc-4.7.0/gcc/target.def index 6084b21..d7a6798 100644 --- gcc-4.7.0.orig/gcc/target.def +++ gcc-4.7.0/gcc/target.def @@ -229,6 +229,15 @@ DEFHOOK void, (const char *name, unsigned int flags, tree decl), default_no_named_section) +/* Return preferred (sub)section for variable DECL. + Main purpose of this function is allow target to actually control + the section, which TARGET_ASM_SELECT_SECTION does not. */ +DEFHOOK +(variable_section, + "", + section *, (tree decl, bool prefer_noswitch_p), + default_variable_section) + /* Return preferred text (sub)section for function DECL. Main purpose of this function is to separate cold, normal and hot functions. STARTUP is true when function is known to be used only @@ -305,6 +314,13 @@ section names for mergeable constant data. Define this macro to override\n\ the string if a different section name should be used.", const char *, ".rodata") +/* Return the mergeable_rodata_prefix to use for DECL. */ +DEFHOOK +(decl_mergeable_rodata_prefix, + "", + const char *, (tree decl), + default_decl_mergeable_rodata_prefix) + /* Return the section to be used for transactional memory clone tables. */ DEFHOOK (tm_clone_table_section, @@ -1095,6 +1111,58 @@ DEFHOOK enum machine_mode, (void), default_unwind_word_mode) +/* Tree nodes that might be referenced by things like, say, size_type */ +DEFHOOK +(build_common_tree_nodes, + "", + void, (void), + hook_void_void) + +/* Provide the precision to be used for size_type, when this is not + * a standard type. */ +DEFHOOK +(size_type_precision, + "", + int, (void), + hook_int_void_0) + +/* Provide the type node to be used for size_type, when this is not + * a standard type. */ +DEFHOOK +(size_type_tree, + "", + tree, (void), + hook_tree_void_null) + +/* Likewise for ptrdiff_type */ +DEFHOOK +(ptrdiff_type_tree, + "", + tree, (void), + hook_tree_void_null) + +/* Return target-specific type for size, overriding c_common */ +DEFHOOK +(c_common_type_for_size, + "", + tree, (unsigned int bits, int unsignedp), + hook_tree_uint_int_null) + +/* Return target-specific common type */ +DEFHOOK +(c_common_signed_or_unsigned_type, + "", + tree, (int unsignedp, tree type), + hook_tree_int_tree_null) + +/* Emit preprocessor definitions for min/max values for non-standard + * built-in types for size_type_node and ptrdiff_type_node. */ +DEFHOOK +(cpp_builtin_define_type_minmax, + "", + bool, (const char *min_macro, const char *max_macro, tree type), + hook_bool_constcharptr_constcharptr_tree_false) + /* Given two decls, merge their attributes and return the result. */ DEFHOOK (merge_decl_attributes, @@ -1534,6 +1602,47 @@ DEFHOOK bool, (struct ao_ref_s *ref), default_ref_may_alias_errno) +/* MODE to use for a pointer to a particular type */ +DEFHOOK +(type_pointer_mode, + "Define this to return the machine mode to use for pointers to\ + @var{to_type}. The default version of this hook defers to\ + @code{TARGET_ADDR_SPACE_POINTER_MODE}.", + enum machine_mode, (tree to_type), + default_type_pointer_mode) + +/* MODE to use for an address of a particular type */ +DEFHOOK +(type_address_mode, + "Define this to return the machine mode to use for addresses of\ + @var{to_type}. The default version of this hook defers to\ + @code{TARGET_ADDR_SPACE_ADDRESS_MODE}.", + enum machine_mode, (tree to_type), + default_type_address_mode) + +/* True if MODE is valid for a pointer in __attribute__((mode("MODE"))) + to a particular type. */ +DEFHOOK +(type_valid_pointer_mode, + "Define this to return nonzero if the port can handle pointers with machine\ + mode @var{mode} to @var{to_type}. This target hook is the same as the\ + @code{TARGET_VALID_POINTER_MODE} target hook, except that it considers the\ + type referenced. The default version of this hook extracts the\ + address space and uses @code{TARGET_ADDR_SPACE_VALID_POINTER_MODE}.", + bool, (enum machine_mode mode, tree to_type), + default_type_valid_pointer_mode) + +DEFHOOK +(default_pointer_address_modes_p, + "If a target implements @code{TARGET_TYPE_POINTER_MODE},\ + @code{TARGET_TYPE_ADDRESS_MODE}, @code{TARGET_ADDR_SPACE_POINTER_MODE}, or\ + @code{TARGET_ADDR_SPACE_ADDRESS_MODE}, define this to return true when the\ + pointer mode will always match @code{Pmode} and the address mode will\ + always match @code{ptr_mode}. If not defined, this will return false if\ + any of those hooks are defined.", + bool, (void), + default_default_pointer_address_modes_p) + /* Support for named address spaces. */ #undef HOOK_PREFIX #define HOOK_PREFIX "TARGET_ADDR_SPACE_" diff --git gcc-4.7.0.orig/gcc/target.h gcc-4.7.0/gcc/target.h index e3307e8..e9b9d2a 100644 --- gcc-4.7.0.orig/gcc/target.h +++ gcc-4.7.0/gcc/target.h @@ -84,12 +84,6 @@ typedef int (* print_switch_fn_type) (print_switch_type, const char *); /* An example implementation for ELF targets. Defined in varasm.c */ extern int elf_record_gcc_switches (print_switch_type type, const char *); -/* Some places still assume that all pointer or address modes are the - standard Pmode and ptr_mode. These optimizations become invalid if - the target actually supports multiple different modes. For now, - we disable such optimizations on such targets, using this function. */ -extern bool target_default_pointer_address_modes_p (void); - struct stdarg_info; struct spec_info_def; struct hard_reg_set_container; diff --git gcc-4.7.0.orig/gcc/targhooks.c gcc-4.7.0/gcc/targhooks.c index 8e3d74e..3fefb36 100644 --- gcc-4.7.0.orig/gcc/targhooks.c +++ gcc-4.7.0/gcc/targhooks.c @@ -1025,6 +1025,58 @@ default_ref_may_alias_errno (ao_ref *ref) return false; } +/* Return the mode for a pointer to a given type, defaulting to the + behavior of TARGET_ADDR_SPACE_POINTER_MODE. */ + +enum machine_mode +default_type_pointer_mode (tree to_type) +{ + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + return targetm.addr_space.pointer_mode (as); +} + +/* Return the mode for an address of a given type, defaulting to the + behavior of TARGET_ADDR_SPACE_ADDRESS_MODE. */ + +enum machine_mode +default_type_address_mode (tree to_type) +{ + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + return targetm.addr_space.address_mode (as); +} + +/* Type-inspecting version of valid_pointer_mode. */ + +bool +default_type_valid_pointer_mode (enum machine_mode mode, tree to_type) +{ + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + return targetm.addr_space.valid_pointer_mode (mode, as); +} + +/* Some places still assume that all pointer or address modes are the + standard Pmode and ptr_mode. These optimizations become invalid if + the target actually supports multiple different modes. Allow the + target to indicate whether it will do so. */ + +bool +default_default_pointer_address_modes_p (void) +{ + if (targetm.type_address_mode != default_type_address_mode) + return false; + if (targetm.type_pointer_mode != default_type_pointer_mode) + return false; + if (targetm.addr_space.address_mode != default_addr_space_address_mode) + return false; + if (targetm.addr_space.pointer_mode != default_addr_space_pointer_mode) + return false; + + return true; +} + /* Return the mode for a pointer to a given ADDRSPACE, defaulting to ptr_mode for the generic address space only. */ @@ -1057,21 +1109,6 @@ default_addr_space_valid_pointer_mode (enum machine_mode mode, addr_space_t as) return targetm.valid_pointer_mode (mode); } -/* Some places still assume that all pointer or address modes are the - standard Pmode and ptr_mode. These optimizations become invalid if - the target actually supports multiple different modes. For now, - we disable such optimizations on such targets, using this function. */ - -bool -target_default_pointer_address_modes_p (void) -{ - if (targetm.addr_space.address_mode != default_addr_space_address_mode) - return false; - if (targetm.addr_space.pointer_mode != default_addr_space_pointer_mode) - return false; - - return true; -} /* Named address space version of legitimate_address_p. */ diff --git gcc-4.7.0.orig/gcc/targhooks.h gcc-4.7.0/gcc/targhooks.h index 8618115..dface0c 100644 --- gcc-4.7.0.orig/gcc/targhooks.h +++ gcc-4.7.0/gcc/targhooks.h @@ -140,6 +140,10 @@ extern bool default_target_option_pragma_parse (tree, tree); extern bool default_target_can_inline_p (tree, tree); extern bool default_valid_pointer_mode (enum machine_mode); extern bool default_ref_may_alias_errno (struct ao_ref_s *); +extern enum machine_mode default_type_pointer_mode (tree); +extern enum machine_mode default_type_address_mode (tree); +extern bool default_type_valid_pointer_mode (enum machine_mode, tree); +extern bool default_default_pointer_address_modes_p (void); extern enum machine_mode default_addr_space_pointer_mode (addr_space_t); extern enum machine_mode default_addr_space_address_mode (addr_space_t); extern bool default_addr_space_valid_pointer_mode (enum machine_mode, @@ -172,8 +176,10 @@ extern int default_label_align_after_barrier_max_skip (rtx); extern int default_loop_align_max_skip (rtx); extern int default_label_align_max_skip (rtx); extern int default_jump_align_max_skip (rtx); +extern const char * default_decl_mergeable_rodata_prefix (tree); extern section * default_function_section(tree decl, enum node_frequency freq, bool startup, bool exit); +extern section *default_variable_section (tree, bool); extern enum machine_mode default_get_reg_raw_mode(int); extern void *default_get_pch_validity (size_t *); diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/bic_sr_irq.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/bic_sr_irq.c new file mode 100644 index 0000000..282fe08 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/bic_sr_irq.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern void * alloca (unsigned int); +extern unsigned int use_data (void *arg); +extern unsigned int sr_value; + +__attribute__ ((interrupt(1*2))) +void clear_sr () +{ + unsigned char data[14]; + unsigned int sr_local; + + /* The following are 4-byte instructions */ + /* { dg-final { scan-assembler "bic\[ \t\]#8, 22\\(r1\\)" } } */ + __bic_status_register_on_exit(8); + sr_local = use_data (data); + /* { dg-final { scan-assembler "bic\[ \t\]r15, 22\\(r1\\)" } } */ + __bic_status_register_on_exit(sr_local); + /* { dg-final { scan-assembler "bic\[ \t\]@r1, 22\\(r1\\)" } } */ + __bic_status_register_on_exit(*(unsigned int*)data); + + /* The following are 6-byte instructions */ + /* { dg-final { scan-assembler "bic\[ \t\]#9, 22\\(r1\\)" } } */ + __bic_status_register_on_exit(9); + /* { dg-final { scan-assembler "bic\[ \t\]&sr_value, 22\\(r1\\)" } } */ + __bic_status_register_on_exit(sr_value); + /* { dg-final { scan-assembler "bic\[ \t\]4\\(r1\\), 22\\(r1\\)" } } */ + __bic_status_register_on_exit(*(2 + (unsigned int*)data)); + +} + +__attribute__ ((interrupt(2*2))) +void alloca_sr (int len) +{ + char* locbuf; + + /* { dg-final { scan-assembler "bic\[ \t\]#1, @r4" } } */ + __bic_status_register_on_exit(1); + locbuf = alloca(len); + locbuf[0] = 'A'; + locbuf[1] = 0; + use_data(locbuf); + /* SF 3198920: This one gets stored in the wrong location, because + * r1 still has the locbuf allocation reflected in it. */ + /* { dg-final { scan-assembler "bic\[ \t\]#2, @r4" } } */ + __bic_status_register_on_exit(2); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/bis_sr_irq.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/bis_sr_irq.c new file mode 100644 index 0000000..56f9444 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/bis_sr_irq.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern void * alloca (unsigned int); +extern unsigned int use_data (unsigned char *arg); +extern unsigned int sr_value; + +__attribute__ ((interrupt(1*2))) +void set_sr () +{ + unsigned char data[14]; + unsigned int sr_local; + + /* The following are 4-byte instructions */ + /* { dg-final { scan-assembler "bis\[ \t\]#8, 22\\(r1\\)" } } */ + __bis_status_register_on_exit(8); + sr_local = use_data (data); + /* { dg-final { scan-assembler "bis\[ \t\]r15, 22\\(r1\\)" } } */ + __bis_status_register_on_exit(sr_local); + /* { dg-final { scan-assembler "bis\[ \t\]@r1, 22\\(r1\\)" } } */ + __bis_status_register_on_exit(*(unsigned int*)data); + + /* The following are 6-byte instructions */ + /* { dg-final { scan-assembler "bis\[ \t\]#9, 22\\(r1\\)" } } */ + __bis_status_register_on_exit(9); + /* { dg-final { scan-assembler "bis\[ \t\]&sr_value, 22\\(r1\\)" } } */ + __bis_status_register_on_exit(sr_value); + /* { dg-final { scan-assembler "bis\[ \t\]4\\(r1\\), 22\\(r1\\)" } } */ + __bis_status_register_on_exit(*(2 + (unsigned int*)data)); + +} + +__attribute__ ((interrupt(2*2))) +void alloca_sr (int len) +{ + char* locbuf; + + /* { dg-final { scan-assembler "bis\[ \t\]#1, @r4" } } */ + __bis_status_register_on_exit(1); + locbuf = alloca(len); + locbuf[0] = 'A'; + locbuf[1] = 0; + use_data(locbuf); + /* { dg-final { scan-assembler "bis\[ \t\]#2, @r4" } } */ + __bis_status_register_on_exit(2); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/bswap.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/bswap.c new file mode 100644 index 0000000..0db1432 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/bswap.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +unsigned int +bswaphi2 (unsigned int v) +{ + /* { dg-final { scan-assembler "\n\tmov.b\tr15, r15\n\tswpb\tr15\n\tret\n" } } */ + return v << 8; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtin_address.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtin_address.c new file mode 100644 index 0000000..9f92c77 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtin_address.c @@ -0,0 +1,82 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +#if LIVE_P1_ISR +#include +#define ISR_VECTOR PORT1_VECTOR +#else /* LIVE_P1_ISR */ +#define ISR_VECTOR 1*2 +extern volatile unsigned char P1IV; +#endif /* ISR_VECTOR */ + +extern void * alloca (unsigned int len); + +extern void reference (void* p); + +void fn () +{ + extern volatile void* ra_fn; + extern volatile void* fa_fn; + /* { dg-final { scan-assembler "mov\t@r4, &ra_fn *\n" } } */ + ra_fn = __builtin_return_address(0); + /* { dg-final { scan-assembler "mov\tr4, &fa_fn *\n" } } */ + fa_fn = __builtin_frame_address(0); +} + +void fnl () +{ + extern volatile void* ra_fnl; + extern volatile void* fa_fnl; + char data[4]; + reference(data); + /* { dg-final { scan-assembler "mov\t@r4, &ra_fnl *\n" } } */ + ra_fnl = __builtin_return_address(0); + /* { dg-final { scan-assembler "mov\tr4, &fa_fnl *\n" } } */ + fa_fnl = __builtin_frame_address(0); +} + +void fnd (int len) +{ + extern volatile void* ra_fnd; + extern volatile void* fa_fnd; + + char * data = alloca(len); + reference(data); + /* { dg-final { scan-assembler "mov\t@r4, &ra_fnd *\n" } } */ + ra_fnd = __builtin_return_address(0); + /* { dg-final { scan-assembler "mov\tr4, &fa_fnd *\n" } } */ + fa_fnd = __builtin_frame_address(0); +} + +void fnma (int zero, int one, int two, int three, int four, int five) +{ + extern volatile void* ra_fnma; + extern volatile void* fa_fnma; + + int data[6]; + data[0] = zero; + data[1] = one; + data[2] = two; + data[3] = three; + data[4] = four; + data[5] = five; + reference(data); + /* { dg-final { scan-assembler "mov\t@r4, &ra_fnma *\n" } } */ + ra_fnma = __builtin_return_address(0); + /* { dg-final { scan-assembler "mov\tr4, &fa_fnma *\n" } } */ + fa_fnma = __builtin_frame_address(0); +} + +__attribute__((interrupt(ISR_VECTOR))) +void isr () +{ + extern volatile void* ra_isr; + extern volatile void* fa_isr; + + /* Read the vector to clear the interrupt. */ + (void)P1IV; + /* { dg-final { scan-assembler "mov\t2\\(r4\\), &ra_isr *\n" } } */ + ra_isr = __builtin_return_address(0); + /* { dg-final { scan-assembler "mov\tr4, &fa_fnma *\n" } } */ + fa_isr = __builtin_frame_address(0); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_1.c new file mode 100644 index 0000000..757bdbf --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +void test () +{ + /* { dg-final { scan-assembler "dint\n\tnop\n\teint\n\tnop\n\tret" } } */ + __dint(); + __eint(); + __nop(); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_bic_sr.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_bic_sr.c new file mode 100644 index 0000000..ee1e6ab --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_bic_sr.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern volatile unsigned int read_sr; +extern unsigned int write_sr; +extern unsigned int *sr_ptr; + +void test () +{ + int i; + unsigned int sr; + + /* { dg-final { scan-assembler "bic\t&write_sr, r2\n" } } */ + __bic_status_register(write_sr); + /* { dg-final { scan-assembler "bic\t#4660, r2\n" } } */ + __bic_status_register(0x1234); + /* { dg-final { scan-assembler "bic\t#8, r2\n" } } */ + __bic_status_register(8); + /* { dg-final { scan-assembler "bic\tr15, r2\n" } } */ + __bic_status_register(read_sr & 0x42); + /* { dg-final { scan-assembler "bic\t@r15, r2\n" } } */ + __bic_status_register(*sr_ptr); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_bis_sr.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_bis_sr.c new file mode 100644 index 0000000..2f8d023 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_bis_sr.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern volatile unsigned int read_sr; +extern unsigned int write_sr; +extern unsigned int *sr_ptr; + +void test () +{ + int i; + unsigned int sr; + + /* { dg-final { scan-assembler "bis\t&write_sr, r2\n" } } */ + __bis_status_register(write_sr); + /* { dg-final { scan-assembler "bis\t#4660, r2\n" } } */ + __bis_status_register(0x1234); + /* { dg-final { scan-assembler "bis\t#8, r2\n" } } */ + __bis_status_register(8); + /* { dg-final { scan-assembler "bis\tr15, r2\n" } } */ + __bis_status_register(read_sr & 0x42); + /* { dg-final { scan-assembler "bis\t@r15, r2\n" } } */ + __bis_status_register(*sr_ptr); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_gsistate.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_gsistate.c new file mode 100644 index 0000000..1d611eb --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_gsistate.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +typedef unsigned int istate_t; +extern volatile istate_t sv ; +extern istate_t * volatile svp; + +void test () +{ + istate_t sv; + + /* { dg-final { scan-assembler "mov\tr2, r15\n" } } */ + sv = __get_interrupt_state(); + /* { dg-final { scan-assembler "mov\t\&svp, r14\n\tmov\tr2, @r14\n" } } */ + *svp = __get_interrupt_state(); + /* { dg-final { scan-assembler "mov\tr15, r2\n" } } */ + __set_interrupt_state(sv); + /* { dg-final { scan-assembler "mov\t@r15, r2\n" } } */ + __set_interrupt_state(*svp); + /* { dg-final { scan-assembler "mov\t#8, r2\n" } } */ + __set_interrupt_state(8); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_read_sr.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_read_sr.c new file mode 100644 index 0000000..f2683c1 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_read_sr.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned int read_sr; +extern unsigned int *sr_ptr; + +void test () +{ + int i; + unsigned int sr; + + /* { dg-final { scan-assembler "mov\tr2, r15\n" } } */ + sr = __read_status_register(); + /* { dg-final { scan-assembler "mov\tr2, \&read_sr\n" } } */ + read_sr = __read_status_register(); + /* { dg-final { scan-assembler "mov\tr2, @r15\n" } } */ + *sr_ptr = __read_status_register(); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_sp.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_sp.c new file mode 100644 index 0000000..12b54ac --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_sp.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern void * volatile read_sp; +extern void * write_sp; +extern void * * sp_ptr; + +void test () +{ + int i; + void * sp; + + /* { dg-final { scan-assembler "mov\tr1, r15\n" } } */ + sp = __read_stack_pointer(); + /* { dg-final { scan-assembler "mov\tr1, \&read_sp\n" } } */ + read_sp = __read_stack_pointer(); + /* { dg-final { scan-assembler "mov\tr1, @r15\n" } } */ + *sp_ptr = __read_stack_pointer(); + /* { dg-final { scan-assembler "mov\t&write_sp, r1\n" } } */ + __write_stack_pointer(write_sp); + /* { dg-final { scan-assembler "mov\t#4660, r1\n" } } */ + __write_stack_pointer((void *)0x1234); + /* { dg-final { scan-assembler "mov\t#8, r1\n" } } */ + __write_stack_pointer((void *)8); + /* { dg-final { scan-assembler "mov\tr15, r1\n" } } */ + __write_stack_pointer((void *)(0x42 & (unsigned int)read_sp)); + /* { dg-final { scan-assembler "mov\t@r15, r1\n" } } */ + __write_stack_pointer(*sp_ptr); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_swap_bytes.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_swap_bytes.c new file mode 100644 index 0000000..41f4858 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_swap_bytes.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +unsigned int vi; +unsigned int vx; +unsigned int vc; +unsigned int get_v (); + +void test () +{ + /* { dg-final { scan-assembler "mov\t#13330, \&vi\n" } } */ + vi = __swap_bytes(0x1234); + /* { dg-final { scan-assembler "swpb\t\&vx\n" } } */ + vx = __swap_bytes(vx); + /* { dg-final { scan-assembler "call\t#get_v\n\tswpb\tr15\n\tmov\tr15, \&vc\n" } } */ + vc = __swap_bytes(get_v()); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/builtins_write_sr.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_write_sr.c new file mode 100644 index 0000000..c891527 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/builtins_write_sr.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern volatile unsigned int read_sr; +extern unsigned int write_sr; +extern unsigned int *sr_ptr; + +void test () +{ + int i; + unsigned int sr; + + /* { dg-final { scan-assembler "mov\t&write_sr, r2\n" } } */ + __write_status_register(write_sr); + /* { dg-final { scan-assembler "mov\t#4660, r2\n" } } */ + __write_status_register(0x1234); + /* { dg-final { scan-assembler "mov\t#8, r2\n" } } */ + __write_status_register(8); + /* { dg-final { scan-assembler "mov\tr15, r2\n" } } */ + __write_status_register(read_sr & 0x42); + /* { dg-final { scan-assembler "mov\t@r15, r2\n" } } */ + __write_status_register(*sr_ptr); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/conflict_attribute.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/conflict_attribute.c new file mode 100644 index 0000000..7123e5e --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/conflict_attribute.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=430x" } */ +unsigned __attribute__((__a16__)) int * a16; +unsigned __attribute__((__a20__)) int * a20; +unsigned __attribute__((__a16__,__a20__)) int * a36; /* { dg-warning "'__a20__' cannot combine with '__a16__'" } */ + +void __attribute__((__c16__)) f16 (); +void __attribute__((__c20__)) f20 (); +void __attribute__((__c16__,__c20__)) f36 (); /* { dg-warning "'__c20__' cannot combine with '__c16__'" } */ + +void (* __attribute__((__c16__)) pf16) (); +void (* __attribute__((__c20__)) pf20) (); +void (*__attribute__((__c16__,__c20__)) pf36) (); /* { dg-warning "'__c20__' cannot combine with '__c16__'" } */ + +unsigned __attribute__((__d16__)) int d16; +unsigned __attribute__((__d20__)) int d20; +unsigned __attribute__((__d16__,__d20__)) int d36; /* { dg-warning "'__d20__' cannot combine with '__d16__'" } */ + +unsigned __attribute__((__near__,__d20__)) int nd20; /* { dg-warning "'__d20__' cannot combine with '__d16__'" } */ +unsigned __attribute__((__d20__,__near__)) int d20n; /* { dg-warning "'__near__' cannot combine with '__d20__'" } */ +unsigned __attribute__((__far__,__d16__)) int fd16; /* { dg-warning "'__d16__' cannot combine with '__d20__'" } */ +unsigned __attribute__((__d16__,__far__)) int d16f; /* { dg-warning "'__far__' cannot combine with '__d16__'" } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/critical_attribute.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/critical_attribute.c new file mode 100644 index 0000000..b60ea3b --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/critical_attribute.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +__attribute__((critical)) +int +critical (int a) +{ + /* { dg-final { scan-assembler "critical:\n\tpush\tr2\n\tdint\n\tnop\n\tadd\t#1, r15\n\tpop\tr2\n\tret\n" } } */ + return a+1; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/elimination.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/elimination.c new file mode 100644 index 0000000..22b4334 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/elimination.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "" } */ + +static unsigned char is_initialized = 0; + +int putchar (int c) +{ + /* { dg-final { scan-assembler "\tmov\tr15, -4\\(r4\\)\n" } } */ + if (! is_initialized) { + unsigned int delay; + + is_initialized = 1; + delay = 0; + while (++delay); + } + + return c; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/even_in_range.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/even_in_range.c new file mode 100644 index 0000000..f27fcd0 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/even_in_range.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern volatile unsigned int IV; +extern unsigned int result; +void handle () +{ + switch (__even_in_range(IV, 14)) { + case 0: + result = 'z'; + break; + case 2: + result = 't'; + break; + case 4: + result = 'f'; + break; + case 6: + result = 's'; + break; + case 8: + result = 'e'; + break; + case 10: + result = 't'; + break; + case 12: + result = 't'; + break; + case 14: + result = 'f'; + break; + } +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/framesaver_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/framesaver_1.c new file mode 100644 index 0000000..8e4c26e --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/framesaver_1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern volatile int v1; +extern volatile int v2; +extern volatile int v3; +extern void doit(); + +__attribute__ ((saveprologue)) +int func (int a, int b, int c) +{ /* { dg-warning "'saveprologue' no longer supported" } */ + /* NOT dg-final { scan-assembler "\tadd\t\#llo\\(-18\\), r1\n\tmov\tr0, r12\n\tbr\t#__prologue_saver" } } */ + int l1 = v1+v2; + int l2 = v2+v3; + int l3 = v1+v3; + doit(); + return a+b+c+l1+l2+l3; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/framesaver_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/framesaver_2.c new file mode 100644 index 0000000..f197214 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/framesaver_2.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern volatile int v1; +extern volatile int v2; +extern volatile int v3; +extern void doit(char * data); + +__attribute__ ((saveprologue)) +int func (int a, int b, int c) +{ /* { dg-warning "'saveprologue' no longer supported" } */ + /* NOT dg-final { scan-assembler "\tadd\t\#llo\\(-20\\), r1\n\tmov\tr0, r12\n\tbr\t#__prologue_saver" } } */ + int l1 = v1+v2; + int l2 = v2+v3; + int l3 = v1+v3; + char* data = __builtin_alloca (l3); + doit(data); + return a+b+c+l1+l2+l3; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/gen_return_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/gen_return_1.c new file mode 100644 index 0000000..8dac65e --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/gen_return_1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +extern int test (); +extern void doit (); + +int func () +{ + if (test ()) + /* { dg-final { scan-assembler "mov\t#2, r15\n\tret\n" } } */ + return 2; + doit(); + /* { dg-final { scan-assembler "mov\t#1, r15\n\tret\n" } } */ + return 1; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/gen_return_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/gen_return_2.c new file mode 100644 index 0000000..12d81a8 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/gen_return_2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +extern int test (); +extern void doit (); + +__attribute__ ((naked)) +int func () +{ + /* { dg-final { scan-assembler-not "\tret\n" } } */ + if (test ()) + return 2; + doit(); + return 1; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/msp430.exp gcc-4.7.0/gcc/testsuite/gcc.target/msp430/msp430.exp new file mode 100644 index 0000000..735bb9b --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/msp430.exp @@ -0,0 +1,41 @@ +# Copyright (C) 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an MSP430 target. +if ![istarget msp430-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/section_attribute.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/section_attribute.c new file mode 100644 index 0000000..ce69a18 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/section_attribute.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +__attribute__ ((naked,section(".init2"))) +void __init_stack () /* { dg-warning "frame allocation destroys caller register due to 'task'" } */ +{ + /* { dg-final { scan-assembler ".section\t.init2,\"ax\",@progbits" } } */ + /* { dg-final { scan-assembler "mov\t#256, r1\n" } } */ + __write_stack_pointer((void*)0x100); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3090574_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3090574_1.c new file mode 100644 index 0000000..fec0e99 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3090574_1.c @@ -0,0 +1,5 @@ +/* { dg-error "PIC not supported on msp430" } */ +/* { dg-do compile } */ +/* { dg-options "-O -fpic" } */ + +int t (int a) { return a+1; } diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3090574_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3090574_2.c new file mode 100644 index 0000000..506a4a6 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3090574_2.c @@ -0,0 +1,5 @@ +/* { dg-error "PIC not supported on msp430" } */ +/* { dg-do compile } */ +/* { dg-options "-O -fPIC" } */ + +int t (int a) { return a+1; } diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3104943_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_1.c new file mode 100644 index 0000000..e4079da --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +struct record { + int data[1]; +}; + +extern struct record ef (); + +struct record +f () +{ + struct record rv = { sizeof(rv) }; + /* { dg-final { scan-assembler "mov\t#2, r15" } } */ + return rv; +} + +int +xf () +{ + struct record rv = ef(); + /* { dg-final { scan-assembler "add\t#1, r15\n" } } */ + return 1 + rv.data[0]; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3104943_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_2.c new file mode 100644 index 0000000..26401d9 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_2.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +struct record { + int data[2]; +}; + +extern struct record ef (); + +struct record +f () +{ + struct record rv = { 1, sizeof(rv) }; + /* { dg-final { scan-assembler "mov\t#1, r14" } } */ + /* { dg-final { scan-assembler "mov\t#4, r15" } } */ + return rv; +} + +int +xf () +{ + struct record rv = ef(); + /* { dg-final { scan-assembler "mov\tr14, r15" } } */ + return 1 + rv.data[0]; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3104943_3.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_3.c new file mode 100644 index 0000000..931c4ab --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_3.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +struct record { + int data[3]; +}; + +extern struct record ef (); + +struct record +f () +{ + struct record rv = { 1, 2, sizeof(rv) }; + /* NOTE: Although this can fit in 3 registers, the middle end treats + the return value as a DImode integer, which cannot be placed + starting in r13. */ + /* { dg-final { scan-assembler "mov\t#1, r12" } } */ + /* { dg-final { scan-assembler "mov\t#2, r13" } } */ + /* { dg-final { scan-assembler "mov\t#6, r14" } } */ + /* { dg-final { scan-assembler "mov\t#0, r15" } } */ + return rv; +} + +int +xf () +{ + struct record rv = ef(); + /* { dg-final { scan-assembler "mov\tr12, r15" } } */ + return 1 + rv.data[0]; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3104943_4.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_4.c new file mode 100644 index 0000000..a809957 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_4.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +struct record { + int data[4]; +}; + +extern struct record ef (); + +struct record +f () +{ + struct record rv = { 1, 2, 3, sizeof(rv) }; + /* { dg-final { scan-assembler "mov\t#1, r12" } } */ + /* { dg-final { scan-assembler "mov\t#2, r13" } } */ + /* { dg-final { scan-assembler "mov\t#3, r14" } } */ + /* { dg-final { scan-assembler "mov\t#8, r15" } } */ + return rv; +} + +int +xf () +{ + struct record rv = ef(); + /* { dg-final { scan-assembler "mov\tr12, r15" } } */ + return 1 + rv.data[0]; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3104943_5.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_5.c new file mode 100644 index 0000000..69085b2 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3104943_5.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +struct record { + int data[5]; +}; + +extern struct record ef (); + +struct record +f () +{ + struct record rv = { 1, 2, 3, 4, sizeof(rv) }; + /* { dg-final { scan-assembler "mov\t#1, @r15" } } */ + /* { dg-final { scan-assembler "mov\t#2, 2\\(r15\\)" } } */ + /* { dg-final { scan-assembler "mov\t#3, 4\\(r15\\)" } } */ + /* { dg-final { scan-assembler "mov\t#4, 6\\(r15\\)" } } */ + /* { dg-final { scan-assembler "mov\t#10, 8\\(r15\\)" } } */ + return rv; +} + +int +xf () +{ + struct record rv = ef(); + /* { dg-final { scan-assembler "mov\t@r1, r15" } } */ + return 1 + rv.data[0]; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3112089.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3112089.c new file mode 100644 index 0000000..ed177ba --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3112089.c @@ -0,0 +1,67 @@ +/* https://sourceforge.net/tracker/?func=detail&aid=3112089&group_id=277223&atid=1177287 */ + + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef unsigned long int uint32_t; +typedef unsigned int uint16_t; +typedef unsigned char uint8_t; + +#define TIMERS_MAX 3 +#define TIMER_NULL TIMERS_MAX + +typedef struct{ + uint32_t count; + uint32_t interval; + uint16_t *mbox; /* caller supplied */ + uint8_t prev; + uint8_t next; +} TimerTCB; + +typedef uint8_t TimerId; + +volatile TimerTCB timerTable[TIMERS_MAX]; +volatile uint8_t timerListHead; +volatile uint8_t timerListTail; +volatile uint8_t timerFreeList; + +volatile uint32_t localTime; + +uint8_t TimerTickHandler(void); +TimerId TimerCreate(uint32_t val, uint16_t *mbox, uint8_t options); + +uint8_t TimerTickHandler(void) +{ + uint8_t sts = 0; /* assume no wakeup required */ + volatile uint8_t t; + uint16_t *mbox; + uint32_t val; + + localTime++; + if(timerListHead != TIMER_NULL){ + timerTable[timerListHead].count--; + + while((timerListHead != TIMER_NULL) && (timerTable[timerListHead].count == 0)){ + /* What we're looking for is: + mov 2(r14), r15 + mov @r14, r14 + jeq .L11 + + except with a comparison of the newly read r14 before the jeq. */ + /* { dg-final { scan-assembler "cmp\[ \t\]#0, r15" } } */ + UART_SendByte('t'); + t = timerListHead; + + /* Remove from list of active timers */ + timerListHead = timerTable[t].next; + + if(timerListHead != TIMER_NULL){ + timerTable[timerListHead].prev = TIMER_NULL; + } + + sts = 1; + } + } + return sts; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3148801.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3148801.c new file mode 100644 index 0000000..d10da65 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3148801.c @@ -0,0 +1,20 @@ +/* https://sourceforge.net/tracker/?func=detail&aid=3148801&group_id=42303&atid=432701 */ + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct word5 { + int data[5]; +}; + +extern struct word5 copy5 (struct word5 in); + +int test () +{ + struct word5 local = { 1, 2, 3, 4, 5 }; + struct word5 tmp; + + /* { dg-final { scan-assembler "push\[ \t\]#5\n\[ \t\]push\[ \t\]#4\n\[ \t\]push\[ \t\]#3\n\[ \t\]push\[ \t\]#2\n" } } */ + tmp = copy5(local); + return tmp.data[0]; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3177314_base.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3177314_base.c new file mode 100644 index 0000000..24a3cf2 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3177314_base.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-additional-files "sf3177314_ext.c" } */ + +extern int longname_l10iiiviiii20iiiviiii30iiiviiii40iiiviiii50iiiviiii60iiiviiii70iiiviiii80iiiviiii90iiiviiii100iiviiii110iiviiii120iiviiii130iiviiii140iiviiii150iiviiii160iiviiii170iiviiii180iiviiii190iiviiii200iiviiii210iiviiii220iiviiii230iiviiii240iiviiii250iiviiii260iiviiii270iiviiii280iiviiii290iiviiii; + +int main (int argc, char* argi[]) { + return 0 == longname_l10iiiviiii20iiiviiii30iiiviiii40iiiviiii50iiiviiii60iiiviiii70iiiviiii80iiiviiii90iiiviiii100iiviiii110iiviiii120iiviiii130iiviiii140iiviiii150iiviiii160iiviiii170iiviiii180iiviiii190iiviiii200iiviiii210iiviiii220iiviiii230iiviiii240iiviiii250iiviiii260iiviiii270iiviiii280iiviiii290iiviiii; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3177314_ext.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3177314_ext.c new file mode 100644 index 0000000..061519d --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3177314_ext.c @@ -0,0 +1,2 @@ +/* secondary test file referenced via sf3177314_base.c */ +int longname_l10iiiviiii20iiiviiii30iiiviiii40iiiviiii50iiiviiii60iiiviiii70iiiviiii80iiiviiii90iiiviiii100iiviiii110iiviiii120iiviiii130iiviiii140iiviiii150iiviiii160iiviiii170iiviiii180iiviiii190iiviiii200iiviiii210iiviiii220iiviiii230iiviiii240iiviiii250iiviiii260iiviiii270iiviiii280iiviiii290iiviiii; diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3188386.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3188386.c new file mode 100644 index 0000000..877edb2 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3188386.c @@ -0,0 +1,20 @@ +/* https://sourceforge.net/tracker/?func=detail&aid=3188386&group_id=42303&atid=432701 */ + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct sixbytes { + int data[3]; +}; + +struct sixbytes +f () +{ + struct sixbytes rv = { 1, 2, sizeof(rv) }; + /* { dg-final { scan-assembler "mov\[ \t\]#1, r12" } } */ + /* { dg-final { scan-assembler "mov\[ \t\]#2, r13" } } */ + /* { dg-final { scan-assembler "mov\[ \t\]#6, r14" } } */ + /* { dg-final { scan-assembler "mov\[ \t\]#0, r15" } } */ + + return rv; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3188386_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3188386_2.c new file mode 100644 index 0000000..e18575c --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3188386_2.c @@ -0,0 +1,17 @@ +/* https://sourceforge.net/tracker/?func=detail&aid=3188386&group_id=42303&atid=432701 */ + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct fivebytes { + char data[5]; +} __attribute__((packed)); + +struct fivebytes +f () +{ + struct fivebytes rv = { 1, 2, 3, 4, sizeof(rv) }; + + /* { dg-final { scan-assembler "mov\t#513, r12\n\tmov\t#1027, r13\n\tmov\t#5, r14\n\tmov\t#0, r15" } } */ + return rv; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_1.c new file mode 100644 index 0000000..6a755dc --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +int naked __attribute__((naked)); /* { dg-warning "'naked' attribute ignored" } */ +int signal __attribute__((signal)); /* { dg-warning "'signal' attribute ignored" } */ +int interrupt __attribute__((interrupt)); /* { dg-warning "'interrupt' attribute ignored" } */ +int task __attribute__((task)); /* { dg-warning "'task' attribute ignored" } */ +int wakeup __attribute__((wakeup)); /* { dg-warning "'wakeup' attribute ignored" } */ +int critical __attribute__((critical)); /* { dg-warning "'critical' attribute ignored" } */ +int reentrant __attribute__((reentrant)); /* { dg-warning "'reentrant' attribute ignored" } */ +int saveprologue __attribute__((saveprologue)); /* { dg-warning "'saveprologue' attribute ignored" } */ +int noint_hwmul __attribute__((noint_hwmul)); /* { dg-warning "'noint_hwmul' attribute ignored" } */ + + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_2.c new file mode 100644 index 0000000..3e079a7 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_2.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ + +__attribute__((wakeup)) +void wakeup_requires_interrupt () { } /* { dg-warning "'wakeup' attribute ignored \\(requires 'interrupt'\\)" } */ +__attribute__((signal)) +void signal_requires_interrupt () { } /* { dg-warning "'signal' attribute ignored \\(requires 'interrupt'\\)" } */ + +__attribute__((reentrant,naked)) +void reentrant_naked () { } /* { dg-warning "'reentrant' attribute ignored \\(incompatible with 'naked'\\)" } */ +/* { dg-warning "frame allocation destroys caller register due to 'task'" "" { target *-*-* } 9 } */ +__attribute__((critical,naked)) +void critical_naked () { } /* { dg-warning "'critical' attribute ignored \\(incompatible with 'naked'\\)" } */ +/* { dg-warning "frame allocation destroys caller register due to 'task'" "" { target *-*-* } 12 } */ + +__attribute__((reentrant,critical)) +void no_reentrant_critical () { } /* { dg-warning "'reentrant' attribute ignored \\(incompatible with 'critical'\\)" } */ +__attribute__((reentrant,interrupt(2))) +void no_reentrant_interrupt () { } /* { dg-warning "'reentrant' attribute ignored \\(incompatible with 'interrupt'\\)" } */ +__attribute__((critical,interrupt(4))) +void no_critical_interrupt () { } /* { dg-warning "'critical' attribute ignored \\(incompatible with 'interrupt'\\)" } */ + +__attribute__((naked,task)) +void no_naked_task () { } /* { dg-warning "'naked' attribute ignored \\(incompatible with 'task'\\)" } */ +/* { dg-warning "frame allocation destroys caller register due to 'task'" "" { target *-*-* } 23 } */ + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_3.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_3.c new file mode 100644 index 0000000..b9055d4 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_3.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern void ref (int * p); +extern int call (); + +/* Task functions may allocate frames */ +__attribute__ ((task)) +int task_with_frame () +{ + int v; + ref(&v); + return v; +} + +/* Naked functions should not allocate frames. SF 3264484 describes + * why this is a warning not an error. */ +__attribute__ ((naked)) +int naked_with_frame () /* { dg-warning "function requires 2 bytes for stack storage but frame allocation inhibited by 'naked'" } */ +{ + int v; + ref(&v); + return v; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_4.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_4.c new file mode 100644 index 0000000..f9c54e8 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ + +/* Interrupt vectors non-negative */ +__attribute__ ((interrupt(-2))) +void negative_isr () { } /* { dg-error "interrupt vector offset -2 must be even and non-negative" } */ + +/* Interrupt vectors even */ +__attribute__ ((interrupt(1))) +void odd_isr () { } /* { dg-error "interrupt vector offset 1 must be even and non-negative" } */ + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_5.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_5.c new file mode 100644 index 0000000..7c10286 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_5.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +/* Standard syntax */ +__attribute__ ((interrupt(4*2))) +void vectored_isr () { } +/* { dg-final { scan-assembler "vectored_isr:\n\t.global\t__isr_4\n__isr_4:\n" } } */ + +/* Old flag for non-associated ISR */ +__attribute__ ((interrupt(255))) +void legacy_unvectored_isr () { } + +/* New syntax for non-associated ISR */ +__attribute__ ((interrupt)) +void unvectored_isr () { } + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_6.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_6.c new file mode 100644 index 0000000..92c9937 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_6.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mivcnt=16" } */ + +/* Vector out of range */ +__attribute__ ((interrupt(16*2))) +void overflowed_vector () { } /* { dg-error "interrupt vector 16 is beyond end of MCU vector table" } */ + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_7.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_7.c new file mode 100644 index 0000000..b291112 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_7.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +/* None of these non-hosted functions should generate a return + * instruction of any sort. */ +/* { dg-final { scan-assembler-not "\tret" } } */ + +__attribute__ ((task)) +int task () +{ + return 32; +} + +__attribute__ ((naked)) +int naked () +{ + return 33; +} + +extern int v; + +__attribute__ ((interrupt,naked)) +void naked_isr () +{ + v = 34; + /* { dg-final { scan-assembler "\tmov\t#34, &v\n" } } */ +} + +__attribute__ ((interrupt,task)) +void task_isr () +{ + v = 35; + /* { dg-final { scan-assembler "\tmov\t#35, &v\n" } } */ +} + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3200763_8.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_8.c new file mode 100644 index 0000000..4c2fd4c --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3200763_8.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +/* Hosted tasks include the return instruction */ +__attribute__ ((task,hosted)) +int hosted_task () +{ + /* { dg-final { scan-assembler "\tmov\t#32, r15\n\tret\n" } } */ + return 32; +} + +/* Hosted naked include the return instruction */ +__attribute__ ((naked,hosted)) +int hosted_naked () +{ + /* { dg-final { scan-assembler "\tmov\t#33, r15\n\tret\n" } } */ + return 33; +} + +extern int v; + +__attribute__ ((interrupt,naked,hosted)) +void hosted_naked_isr () +{ + v = 34; + /* { dg-final { scan-assembler "\tmov\t#34, &v\n\treti\n" } } */ +} + +__attribute__ ((interrupt,task,hosted)) +void hosted_task_isr () +{ + v = 35; + /* { dg-final { scan-assembler "\tmov\t#35, &v\n\treti\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3201686.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3201686.c new file mode 100644 index 0000000..2066098 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3201686.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +/* { dg-final { scan-assembler-not ".type\tdisappearing, @function" } } */ +extern volatile int v; +static void disappearing () +{ + v = 'd'; +} + +/* { dg-final { scan-assembler ".type\tpreserved, @function" } } */ +__attribute__ ((interrupt(1*2))) +static void preserved () +{ + v = 'p'; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3207853.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3207853.c new file mode 100644 index 0000000..ba9072e --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3207853.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern void doit (unsigned long long int v); +void call () +{ + static const unsigned long long int value = 0x123456789abcdef0ULL; + + /* Builds on 64-bit systems generate different code than ones on + * 32-bit systems. */ + /* { dg-final { scan-assembler "mov\t#llo\\((-1698898192|1311768467463790320)\\), r12" } } */ + /* { dg-final { scan-assembler "mov\t#lhi\\((-1698898192|1311768467463790320)\\), r13" } } */ + /* { dg-final { scan-assembler "mov\t#(llo\\(305419896\\)|hlo\\(1311768467463790320\\)), r14" } } */ + /* { dg-final { scan-assembler "mov\t#(lhi\\(305419896\\)|hhi\\(1311768467463790320\\)), r15" } } */ + doit(value); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_1.c new file mode 100644 index 0000000..6733638 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_1.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tnop\n\tret" } } */ + __delay_cycles (1); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_11.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_11.c new file mode 100644 index 0000000..57665af --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_11.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tmov\t#3, r15\n.L2:\n\tdec\tr15\n\tjne\t.L2\n\tret" } } */ + __delay_cycles (11); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_2.c new file mode 100644 index 0000000..e0bd991 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_2.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tnop\n\tnop\n\tret" } } */ + __delay_cycles (2); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_3.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_3.c new file mode 100644 index 0000000..2d51a60 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_3.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tnop\n\tnop\n\tnop\n\tret" } } */ + __delay_cycles (3); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_4.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_4.c new file mode 100644 index 0000000..1cc43b9 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_4.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tmov\t#1, r15\n.L2:\n\tdec\tr15\n\tjne\t.L2\n\tret" } } */ + __delay_cycles (4); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_5.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_5.c new file mode 100644 index 0000000..4a7b71f --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_5.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tmov\t#1, r15\n.L2:\n\tdec\tr15\n\tjne\t.L2\n\tnop\n\tret" } } */ + __delay_cycles (5); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_6.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_6.c new file mode 100644 index 0000000..7bca3fb --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_6.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tmov\t#1, r15\n.L2:\n\tdec\tr15\n\tjne\t.L2\n\tnop\n\tnop\n\tret" } } */ + __delay_cycles (6); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_7.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_7.c new file mode 100644 index 0000000..c1df8a6 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_7.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void foo () +{ + /* { dg-final { scan-assembler "foo:\n\tmov\t#2, r15\n.L2:\n\tdec\tr15\n\tjne\t.L2\n\tret" } } */ + __delay_cycles (7); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3237005_check.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_check.c new file mode 100644 index 0000000..0e02bba --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3237005_check.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +int foo (int n) +{ + __delay_cycles (n); /* { dg-error "__delay_cycles argument must be non-negative integer constant" } */ + __delay_cycles (-4); /* { dg-error "__delay_cycles argument must be non-negative integer constant" } */ + __delay_cycles(3 * 65536UL); /* ok: 196608 == 1 + 65535*3 + 2 */ + __delay_cycles(1 + 3 * 65536UL); /* ok: 196609 == 1 + 65536*3 + 0 */ + __delay_cycles(3 + 3 * 65536UL); /* ok: 196611 == 1 + 65536*3 + 2 */ + __delay_cycles(4 + 3 * 65536UL); /* ok: 196612 == 1 + 65536*3 + 3 */ + __delay_cycles(5 + 3 * 65536UL); /* ok: 196613 == 1 + 65536*3 + 1 + 1*3 */ + __delay_cycles(196618UL); /* ok: 196618 == 1 + 65536*3 + 1 + 2*3 + 2 */ + __delay_cycles(196619UL); /* ok: 196619 == 1 + 1 + 3 + 3 + 65536*3 + 3 */ + __delay_cycles(0x7fffffffL); /* ok : 2 + 2 + 32766*3 + 3 + 10922 * 196611 */ + return 0; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3257192_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3257192_1.c new file mode 100644 index 0000000..034144b --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3257192_1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern int v; +extern void ref (int * p); + +__attribute__ ((reentrant,noreturn)) +void noreturn (int arg) +{ + int a; + ref(&a); + v = a+arg; + __dint(); + __bis_status_register (0xF0); +} /* { dg-warning "'noreturn' function does return" } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3261372.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3261372.c new file mode 100644 index 0000000..f6ab6a3 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3261372.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-g" } */ + +__attribute__((critical)) +int +critical (int a) +{ + return a+1; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3273856.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3273856.c new file mode 100644 index 0000000..ef92512 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3273856.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +unsigned long long int backwards_rr (unsigned char v) { return v; } +/* { dg-final { scan-assembler "\tmov.b\tr15, r12\n\tmov\t#0, r13\n\tmov\t#0, r14\n\tmov\t#0, r15\n" } } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3290923.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3290923.c new file mode 100644 index 0000000..2dbbb1b --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3290923.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +extern int longcall (unsigned long long int regs, + int a1, + int a2); + +int test () +{ + int rv; + rv = longcall (0ULL, 1, 1); + /* { dg-final { scan-assembler "\n\tcall\t#longcall\n\tadd\t#4, r1\n" } } */ + rv += longcall (0ULL, 2, 2); + return rv; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3296698.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3296698.c new file mode 100644 index 0000000..eabf89d --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3296698.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +typedef struct { + int bit:1; + int :15; +} type_x; + +static inline type_x getX() { + union { + int f; + type_x t; + } c; + c.f = *(int *)0x100; + return c.t; +} + +extern void subr(); + +void func() { + /* { dg-final { scan-assembler "\n\tbit.b\t#1, &256\n\tjeq\t.L1\n\tcall\t#subr\n" } } */ + if (getX().bit) + subr(); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3300205.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3300205.c new file mode 100644 index 0000000..745a80f --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3300205.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +volatile unsigned char s_char; +volatile unsigned char s_short; +volatile unsigned char s_int; +volatile unsigned char s_long; +volatile unsigned char s_longlong; +volatile unsigned char s_float; +volatile unsigned char s_double; + +void test () +{ + /* { dg-final { scan-assembler "\tmov.b\t#1, \&s_char\n" } } */ + s_char = sizeof(char); + /* { dg-final { scan-assembler "\tmov.b\t#2, \&s_short\n" } } */ + s_short = sizeof(short int); + /* { dg-final { scan-assembler "\tmov.b\t#2, \&s_int\n" } } */ + s_int = sizeof(int); + /* { dg-final { scan-assembler "\tmov.b\t#4, \&s_long\n" } } */ + s_long = sizeof(long int); + /* { dg-final { scan-assembler "\tmov.b\t#8, \&s_longlong\n" } } */ + s_longlong = sizeof(long long int); + /* { dg-final { scan-assembler "\tmov.b\t#4, \&s_float\n" } } */ + s_float = sizeof(float); + /* { dg-final { scan-assembler "\tmov.b\t#4, \&s_double\n" } } */ + s_double = sizeof(double); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3383371_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3383371_1.c new file mode 100644 index 0000000..23801f5 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3383371_1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern unsigned int clear_value; +unsigned int test () +{ + /* { dg-final { scan-assembler "\tmov\t&__wdt_clear_value, &clear_value\n" } } */ + clear_value = __get_watchdog_clear_value (); + /* { dg-final { scan-assembler "\tmov\t&__wdt_clear_value, &__WDTCTL\n" } } */ + __watchdog_clear (); + /* { dg-final { scan-assembler "\tmov\t\#4660, &__wdt_clear_value\n" } } */ + __set_watchdog_clear_value (0x1234); + /* { dg-final { scan-assembler "\tmov\t&__wdt_clear_value, r15\n" } } */ + return __get_watchdog_clear_value (); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3383371_2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3383371_2.c new file mode 100644 index 0000000..a746f84 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3383371_2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-Os -mdisable-watchdog" } */ + +extern unsigned int clear_value; +unsigned int test () +{ + /* { dg-final { scan-assembler "\tmov\t#-1, \&clear_value\n\tmov\t#-1, r15\n" } } */ + clear_value = __get_watchdog_clear_value (); + __watchdog_clear (); + __set_watchdog_clear_value (0x1234); + return __get_watchdog_clear_value (); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3397068.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3397068.c new file mode 100644 index 0000000..788c352 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3397068.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +__attribute__ ((section(".noinit"))) +void fn_noinit_illegal () { } /* { dg-warning "only uninitialized variables can be placed in a .bss section" } */ + +int ia_bss __attribute__ ((section(".infoa.bss"))); +int ib_init __attribute__ ((section(".infob"))) = 1; +int ic_init_bss __attribute__ ((section(".infoc.bss"))) = 1; /* { dg-warning "only uninitialized variables can be placed in a .bss section" } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3423822_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3423822_1.c new file mode 100644 index 0000000..5307439 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3423822_1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +__attribute__ ((__interrupt__(UNDEF_VECTOR))) +static void undef_isr () /* { dg-error "interrupt vector offset 'UNDEF_VECTOR' is not an integer constant" } */ +{ } + +__attribute__ ((__interrupt__("0"))) +static void string_isr () /* { dg-error "interrupt vector offset must be an even non-negative integer constant" } */ +{ } + +__attribute__ ((__interrupt__(4, 1))) +static void multivect_isr () +{ } /* { dg-error "wrong number of arguments specified for '__interrupt__' attribute" } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3426468.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3426468.c new file mode 100644 index 0000000..33b9a09 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3426468.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O -mcpu=430x" } */ + +extern printf (char* fmt, ...); + +void printSI (int r15, unsigned long int v) +{ + printf("Value: %lx\n", v); + /* { dg-final { scan-assembler "pushm\t#2, r14\n" } } */ +} + +void printDI (unsigned long long int v) +{ + printf("Value: %llx\n", v); + /* { dg-final { scan-assembler "pushm\t#4, r15\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3428439.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3428439.c new file mode 100644 index 0000000..3ae3bc4 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3428439.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +int mc (int* dp, int*sp, int l) +{ + while (0 < l--) { + /* { dg-final { scan-assembler "mov\t@r14\\+, @r15\n\tadd\t#2, r15\n" } } */ + *dp++ = *sp++; + } +} + +int sum (int* sv, int l) +{ + int rv = 0; + while (0 < l--) { + /* { dg-final { scan-assembler "add\t@r12\\+, r15\n" } } */ + rv += *sv++; + } + return rv; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3433730.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3433730.c new file mode 100644 index 0000000..b8d114f --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3433730.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern unsigned int strlen (const char *s); +void setval (char* str, int len); +void useval (const char* str, unsigned char len); + +void tryit () +{ + char tmp[17]; + setval (tmp, sizeof(tmp)); + useval (tmp, strlen(tmp)); + /* { dg-final { scan-assembler "sub.b\tr1, r14\n\tmov\tr1, r15\n\tcall\t#useval" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3474171.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3474171.c new file mode 100644 index 0000000..11463b1 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3474171.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ + +#pragma vector=14 +__attribute__((interrupt)) +void isr14 () { } +/* { dg-final { scan-assembler "isr14:\n\t.global\t__isr_7\n__isr_7:\n" } } */ + +#define VECT 22 + +#pragma vector=VECT +__attribute__((interrupt)) +void isrD22 () { } +/* { dg-final { scan-assembler "isrD22:\n\t.global\t__isr_11\n__isr_11:\n" } } */ + +#define PVECT (24) + +#pragma vector=PVECT +__attribute__((interrupt)) +void isrD24 () { } +/* { dg-final { scan-assembler "isrD24:\n\t.global\t__isr_12\n__isr_12:\n" } } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3474171_1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3474171_1.c new file mode 100644 index 0000000..6223566 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3474171_1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ + +#pragma vector 10 /* { dg-warning "missing '=' after '#pragma vector' - ignored" } */ + +#pragma vector=id /* { dg-warning "malformed '#pragma vector' - ignored" } */ + +#pragma vector=(10 /* { dg-warning "malformed '#pragma vector' - ignored" } */ + +#pragma vector=11 +__attribute__((interrupt)) +void isr11 () { } /* { dg-error "interrupt vector offset 11 must be even and non-negative" } */ diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3559978.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3559978.c new file mode 100644 index 0000000..8801ddc --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3559978.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +static volatile struct sTransmitBuffer { + volatile char * head; + volatile char * tail; + char buffer[256]; + unsigned int wake_when_available; +} txBuffer; + +void initialize () +{ + txBuffer.tail = txBuffer.buffer; /* { dg-final { scan-assembler "mov\t#txBuffer\\+2, r15\n\tmov\tr15, r14\n\tadd\t#2, r14\n\tmov\tr14, @r15\n" } } */ +} + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/sf3562063.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3562063.c new file mode 100644 index 0000000..6d2b9ab --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/sf3562063.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +void foo () +{ + /* { dg-final { scan-assembler "\tmov\t#3, r15\n.L2:\n\tdec\tr15\n\tjne\t.L2\n" } } */ + __delay_cycles (11); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/target_isr20.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/target_isr20.c new file mode 100644 index 0000000..12c02b1 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/target_isr20.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O -mcpu=430x -misr20" } */ + +void something (); +__attribute__((__interrupt__(0))) +void isr_0 () { something(0); } +/* { dg-final { scan-assembler "__isr_0:\n\tpushm.a\t#4, r15\n\tmov\t#0, r15\n\tcall\t#something" } } */ + +__attribute__((__interrupt__(16),__sr16__)) +void isr_16 () { something(16); } +/* { dg-final { scan-assembler "__isr_8:\n\tpushm\t#4, r15\n\tmov\t#16, r15\n\tcall\t#something" } } */ + +__attribute__((__interrupt__(20),__sr20__)) +void isr_20 () { something(20); } +/* { dg-final { scan-assembler "__isr_10:\n\tpushm.a\t#4, r15\n\tmov\t#20, r15\n\tcall\t#something" } } */ + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vararg-1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vararg-1.c new file mode 100644 index 0000000..531fd0c --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vararg-1.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +#include + +int test (int a1, ...) +{ + int v1; + va_list va_arglist; + + va_start (va_arglist, a1); + v1 = va_arg (va_arglist, int); + va_end (va_arglist); + /* { dg-final { scan-assembler "\tmov\t4\\(r1\\), r15\n\tret\n" } } */ + return v1; +} + +extern int etest (int a1, ...); + +int calltest () +{ + /* { dg-final { scan-assembler "\tcall\t#etest\n\tadd\t#4, r1\n\tret\n" } } */ + return etest (1, 2); +} + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/volpeep_mem.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/volpeep_mem.c new file mode 100644 index 0000000..d029063 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/volpeep_mem.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned char ior8; +extern volatile unsigned int ior16; +extern volatile unsigned char and8; +extern volatile unsigned int and16; +extern volatile unsigned char nand8; +extern volatile unsigned int nand16; +extern volatile unsigned char xor8; +extern volatile unsigned int xor16; +extern volatile unsigned char mov8; +extern volatile unsigned int mov16; +extern volatile unsigned char add8; +extern volatile unsigned int add16; +extern volatile unsigned char sub8; +extern volatile unsigned int sub16; + +unsigned char m8; +unsigned int m16; + +void +testm () +{ + /* { dg-final { scan-assembler "mov.b\t\&m8, r15\n" } } */ + ior8 |= m8; /* { dg-final { scan-assembler "bis.b\tr15, \&ior8\n" } } */ + and8 &= m8; /* { dg-final { scan-assembler "and.b\tr15, \&and8\n" } } */ + nand8 &= ~m8; /* { dg-final { scan-assembler "bic.b\tr15, \&nand8\n" } } */ + xor8 ^= m8; /* { dg-final { scan-assembler "xor.b\tr15, \&xor8\n" } } */ + add8 += m8; /* { dg-final { scan-assembler "add.b\tr15, \&add8\n" } } */ + sub8 -= m8; /* { dg-final { scan-assembler "sub.b\tr15, \&sub8\n" } } */ + /* { dg-final { scan-assembler "mov\t\&m16, r15\n" } } */ + ior16 |= m16; /* { dg-final { scan-assembler "bis\tr15, \&ior16\n" } } */ + and16 &= m16; /* { dg-final { scan-assembler "and\tr15, \&and16\n" } } */ + nand16 &= ~m16; /* { dg-final { scan-assembler "bic\tr15, \&nand16\n" } } */ + xor16 ^= m16; /* { dg-final { scan-assembler "xor\tr15, \&xor16\n" } } */ + add16 += m16; /* { dg-final { scan-assembler "add\tr15, \&add16\n" } } */ + sub16 -= m16; /* { dg-final { scan-assembler "sub\tr15, \&sub16\n" } } */ +} + +void +testm2m () +{ + mov8 = m8; /* { dg-final { scan-assembler "mov.b\t\&m8, \&mov8\n" } } */ + mov16 = m16; /* { dg-final { scan-assembler "mov\t\&m16, \&mov16\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/volpeep_reg.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/volpeep_reg.c new file mode 100644 index 0000000..4e4fe76 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/volpeep_reg.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned char ior8; +extern volatile unsigned int ior16; +extern volatile unsigned char and8; +extern volatile unsigned int and16; +extern volatile unsigned char nand8; +extern volatile unsigned int nand16; +extern volatile unsigned char xor8; +extern volatile unsigned int xor16; +extern volatile unsigned char add8; +extern volatile unsigned int add16; +extern volatile unsigned char sub8; +extern volatile unsigned int sub16; + +void +testr (unsigned char v8, + unsigned int v16) +{ + ior8 |= v8; /* { dg-final { scan-assembler "bis.b\tr15, \&ior8\n" } } */ + ior16 |= v16; /* { dg-final { scan-assembler "bis\tr14, \&ior16\n" } } */ + and8 &= v8; /* { dg-final { scan-assembler "and.b\tr15, \&and8\n" } } */ + and16 &= v16; /* { dg-final { scan-assembler "and\tr14, \&and16\n" } } */ + nand8 &= ~v8; /* { dg-final { scan-assembler "bic.b\tr15, \&nand8\n" } } */ + nand16 &= ~v16; /* { dg-final { scan-assembler "bic\tr14, \&nand16\n" } } */ + xor8 ^= v8; /* { dg-final { scan-assembler "xor.b\tr15, \&xor8\n" } } */ + xor16 ^= v16; /* { dg-final { scan-assembler "xor\tr14, \&xor16\n" } } */ + add8 += v8; /* { dg-final { scan-assembler "add.b\tr15, \&add8\n" } } */ + add16 += v16; /* { dg-final { scan-assembler "add\tr14, \&add16\n" } } */ + sub8 -= v8; /* { dg-final { scan-assembler "sub.b\tr15, \&sub8\n" } } */ + sub16 -= v16; /* { dg-final { scan-assembler "sub\tr14, \&sub16\n" } } */ +} + diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/volpeep_volmem.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/volpeep_volmem.c new file mode 100644 index 0000000..b58de05 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/volpeep_volmem.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned char ior8; +extern volatile unsigned int ior16; +extern volatile unsigned char and8; +extern volatile unsigned int and16; +extern volatile unsigned char nand8; +extern volatile unsigned int nand16; +extern volatile unsigned char xor8; +extern volatile unsigned int xor16; +extern volatile unsigned char mov8; +extern volatile unsigned int mov16; +extern volatile unsigned char add8; +extern volatile unsigned int add16; +extern volatile unsigned char sub8; +extern volatile unsigned int sub16; + +volatile unsigned char m8; +volatile unsigned int m16; + +void +testm () +{ + ior8 |= m8; /* { dg-final { scan-assembler "bis.b\t\&m8, \&ior8\n" } } */ + and8 &= m8; /* { dg-final { scan-assembler "and.b\t\&m8, \&and8\n" } } */ + nand8 &= ~m8; /* { dg-final { scan-assembler "bic.b\t\&m8, \&nand8\n" } } */ + xor8 ^= m8; /* { dg-final { scan-assembler "xor.b\t\&m8, \&xor8\n" } } */ + add8 += m8; /* { dg-final { scan-assembler "add.b\t\&m8, \&add8\n" } } */ + sub8 -= m8; /* { dg-final { scan-assembler "sub.b\t\&m8, \&sub8\n" } } */ + + ior16 |= m16; /* { dg-final { scan-assembler "bis\t\&m16, \&ior16\n" } } */ + and16 &= m16; /* { dg-final { scan-assembler "and\t\&m16, \&and16\n" } } */ + nand16 &= ~m16; /* { dg-final { scan-assembler "bic\t\&m16, \&nand16\n" } } */ + xor16 ^= m16; /* { dg-final { scan-assembler "xor\t\&m16, \&xor16\n" } } */ + add16 += m16; /* { dg-final { scan-assembler "add\t\&m16, \&add16\n" } } */ + sub16 -= m16; /* { dg-final { scan-assembler "sub\t\&m16, \&sub16\n" } } */ +} + +void +testm2m () +{ + mov8 = m8; /* { dg-final { scan-assembler "mov.b\t\&m8, \&mov8\n" } } */ + mov16 = m16; /* { dg-final { scan-assembler "mov\t\&m16, \&mov16\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa1.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa1.c new file mode 100644 index 0000000..cb1432d --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned int periph; + +void vwa (unsigned int v) +{ + /* { dg-final { scan-assembler "\n\tand\tr15, \&periph\n" } } */ + periph &= v; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa2.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa2.c new file mode 100644 index 0000000..4f1b344 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fno-peephole2" } */ + +extern volatile unsigned int periph; + +void vwa (unsigned int v) +{ + /* { dg-final { scan-assembler "\n\tmov\t\&periph, r14\n\tand\tr14, r15\n\tmov\tr15, \&periph\n" } } */ + periph &= v; +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa3.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa3.c new file mode 100644 index 0000000..5da9526 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa3.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fno-peephole2" } */ + +extern volatile unsigned char periph8; +extern volatile unsigned int periph16; + +extern void use (unsigned long long int regargs, + unsigned int p16, + unsigned char p8); + +void vwa_push () +{ + /* pushm1 requires vwa support */ + /* { dg-final { scan-assembler "\n\tmov.b\t\&periph8, r14\n\tmov\t\&periph16, r15\n\tpush.b\tr14\n\tpush\tr15\n" } } */ + use (0ULL, periph16, periph8); +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa4.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa4.c new file mode 100644 index 0000000..630c905 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa4.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +#define ADDR8 1351 +#define ADDR16 1352 + +void set_bit0 () +{ + *(volatile unsigned char*)ADDR8 |= 1; /* { dg-final { scan-assembler "bis.b\t#1, \&1351\n" } } */ + *(volatile unsigned int*)ADDR16 |= 8; /* { dg-final { scan-assembler "bis\t#8, \&1352\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa5.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa5.c new file mode 100644 index 0000000..20bf44f --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa5.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned int and16; +extern volatile unsigned int nand16; +extern volatile unsigned int ior16; +extern volatile unsigned int xor16; +extern volatile unsigned int add16; +extern volatile unsigned int sub16; +extern volatile unsigned int mov16; + +void f () +{ + and16 &= and16; /* { dg-final { scan-assembler "and\t\&and16, \&and16\n" } } */ + nand16 &= ~nand16; /* { dg-final { scan-assembler "bic\t\&nand16, \&nand16\n" } } */ + ior16 |= ior16; /* { dg-final { scan-assembler "bis\t\&ior16, \&ior16\n" } } */ + add16 += add16; /* { dg-final { scan-assembler "add\t\&add16, \&add16\n" } } */ + sub16 -= sub16; /* { dg-final { scan-assembler "sub\t\&sub16, \&sub16\n" } } */ + mov16 = mov16; /* { dg-final { scan-assembler "mov\t\&mov16, \&mov16\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa_error.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa_error.c new file mode 100644 index 0000000..20bf9c8 --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa_error.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +extern volatile unsigned char ior8; +extern volatile unsigned int ior16; +extern volatile unsigned char and8; +extern volatile unsigned int and16; + +extern volatile unsigned char v8; +extern volatile unsigned int v16; + +void +testv1 () +{ + unsigned char l8; + unsigned char t8; + unsigned int l16; + + /* Note that this pattern is what "ior8 |= (l8 = v8)" normally + * becomes, but in this case there are sequence points which make + * moving the read of v8 before the read of ior8 clearly incorrect. + * If the original msp430_vwa_* predicates are used to subvert + * volatile checking in the iorqi3 insn, the combiner phase will + * move the read of v8 before the first read of ior8 before the + * peephole optimization could detect and inhibit the collapse, and + * the abstract machine order requirements are violated. */ + t8 = ior8; + l8 = v8; + ior8 = t8 | l8; + /* { dg-final { scan-assembler "mov.b\t\&ior8, r15\n\tmov.b\t\&v8, r14\n\tbis.b\tr14, r15\n\tmov.b\tr15, \&ior8\n" } } */ + and8 &= l8; /* { dg-final { scan-assembler "and.b\tr14, \&and8\n" } } */ +} diff --git gcc-4.7.0.orig/gcc/testsuite/gcc.target/msp430/vwa_regression.c gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa_regression.c new file mode 100644 index 0000000..f1833aa --- /dev/null +++ gcc-4.7.0/gcc/testsuite/gcc.target/msp430/vwa_regression.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +/* This program demonstrates a code size regression upon removal of + * the volatile workaround from mspgcc. RTL optimizations end up + * keeping &bitbuffer[1] into a register but moving the final write to + * epilog code. This preserves the semantics of volatile, but results + * in larger code than if the write were made directly to memory. It + * cannot be undone by peephole optimization. + */ + +extern volatile char bitbuffer[2]; + +void showlevel (unsigned char lvl) +{ + bitbuffer[0] &= 0xf1; + bitbuffer[1] &= 0xf0; + + switch(lvl) + { + case 0: + bitbuffer[0] |= 0x01; + bitbuffer[1] |= 0x01; + /* { dg-final { scan-assembler ".L3:\n\tbis.b\t#1, \&bitbuffer\n\tmov.b\t\&bitbuffer\\+1, r15\n\tbis.b\t#1, r15\n\tjmp\t.L11\n" } } */ + /* { dg-final { scan-assembler ".L11:\n\tmov.b\tr15, \&bitbuffer\\+1\n.L1:\n\tret\n" } } */ + break; + case 1: + bitbuffer[0] |= 0x01; + bitbuffer[1] |= 0x03; + break; + case 2: + bitbuffer[0] |= 0x01; + bitbuffer[1] |= 0x07; + break; + case 3: + bitbuffer[0] |= 0x01; + bitbuffer[1] |= 0x0f; + break; + case 4: + bitbuffer[0] |= 0x03; + bitbuffer[1] |= 0x0f; + break; + case 5: + bitbuffer[0] |= 0x07; + bitbuffer[1] |= 0x0f; + break; + }; +} + diff --git gcc-4.7.0.orig/gcc/tree-pretty-print.c gcc-4.7.0/gcc/tree-pretty-print.c index 4b9b453..227999c 100644 --- gcc-4.7.0.orig/gcc/tree-pretty-print.c +++ gcc-4.7.0/gcc/tree-pretty-print.c @@ -723,11 +723,41 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, } else if (TREE_CODE (node) == INTEGER_TYPE) { - pp_string (buffer, (TYPE_UNSIGNED (node) - ? ""); + if (TYPE_PRECISION (node) == CHAR_TYPE_SIZE) + pp_string (buffer, (TYPE_UNSIGNED (node) + ? "unsigned char" + : "signed char")); + else if (TYPE_PRECISION (node) == SHORT_TYPE_SIZE) + pp_string (buffer, (TYPE_UNSIGNED (node) + ? "unsigned short" + : "signed short")); + else if (TYPE_PRECISION (node) == INT_TYPE_SIZE) + pp_string (buffer, (TYPE_UNSIGNED (node) + ? "unsigned int" + : "signed int")); + else if (TYPE_PRECISION (node) == LONG_TYPE_SIZE) + pp_string (buffer, (TYPE_UNSIGNED (node) + ? "unsigned long" + : "signed long")); + else if (TYPE_PRECISION (node) == LONG_LONG_TYPE_SIZE) + pp_string (buffer, (TYPE_UNSIGNED (node) + ? "unsigned long long" + : "signed long long")); + else if (TYPE_PRECISION (node) >= CHAR_TYPE_SIZE + && exact_log2 (TYPE_PRECISION (node))) + { + pp_string (buffer, (TYPE_UNSIGNED (node) ? "uint" : "int")); + pp_decimal_int (buffer, TYPE_PRECISION (node)); + pp_string (buffer, "_t"); + } + else + { + pp_string (buffer, (TYPE_UNSIGNED (node) + ? ""); + } } else if (TREE_CODE (node) == COMPLEX_TYPE) { diff --git gcc-4.7.0.orig/gcc/tree-ssa-address.c gcc-4.7.0/gcc/tree-ssa-address.c index cf131578..1d3d04c 100644 --- gcc-4.7.0.orig/gcc/tree-ssa-address.c +++ gcc-4.7.0/gcc/tree-ssa-address.c @@ -538,7 +538,7 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts, aff_tree *addr, bool speed) { addr_space_t as = TYPE_ADDR_SPACE (type); - enum machine_mode address_mode = targetm.addr_space.address_mode (as); + enum machine_mode address_mode = targetm.type_address_mode (type); HOST_WIDE_INT coef; double_int best_mult, amult, amult_neg; unsigned best_mult_cost = 0, acost; diff --git gcc-4.7.0.orig/gcc/tree-ssa-ccp.c gcc-4.7.0/gcc/tree-ssa-ccp.c index 2080c06..c28006a 100644 --- gcc-4.7.0.orig/gcc/tree-ssa-ccp.c +++ gcc-4.7.0/gcc/tree-ssa-ccp.c @@ -2288,7 +2288,7 @@ optimize_stdarg_builtin (gimple call) case BUILT_IN_VA_START: if (!va_list_simple_ptr || targetm.expand_builtin_va_start != NULL - || builtin_decl_explicit_p (BUILT_IN_NEXT_ARG)) + || !builtin_decl_explicit_p (BUILT_IN_NEXT_ARG)) return NULL_TREE; if (gimple_call_num_args (call) != 2) diff --git gcc-4.7.0.orig/gcc/tree-ssa-forwprop.c gcc-4.7.0/gcc/tree-ssa-forwprop.c index 20821ef..2b01640 100644 --- gcc-4.7.0.orig/gcc/tree-ssa-forwprop.c +++ gcc-4.7.0/gcc/tree-ssa-forwprop.c @@ -1,5 +1,5 @@ /* Forward propagation of expressions for single use variables. - Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011 + Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -2274,7 +2274,7 @@ combine_conversions (gimple_stmt_iterator *gsi) && inter_prec >= inside_prec && (inter_float || inter_vec || inter_unsignedp == inside_unsignedp) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type)) && ! final_ptr && (! final_vec || inter_prec == inside_prec)) @@ -2316,7 +2316,7 @@ combine_conversions (gimple_stmt_iterator *gsi) == (final_unsignedp && final_prec > inter_prec)) && ! (inside_ptr && inter_prec != final_prec) && ! (final_ptr && inside_prec != inter_prec) - && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type)) + && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type)) && TYPE_MODE (type) == TYPE_MODE (inter_type))) { gimple_assign_set_rhs1 (stmt, defop0); diff --git gcc-4.7.0.orig/gcc/tree-ssa-loop-ivopts.c gcc-4.7.0/gcc/tree-ssa-loop-ivopts.c index 10c9352..90a4c9f 100644 --- gcc-4.7.0.orig/gcc/tree-ssa-loop-ivopts.c +++ gcc-4.7.0/gcc/tree-ssa-loop-ivopts.c @@ -2405,28 +2405,26 @@ add_candidate (struct ivopts_data *data, add_autoinc_candidates (data, base, step, important, use); } -/* Add a standard "0 + 1 * iteration" iv candidate for a - type with SIZE bits. */ - -static void -add_standard_iv_candidates_for_size (struct ivopts_data *data, - unsigned int size) -{ - tree type = lang_hooks.types.type_for_size (size, true); - add_candidate (data, build_int_cst (type, 0), build_int_cst (type, 1), - true, NULL); -} - /* Adds standard iv candidates. */ static void add_standard_iv_candidates (struct ivopts_data *data) { - add_standard_iv_candidates_for_size (data, INT_TYPE_SIZE); + add_candidate (data, integer_zero_node, integer_one_node, true, NULL); /* The same for a double-integer type if it is still fast enough. */ - if (BITS_PER_WORD >= INT_TYPE_SIZE * 2) - add_standard_iv_candidates_for_size (data, INT_TYPE_SIZE * 2); + if (TYPE_PRECISION + (long_integer_type_node) > TYPE_PRECISION (integer_type_node) + && TYPE_PRECISION (long_integer_type_node) <= BITS_PER_WORD) + add_candidate (data, build_int_cst (long_integer_type_node, 0), + build_int_cst (long_integer_type_node, 1), true, NULL); + + /* The same for a double-integer type if it is still fast enough. */ + if (TYPE_PRECISION + (long_long_integer_type_node) > TYPE_PRECISION (long_integer_type_node) + && TYPE_PRECISION (long_long_integer_type_node) <= BITS_PER_WORD) + add_candidate (data, build_int_cst (long_long_integer_type_node, 0), + build_int_cst (long_long_integer_type_node, 1), true, NULL); } @@ -2610,6 +2608,14 @@ alloc_use_cost_map (struct ivopts_data *data) } } +/* Returns true if COST is infinite. */ + +static bool +infinite_cost_p (comp_cost cost) +{ + return cost.cost == INFTY; +} + /* Returns description of computation cost of expression whose runtime cost is RUNTIME and complexity corresponds to COMPLEXITY. */ @@ -2629,6 +2635,9 @@ new_cost (unsigned runtime, unsigned complexity) static comp_cost add_costs (comp_cost cost1, comp_cost cost2) { + if (infinite_cost_p(cost1) || infinite_cost_p(cost2)) + return infinite_cost; + gcc_assert (INFTY != cost1.complexity && INFTY != cost2.complexity); cost1.cost += cost2.cost; cost1.complexity += cost2.complexity; @@ -2639,6 +2648,9 @@ add_costs (comp_cost cost1, comp_cost cost2) static comp_cost sub_costs (comp_cost cost1, comp_cost cost2) { + if (infinite_cost_p(cost1) || infinite_cost_p(cost2)) + return infinite_cost; + gcc_assert (INFTY != cost1.complexity && INFTY != cost2.complexity); cost1.cost -= cost2.cost; cost1.complexity -= cost2.complexity; @@ -2651,20 +2663,13 @@ sub_costs (comp_cost cost1, comp_cost cost2) static int compare_costs (comp_cost cost1, comp_cost cost2) { + gcc_assert(! (infinite_cost_p(cost1) || infinite_cost_p(cost2))); if (cost1.cost == cost2.cost) return cost1.complexity - cost2.complexity; return cost1.cost - cost2.cost; } -/* Returns true if COST is infinite. */ - -static bool -infinite_cost_p (comp_cost cost) -{ - return cost.cost == INFTY; -} - /* Sets cost of (USE, CANDIDATE) pair to COST and record that it depends on invariants DEPENDS_ON and that the value used in expressing it is VALUE, and in case of iv elimination the comparison operator is COMP. */ @@ -2773,7 +2778,8 @@ static rtx produce_memory_decl_rtl (tree obj, int *regno) { addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (obj)); - enum machine_mode address_mode = targetm.addr_space.address_mode (as); + enum machine_mode pointer_mode = targetm.type_pointer_mode (TREE_TYPE (obj)); + enum machine_mode address_mode = targetm.type_address_mode (TREE_TYPE (obj)); rtx x; gcc_assert (obj); @@ -2784,6 +2790,7 @@ produce_memory_decl_rtl (tree obj, int *regno) SET_SYMBOL_REF_DECL (x, obj); x = gen_rtx_MEM (DECL_MODE (obj), x); set_mem_addr_space (x, as); + set_mem_pointer_address_modes (x, pointer_mode, address_mode); targetm.encode_section_info (obj, x, true); } else @@ -2791,6 +2798,7 @@ produce_memory_decl_rtl (tree obj, int *regno) x = gen_raw_REG (address_mode, (*regno)++); x = gen_rtx_MEM (DECL_MODE (obj), x); set_mem_addr_space (x, as); + set_mem_pointer_address_modes (x, pointer_mode, address_mode); } return x; @@ -3847,8 +3855,7 @@ difference_cost (struct ivopts_data *data, if (integer_zerop (e1)) { comp_cost cost = force_var_cost (data, e2, depends_on); - cost.cost += multiply_by_cost (-1, mode, data->speed); - return cost; + return add_costs (cost, new_cost (multiply_by_cost (-1, mode, data->speed), 0)); } type = signed_type_for (TREE_TYPE (e1)); @@ -4157,8 +4164,12 @@ get_computation_cost_at (struct ivopts_data *data, ubase, build_int_cst (utype, 0), &symbol_present, &var_present, &offset, depends_on)); - cost.cost /= avg_loop_niter (data->current_loop); - cost.cost += add_cost (TYPE_MODE (ctype), data->speed); + if (!infinite_cost_p (cost)) + { + unsigned adjusted_cost = cost.cost / avg_loop_niter (data->current_loop); + adjusted_cost += add_cost (TYPE_MODE (ctype), data->speed); + cost = new_cost (adjusted_cost, cost.complexity); + } } if (inv_expr_id) @@ -4187,6 +4198,9 @@ get_computation_cost_at (struct ivopts_data *data, speed, stmt_is_after_inc, can_autoinc)); + if (infinite_cost_p (cost)) + return cost; + /* Otherwise estimate the costs for computing the expression. */ if (!symbol_present && !var_present && !offset) { @@ -4295,7 +4309,7 @@ determine_use_iv_cost_address (struct ivopts_data *data, if (cand->ainc_use == use) { - if (can_autoinc) + if (can_autoinc && !infinite_cost_p (cost)) cost.cost -= cand->cost_step; /* If we generated the candidate solely for exploiting autoincrement opportunities, and it turns out it can't be used, set the cost to @@ -4827,10 +4841,11 @@ determine_use_iv_cost_condition (struct ivopts_data *data, bound_cost.cost = parm_decl_cost (data, *bound_cst); else if (TREE_CODE (*bound_cst) == INTEGER_CST) bound_cost.cost = 0; - express_cost.cost += bound_cost.cost; + express_cost = add_costs (express_cost, bound_cost); /* Choose the better approach, preferring the eliminated IV. */ - if (compare_costs (elim_cost, express_cost) <= 0) + if (!infinite_cost_p(elim_cost) && (infinite_cost_p (express_cost) + || compare_costs (elim_cost, express_cost) <= 0)) { cost = elim_cost; depends_on = depends_on_elim; @@ -5215,14 +5230,12 @@ iv_ca_cand_for_use (struct iv_ca *ivs, struct iv_use *use) static void iv_ca_recount_cost (struct ivopts_data *data, struct iv_ca *ivs) { + unsigned cost_for_size; comp_cost cost = ivs->cand_use_cost; - cost.cost += ivs->cand_cost; - - cost.cost += ivopts_global_cost_for_size (data, - ivs->n_regs + ivs->num_used_inv_expr); - - ivs->cost = cost; + cost = add_costs(ivs->cand_use_cost, new_cost (ivs->cand_cost, 0)); + cost_for_size = ivopts_global_cost_for_size (data, ivs->n_regs + ivs->num_used_inv_expr); + ivs->cost = add_costs(cost, new_cost (cost_for_size, 0)); } /* Remove invariants in set INVS to set IVS. */ @@ -5379,6 +5392,8 @@ iv_ca_add_use (struct ivopts_data *data, struct iv_ca *ivs, struct iv_cand *cand = iv_cand (data, i); cp = get_use_iv_cost (data, use, cand); + if (!cp || infinite_cost_p (cp->cost)) + continue; if (cheaper_cost_pair (cp, best_cp)) best_cp = cp; @@ -5767,7 +5782,8 @@ iv_ca_prune (struct ivopts_data *data, struct iv_ca *ivs, acost = iv_ca_narrow (data, ivs, cand, &act_delta); - if (compare_costs (acost, best_cost) < 0) + if (!infinite_cost_p (acost) && (infinite_cost_p (best_cost) + || compare_costs (acost, best_cost) < 0)) { best_cost = acost; iv_ca_delta_free (&best_delta); @@ -5857,7 +5873,8 @@ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs, iv_ca_set_no_cp (data, ivs, use); act_delta = iv_ca_delta_add (use, NULL, cp, act_delta); - if (compare_costs (act_cost, best_cost) < 0) + if (!infinite_cost_p (act_cost) && (infinite_cost_p (best_cost) + || compare_costs (act_cost, best_cost) < 0)) { best_cost = act_cost; @@ -5896,7 +5913,8 @@ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs, act_delta = iv_ca_delta_add (use, iv_ca_cand_for_use (ivs, use), cp, act_delta); - if (compare_costs (act_cost, best_cost) < 0) + if (!infinite_cost_p (act_cost) && (infinite_cost_p (best_cost) + || compare_costs (act_cost, best_cost) < 0)) { best_cost = act_cost; @@ -5957,7 +5975,7 @@ try_improve_iv_set (struct ivopts_data *data, struct iv_ca *ivs) /* If we successfully added the candidate and the set is small enough, try optimizing it by removing other candidates. */ - if (n_ivs <= ALWAYS_PRUNE_CAND_SET_BOUND) + if (!infinite_cost_p (acost) && n_ivs <= ALWAYS_PRUNE_CAND_SET_BOUND) { iv_ca_delta_commit (data, ivs, act_delta, true); acost = iv_ca_prune (data, ivs, cand, &tmp_delta); @@ -5965,7 +5983,8 @@ try_improve_iv_set (struct ivopts_data *data, struct iv_ca *ivs) act_delta = iv_ca_delta_join (act_delta, tmp_delta); } - if (compare_costs (acost, best_cost) < 0) + if (!infinite_cost_p (acost) && (infinite_cost_p (best_cost) + || compare_costs (acost, best_cost) < 0)) { best_cost = acost; iv_ca_delta_free (&best_delta); @@ -6041,12 +6060,12 @@ find_optimal_iv_set (struct ivopts_data *data) origset = find_optimal_iv_set_1 (data, true); set = find_optimal_iv_set_1 (data, false); - if (!origset && !set) - return NULL; - origcost = origset ? iv_ca_cost (origset) : infinite_cost; cost = set ? iv_ca_cost (set) : infinite_cost; + if (infinite_cost_p (origcost) && infinite_cost_p (cost)) + return NULL; + if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Original cost %d (complexity %d)\n\n", @@ -6056,7 +6075,8 @@ find_optimal_iv_set (struct ivopts_data *data) } /* Choose the one with the best cost. */ - if (compare_costs (origcost, cost) <= 0) + if (!infinite_cost_p (origcost) && (infinite_cost_p (cost) + || compare_costs (origcost, cost) <= 0)) { if (set) iv_ca_free (&set); @@ -6177,8 +6197,8 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data, gcc_assert (gimple_assign_lhs (use->stmt) == cand->var_after); step = cand->iv->step; - ctype = TREE_TYPE (step); utype = TREE_TYPE (cand->var_after); + ctype = generic_type_for (utype); if (TREE_CODE (step) == NEGATE_EXPR) { incr_code = MINUS_EXPR; @@ -6215,8 +6235,9 @@ rewrite_use_nonlinear_expr (struct ivopts_data *data, the iv. */ op = fold_convert (ctype, cand->var_before); comp = fold_convert (utype, - build2 (incr_code, ctype, op, - unshare_expr (step))); + fold_build2 (incr_code, ctype, op, + fold_convert (ctype, + unshare_expr (step)))); } else { diff --git gcc-4.7.0.orig/gcc/tree.c gcc-4.7.0/gcc/tree.c index fa01583..d470c44 100644 --- gcc-4.7.0.orig/gcc/tree.c +++ gcc-4.7.0/gcc/tree.c @@ -7100,9 +7100,7 @@ build_pointer_type_for_mode (tree to_type, enum machine_mode mode, tree build_pointer_type (tree to_type) { - addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC - : TYPE_ADDR_SPACE (to_type); - enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as); + enum machine_mode pointer_mode = targetm.type_pointer_mode (to_type); return build_pointer_type_for_mode (to_type, pointer_mode, false); } @@ -7167,9 +7165,7 @@ build_reference_type_for_mode (tree to_type, enum machine_mode mode, tree build_reference_type (tree to_type) { - addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC - : TYPE_ADDR_SPACE (to_type); - enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as); + enum machine_mode pointer_mode = targetm.type_pointer_mode (to_type); return build_reference_type_for_mode (to_type, pointer_mode, false); } @@ -9251,17 +9247,23 @@ build_common_tree_nodes (bool signed_char, bool short_double) TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1); TYPE_PRECISION (boolean_type_node) = 1; + targetm.build_common_tree_nodes(); + /* Define what type to use for size_t. */ - if (strcmp (SIZE_TYPE, "unsigned int") == 0) - size_type_node = unsigned_type_node; - else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) - size_type_node = long_unsigned_type_node; - else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) - size_type_node = long_long_unsigned_type_node; - else if (strcmp (SIZE_TYPE, "short unsigned int") == 0) - size_type_node = short_unsigned_type_node; - else - gcc_unreachable (); + size_type_node = targetm.size_type_tree(); + if (!size_type_node) + { + if (strcmp (SIZE_TYPE, "unsigned int") == 0) + size_type_node = unsigned_type_node; + else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) + size_type_node = long_unsigned_type_node; + else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0) + size_type_node = long_long_unsigned_type_node; + else if (strcmp (SIZE_TYPE, "short unsigned int") == 0) + size_type_node = short_unsigned_type_node; + else + gcc_unreachable (); + } /* Fill in the rest of the sized types. Reuse existing type nodes when possible. */ @@ -10162,32 +10164,26 @@ widest_int_cst_value (const_tree x) return val; } -/* If TYPE is an integral type, return an equivalent type which is - unsigned iff UNSIGNEDP is true. If TYPE is not an integral type, - return TYPE itself. */ +/* If TYPE is an integral or pointer type, return an integer type with + the same precision which is unsigned iff UNSIGNEDP is true, or itself + if TYPE is already an integer type of signedness UNSIGNEDP. */ tree signed_or_unsigned_type_for (int unsignedp, tree type) { - tree t = type; - if (POINTER_TYPE_P (type)) - { - /* If the pointer points to the normal address space, use the - size_type_node. Otherwise use an appropriate size for the pointer - based on the named address space it points to. */ - if (!TYPE_ADDR_SPACE (TREE_TYPE (t))) - t = size_type_node; - else - return lang_hooks.types.type_for_size (TYPE_PRECISION (t), unsignedp); - } + if (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type) == unsignedp) + return type; - if (!INTEGRAL_TYPE_P (t) || TYPE_UNSIGNED (t) == unsignedp) - return t; + if (!INTEGRAL_TYPE_P (type) + && !POINTER_TYPE_P (type)) + return NULL_TREE; - return lang_hooks.types.type_for_size (TYPE_PRECISION (t), unsignedp); + return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); } -/* Returns unsigned variant of TYPE. */ +/* If TYPE is an integral or pointer type, return an integer type with + the same precision which is unsigned, or itself if TYPE is already an + unsigned integer type. */ tree unsigned_type_for (tree type) @@ -10195,7 +10191,9 @@ unsigned_type_for (tree type) return signed_or_unsigned_type_for (1, type); } -/* Returns signed variant of TYPE. */ +/* If TYPE is an integral or pointer type, return an integer type with + the same precision which is signed, or itself if TYPE is already a + signed integer type. */ tree signed_type_for (tree type) diff --git gcc-4.7.0.orig/gcc/var-tracking.c gcc-4.7.0/gcc/var-tracking.c index c6280e2..8c7e081 100644 --- gcc-4.7.0.orig/gcc/var-tracking.c +++ gcc-4.7.0/gcc/var-tracking.c @@ -4904,7 +4904,7 @@ get_address_mode (rtx mem) enum machine_mode mode = GET_MODE (XEXP (mem, 0)); if (mode != VOIDmode) return mode; - return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); + return MEM_ADDRESS_MODE (mem); } /* Replace all registers and addresses in an expression with VALUE diff --git gcc-4.7.0.orig/gcc/varasm.c gcc-4.7.0/gcc/varasm.c index 79c81fa..4c3cfc6 100644 --- gcc-4.7.0.orig/gcc/varasm.c +++ gcc-4.7.0/gcc/varasm.c @@ -659,6 +659,12 @@ unlikely_text_section_p (section *sect) return sect == function_section_1 (current_function_decl, true); } +const char * +default_decl_mergeable_rodata_prefix (tree decl ATTRIBUTE_UNUSED) +{ + return targetm.asm_out.mergeable_rodata_prefix; +} + /* Return the read-only data section associated with function DECL. */ section * @@ -742,7 +748,7 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED, const char *str; HOST_WIDE_INT i; int j, unit; - const char *prefix = targetm.asm_out.mergeable_rodata_prefix; + const char *prefix = targetm.asm_out.decl_mergeable_rodata_prefix (decl); char *name = (char *) alloca (strlen (prefix) + 30); mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (decl))); @@ -994,7 +1000,7 @@ align_variable (tree decl, bool dont_output_data) section should be used wherever possible. */ section * -get_variable_section (tree decl, bool prefer_noswitch_p) +default_variable_section (tree decl, bool prefer_noswitch_p) { addr_space_t as = ADDR_SPACE_GENERIC; int reloc; @@ -1070,7 +1076,7 @@ get_block_for_decl (tree decl) an object block if it requires a standalone definition. */ if (TREE_CODE (decl) == VAR_DECL) align_variable (decl, 0); - sect = get_variable_section (decl, true); + sect = targetm.asm_out.variable_section (decl, true); if (SECTION_STYLE (sect) == SECTION_NOSWITCH) return NULL; @@ -1294,10 +1300,7 @@ make_decl_rtl (tree decl) { enum machine_mode address_mode = Pmode; if (TREE_TYPE (decl) != error_mark_node) - { - addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); - address_mode = targetm.addr_space.address_mode (as); - } + address_mode = targetm.type_address_mode (TREE_TYPE (decl)); x = gen_rtx_SYMBOL_REF (address_mode, name); } SYMBOL_REF_WEAK (x) = DECL_WEAK (decl); @@ -2025,7 +2028,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, targetm.asm_out.mark_decl_preserved (name); /* First make the assembler name(s) global if appropriate. */ - sect = get_variable_section (decl, false); + sect = targetm.asm_out.variable_section (decl, false); if (TREE_PUBLIC (decl) && (sect->common.flags & SECTION_COMMON) == 0) globalize_decl (decl); @@ -4477,9 +4480,9 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) resolving it. */ if (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) - && targetm.addr_space.valid_pointer_mode + && targetm.type_valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp)), - TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) + TREE_TYPE (TREE_TYPE (exp)))) { tree saved_type = TREE_TYPE (exp); @@ -4487,9 +4490,9 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) pointer modes. */ while (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) - && targetm.addr_space.valid_pointer_mode + && targetm.type_valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp)), - TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) + TREE_TYPE (TREE_TYPE (exp)))) exp = TREE_OPERAND (exp, 0); /* If what we're left with is the address of something, we can diff --git gcc-4.7.0.orig/gcc/varpool.c gcc-4.7.0/gcc/varpool.c index c2d88c3..73e4c6b 100644 --- gcc-4.7.0.orig/gcc/varpool.c +++ gcc-4.7.0/gcc/varpool.c @@ -629,7 +629,7 @@ varpool_finalize_named_section_flags (struct varpool_node *node) && TREE_CODE (node->decl) == VAR_DECL && !DECL_HAS_VALUE_EXPR_P (node->decl) && DECL_SECTION_NAME (node->decl)) - get_variable_section (node->decl, false); + targetm.asm_out.variable_section (node->decl, false); } /* Output all variables enqueued to be assembled. */ diff --git gcc-4.7.0.orig/libgcc/config.host gcc-4.7.0/libgcc/config.host index 257622a..c7dad72 100644 --- gcc-4.7.0.orig/libgcc/config.host +++ gcc-4.7.0/libgcc/config.host @@ -393,6 +393,10 @@ avr-*-*) tmake_file="${cpu_type}/t-avr t-fpbit" tm_file="$tm_file avr/avr-lib.h" ;; +msp430-*-*) + tmake_file="${cpu_type}/t-msp430" + extra_parts="$extra_parts libcrt0.a libcrt0dwdt.a crt0ivtbl16.o crt0ivtbl32.o crt0ivtbl64.o" + ;; bfin*-elf*) tmake_file="bfin/t-bfin bfin/t-crtlibid bfin/t-crtstuff t-libgcc-pic t-fdpbit" extra_parts="$extra_parts crtbeginS.o crtendS.o crti.o crtn.o crtlibid.o" diff --git gcc-4.7.0.orig/libgcc/config/msp430/crt0.S gcc-4.7.0/libgcc/config/msp430/crt0.S new file mode 100644 index 0000000..6a70ac8 --- /dev/null +++ gcc-4.7.0/libgcc/config/msp430/crt0.S @@ -0,0 +1,349 @@ +/* -*- Mode: Asm -*- */ +#if WITH_DISABLE_WDT +#define WDTIMER_KICK +#else /* WITH_DISABLE_WDT */ +#define WDTIMER_KICK \ + mov &__wdt_clear_value, &__WDTCTL +#endif /* WITH_DISABLE_WDT */ + +#if __MSP430X__ & __MSP430_CPUX_TARGET_C20__ +#define CALLX calla +#define RETX reta +#else /* C20 */ +#define CALLX call +#define RETX ret +#endif /* C20 */ + +#if __MSP430X__ - 0 + .cpux_target bits=__MSP430X__ ; Encode build options for link-time validation +#endif /* __MSP430X__ */ + +/******* CRT support functions *********/ + +/* The following sections are arranged in exactly this order by the loader, + * right before the text region. + ;; .init0 (_reset_vector__: Start here after reset) + ;; .init1 (User definable) + ;; .init2 (__init_stack: Initialize stack) + ;; .init3 (__low_level_init: Initialize hardware; user definable) + ;; .init4 (__do_copy_data; __do_clear_bss: Copy data to .data, clear bss) + ;; .init5 (User definable) + ;; .init6 (__do_global_ctors: C++ constructors) + ;; .init7 (User definable) + ;; .init8 (User definable) + ;; .init9 (main) + ;; .fini9 (__stop_progExec__: Falls into here after main(). User definable) + ;; .fini8 (User definable) + ;; .fini7 (User definable) + ;; .fini6 (C++ destructors) + ;; .fini5 (User definable) + ;; .fini4 (User definable) + ;; .fini3 (User definable) + ;; .fini2 (User definable) + ;; .fini1 (User definable) + ;; .fini0 (_endless_loop__: Infinite loop after program termination) + +NOTE: If you override any of the startup functions, ensure you put the + replacement in the correct section. +*/ + +#if defined(L_reset_vector__) +/***************************************************************** + * Program starts here. + * overwriting this label in the user program + * causes removing all startup code except __do_global_ctors + *****************************************************************/ + .section .init0, "ax", @progbits + + .global _reset_vector__ + .weak _reset_vector__ + + .func _reset_vector__ + + ;; .init0 (Start here after reset) +_reset_vector__: + + ;; .init1 (Initialize watchdog support) + .global __watchdog_support + ;; .init2 (Initialize stack) + .global __init_stack + ;; .init3 (Initialize hardware: user definable) + .global __low_level_init + ;; .init4 (Copy data to .data, clear bss) + .global __do_copy_data + .global __do_clear_bss + ;; .init5 (User definable) + ;; .init6 (C++ constructors) + /* .global __do_global_ctors ; Do not reference unless ctors exist */ + ;; .init7 (User definable) + ;; .init8 (User definable) + ;; .init9 (Main routine) + + ;; compiler places the main routine in .init9 unless it is "hosted" + + ;; .fini9 (__stop_progExec__: Falls into here after .init9. User definable) + .global __stop_progExec__ + ;; .fini8 (User definable) + ;; .fini7 (User definable) + ;; .fini6 (C++ destructors) + /* .global __do_global_dtors ; Do not reference unless dtors exist */ + ;; .fini5 (User definable) + ;; .fini4 (User definable) + ;; .fini3 (User definable) + ;; .fini2 (User definable) + ;; .fini1 (User definable) + ;; .fini0 (_endless_loop__: Infinite loop after program termination) + .global _endless_loop__ + + .endfunc +#endif /* defined(L_reset_vector__) */ + +#if defined(L__watchdog_support) +/***************************************************************** + * Initialize watchdog support + * Depending on variant selected, watchdog is disabled or its restart + * value is loaded into __wdt_clear_value for use throughout execution + *****************************************************************/ + .section .init1, "ax", @progbits + + .global __watchdog_support + .weak __watchdog_support + + .func __watchdog_support + +__watchdog_support: +#if WITH_DISABLE_WDT + mov #0x5a80, &__WDTCTL +#else /* WITH_DISABLE_WDT */ + mov.b &__WDTCTL, r5 + bis #0x5a08, r5 + mov r5, &__wdt_clear_value +#endif /* WITH_DISABLE_WDT */ + .endfunc + +#if ! WITH_DISABLE_WDT + .section .noinit.crt0,"aw",@nobits + .p2align 1,0 + .type __wdt_clear_value,@object + .size __wdt_clear_value,2 + .global __wdt_clear_value +__wdt_clear_value: + .skip 2,0 +#endif /* WITH_DISABLE_WDT */ + +#endif + +#if defined(L__init_stack) +/***************************************************************** + * Set stack pointer + * can be overwriten + stack can be initialized in main() prologue, + but setting stack pointer here allows to call subroutines + from startup code and call constructors of statically allocated C++ objects. + Stack pointer will have the same value entering main() as here, + so -mno-stack-init can be used to reduce code size. + initial stack value can be set in ld script as __stack symbol + (end of RAM by default), or via -defsym __stack=
ld option + or via -Wl,defsym,__stack=
gcc option, or by redefining + __init_stack function as follows: + +#if defined (__cplusplus) +extern "C" +endif +__attribute__((__naked__)) __attribute__((section(".init2"))) void __init_stack() +{ + asm volatile("\tmov\t#stack_addr, r1\n"); +} + + *****************************************************************/ + .section .init2, "ax", @progbits + + .global __init_stack + .weak __init_stack + + .func __init_stack + +__init_stack: + mov #__stack, r1 + + .endfunc +#endif + +#if defined(L__low_level_init) +/***************************************************************** + * Initialize peripherals + * Available for user override + *****************************************************************/ + .section .init3, "ax", @progbits + + .global __low_level_init + .weak __low_level_init + + .func __low_level_init + +__low_level_init: + .endfunc +#endif + +#if defined(L_copy_data) +/***************************************************************** + * Initialize data: copy data + * from __data_load_start ( = _etext) to __data_start + * can be overwriten + *****************************************************************/ + .section .init4, "ax", @progbits + + .global __do_copy_data + .weak __do_copy_data + + .func __do_copy_data + +__do_copy_data: + mov #__data_size, r15 + tst r15 + jz .L__copy_data_end +.L__copy_data_loop: + WDTIMER_KICK + decd r15 + mov.w __data_load_start(r15), __data_start(r15) ; data section is word-aligned, so word transfer is acceptable + jne .L__copy_data_loop +.L__copy_data_end: + + .endfunc +#endif /* defined(L_copy_data) */ + +#if defined(L_clear_bss) +/***************************************************************** + * Initialize data: clear .bss + * can be overwriten + *****************************************************************/ + .section .init4, "ax", @progbits + + .global __do_clear_bss + .weak __do_clear_bss + + .func __do_clear_bss + +__do_clear_bss: + mov #__bss_size, r15 + tst r15 + jz .L__clear_bss_end +.L__clear_bss_loop: + WDTIMER_KICK + dec r15 + clr.b __bss_start(r15) + jne .L__clear_bss_loop +.L__clear_bss_end: + + .endfunc +#endif /* defined(L_clear_bss) */ + +#if defined(L__stop_progExec__) +/***************************************************************** + * Execute after main returns + * Default implementation does nothing + *****************************************************************/ + .section .fini9, "ax", @progbits + .global __stop_progExec__ + .weak __stop_progExec__ + + .func __stop_progExec__ +__stop_progExec__: + .endfunc + +#endif + +#if defined(L_endless_loop__) +/***************************************************************** + * Placed at end of CRT code unless overridden + * Default implementation loops entering LPM4, leaving GIE unchanged + *****************************************************************/ + .section .fini0, "ax", @progbits + + .global _endless_loop__ + .weak _endless_loop__ + .func _endless_loop__ + +_endless_loop__: + bis #0xf0, r2 + jmp _endless_loop__ + + .endfunc + +#endif /* defined(L_endless_loop__) */ + +#if defined(L_ctors430) +/***************************************************************** + * Call constructor functions. + * + * No reference to this should be generated unless a function pointer + * is added to the .ctors section. This means that the code will + * be absent from the executable unless at least one pointer is + * present, which also means we don't have to check for an empty + * function list. + *****************************************************************/ + .section .init6, "ax", @progbits + .global __do_global_ctors + .weak __do_global_ctors + + .func __do_global_ctors + +__do_global_ctors: + mov #__ctors_start, r11 + mov #__ctors_end, r10 +.L__ctors_loop: + WDTIMER_KICK + CALLX @r11+ ; call constructor + cmp r10, r11 + jne .L__ctors_loop + + .endfunc +#endif + +#if defined(L_dtors430) +/***************************************************************** + * Call destructor functions. + * + * No reference to this should be generated unless a function pointer + * is added to the .dtors section. This means that the code will + * be absent from the executable unless at least one pointer is + * present, which also means we don't have to check for an empty + * function list. + *****************************************************************/ + .section .fini6,"ax",@progbits + .global __do_global_dtors + .weak __do_global_dtors + + .func __do_global_dtors + +__do_global_dtors: + mov #__dtors_start, r11 + mov #__dtors_end, r10 +.L__dtors_loop: + WDTIMER_KICK + CALLX @r11+ + cmp r10, r11 + jne .L__dtors_loop + + .endfunc +#endif + +#if defined(L_unexpected_) + +/***************************************************************** + * unexpected interrupt vector handler + * can be overwriten by user function with the same name: + * void _unexpected_ __attribute__((interrupt)) { } + * + *****************************************************************/ + + .section .text.crt0, "ax", @progbits + + .global _unexpected_ + .weak _unexpected_ + + .p2align 1,0 +_unexpected_: + reti + +#endif diff --git gcc-4.7.0.orig/libgcc/config/msp430/crt0ivtbl.S gcc-4.7.0/libgcc/config/msp430/crt0ivtbl.S new file mode 100644 index 0000000..1feb18a --- /dev/null +++ gcc-4.7.0/libgcc/config/msp430/crt0ivtbl.S @@ -0,0 +1,156 @@ +/* -*- Mode: Asm -*- */ + +#if __MSP430X__ - 0 + .cpux_target bits=__MSP430X__ ; Encode build options for link-time validation +#endif /* __MSP430X__ */ + + .section .text.crt0, "ax", @progbits + +/*************************************************************** + * Interrupt Vectors: + * WARNING!!! All vectors must be defined here!!! + * User may not define its interrupt service routines! + ***************************************************************/ + +.macro INITIALIZE_VTE_SLOT sn + .global __vte_\sn + .word __vte_\sn +.endm + +.macro INITIALIZE_ISR_SLOT sn + .weak __isr_\sn + .equ __isr_\sn, __br_unexpected_ + .word __isr_\sn +.endm + +.macro DEFINE_IVTABLE _n + .global __ivtbl_\_n + .type __ivtbl_\_n, @object + .size __ivtbl_\_n, 2*\_n +__ivtbl_\_n: +.endm + +.text + .p2align 1,0 +__br_unexpected_: + br #_unexpected_ + + .global _unexpected_ + .global _reset_vector__ + + .section .vectors, "ax", @progbits + +DEFINE_IVTABLE INTERRUPT_VECTOR_COUNT + +#if 32 >= INTERRUPT_VECTOR_COUNT + INITIALIZE_ISR_SLOT 0 + INITIALIZE_ISR_SLOT 1 + INITIALIZE_ISR_SLOT 2 + INITIALIZE_ISR_SLOT 3 + INITIALIZE_ISR_SLOT 4 + INITIALIZE_ISR_SLOT 5 + INITIALIZE_ISR_SLOT 6 + INITIALIZE_ISR_SLOT 7 + INITIALIZE_ISR_SLOT 8 + INITIALIZE_ISR_SLOT 9 + INITIALIZE_ISR_SLOT 10 + INITIALIZE_ISR_SLOT 11 + INITIALIZE_ISR_SLOT 12 + INITIALIZE_ISR_SLOT 13 + INITIALIZE_ISR_SLOT 14 +#if 16 < INTERRUPT_VECTOR_COUNT + INITIALIZE_ISR_SLOT 15 + INITIALIZE_ISR_SLOT 16 + INITIALIZE_ISR_SLOT 17 + INITIALIZE_ISR_SLOT 18 + INITIALIZE_ISR_SLOT 19 + INITIALIZE_ISR_SLOT 20 + INITIALIZE_ISR_SLOT 21 + INITIALIZE_ISR_SLOT 22 + INITIALIZE_ISR_SLOT 23 + INITIALIZE_ISR_SLOT 24 + INITIALIZE_ISR_SLOT 25 + INITIALIZE_ISR_SLOT 26 + INITIALIZE_ISR_SLOT 27 + INITIALIZE_ISR_SLOT 28 + INITIALIZE_ISR_SLOT 29 + INITIALIZE_ISR_SLOT 30 +#endif /* 16 < INTERRUPT_VECTOR_COUNT */ +#else /* 32 >= INTERRUPT_VECTOR_COUNT */ +/* SF 3540953 fram applications overwrite bsl/jtag passwords + * SF 3554291 refine FRAM ISR fix + * + * No current MSP430 chip has more than 25 valid interrupts, and they + * are assigned from the top down. The FRAM chips use lower words in + * the interrupt vector to hold BSL and JTAG passwords, and having + * real addresses in those locations has been shown to result in + * problems accessing BSL and JTAG. For these MCUs, allow the lower + * 32 vector table entry values to be independently assigned. The + * default value is 0xFFFF, corresponding to the erased state, and + * is provided in the primary linker script in binutils when no + * entry-specific value is provided. */ + INITIALIZE_VTE_SLOT 0 + INITIALIZE_VTE_SLOT 1 + INITIALIZE_VTE_SLOT 2 + INITIALIZE_VTE_SLOT 3 + INITIALIZE_VTE_SLOT 4 + INITIALIZE_VTE_SLOT 5 + INITIALIZE_VTE_SLOT 6 + INITIALIZE_VTE_SLOT 7 + INITIALIZE_VTE_SLOT 8 + INITIALIZE_VTE_SLOT 9 + INITIALIZE_VTE_SLOT 10 + INITIALIZE_VTE_SLOT 11 + INITIALIZE_VTE_SLOT 12 + INITIALIZE_VTE_SLOT 13 + INITIALIZE_VTE_SLOT 14 + INITIALIZE_VTE_SLOT 15 + INITIALIZE_VTE_SLOT 16 + INITIALIZE_VTE_SLOT 17 + INITIALIZE_VTE_SLOT 18 + INITIALIZE_VTE_SLOT 19 + INITIALIZE_VTE_SLOT 20 + INITIALIZE_VTE_SLOT 21 + INITIALIZE_VTE_SLOT 22 + INITIALIZE_VTE_SLOT 23 + INITIALIZE_VTE_SLOT 24 + INITIALIZE_VTE_SLOT 25 + INITIALIZE_VTE_SLOT 26 + INITIALIZE_VTE_SLOT 27 + INITIALIZE_VTE_SLOT 28 + INITIALIZE_VTE_SLOT 29 + INITIALIZE_VTE_SLOT 30 + INITIALIZE_VTE_SLOT 31 + INITIALIZE_ISR_SLOT 32 + INITIALIZE_ISR_SLOT 33 + INITIALIZE_ISR_SLOT 34 + INITIALIZE_ISR_SLOT 35 + INITIALIZE_ISR_SLOT 36 + INITIALIZE_ISR_SLOT 37 + INITIALIZE_ISR_SLOT 38 + INITIALIZE_ISR_SLOT 39 + INITIALIZE_ISR_SLOT 40 + INITIALIZE_ISR_SLOT 41 + INITIALIZE_ISR_SLOT 42 + INITIALIZE_ISR_SLOT 43 + INITIALIZE_ISR_SLOT 44 + INITIALIZE_ISR_SLOT 45 + INITIALIZE_ISR_SLOT 46 + INITIALIZE_ISR_SLOT 47 + INITIALIZE_ISR_SLOT 48 + INITIALIZE_ISR_SLOT 49 + INITIALIZE_ISR_SLOT 50 + INITIALIZE_ISR_SLOT 51 + INITIALIZE_ISR_SLOT 52 + INITIALIZE_ISR_SLOT 53 + INITIALIZE_ISR_SLOT 54 + INITIALIZE_ISR_SLOT 55 + INITIALIZE_ISR_SLOT 56 + INITIALIZE_ISR_SLOT 57 + INITIALIZE_ISR_SLOT 58 + INITIALIZE_ISR_SLOT 59 + INITIALIZE_ISR_SLOT 60 + INITIALIZE_ISR_SLOT 61 + INITIALIZE_ISR_SLOT 62 +#endif /* 32 < INTERRUPT_VECTOR_COUNT */ + .word _reset_vector__ diff --git gcc-4.7.0.orig/libgcc/config/msp430/libgcc.S gcc-4.7.0/libgcc/config/msp430/libgcc.S new file mode 100644 index 0000000..88e3f55 --- /dev/null +++ gcc-4.7.0/libgcc/config/msp430/libgcc.S @@ -0,0 +1,1635 @@ +/* -*- Mode: Asm -*- */ + +/* Routines with __ext_ are extensions that differ from the + * similarly-named libgcc standard routine in either name or calling + * convention. + * + * Routines with __xabi_ use an extended ABI where some input and + * output parameters are passed in registers that are normally + * reserved for caller-saved. These routines are still responsible + * for preserving the values in any register that is not used for + * either an input or an output of the function. __xabi_ routines are + * implicitly __ext_ routines. */ + + +/* Offset in bytes from r1 to first word of stack-pushed arguments. */ +#if __MSP430X__ & __MSP430_CPUX_TARGET_C20__ +#define ARGP_OFFSET 4 +#else +#define ARGP_OFFSET 2 +#endif + +/* Size in bytes of each saved register */ +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ +#define SAVEREG_SIZE 4 +#else /* SR20 */ +#define SAVEREG_SIZE 2 +#endif /* SR20 */ + +/* Genericized call and return instructions */ +#if __MSP430X__ & __MSP430_CPUX_TARGET_C20__ +#define CALLX calla +#define RETX reta +#else /* C20 */ +#define CALLX call +#define RETX ret +#endif /* C20 */ + +/* Return a reference to the _aw'th byte on the stack above the _nsr + * callee-saved registers. */ +#define ARG_REFERENCE(_nsr,_aw) (_nsr)*SAVEREG_SIZE+(_aw)+ARGP_OFFSET(r1) + +#if __MSP430X__ - 0 + .cpux_target bits=__MSP430X__ ; Encode build options for link-time validation +#endif /* __MSP430X__ */ + + .section .text.libgcc, "ax", @progbits + +#if defined (L_cmpsi2) + + .global __cmpsi2 + .func __cmpsi2 +__cmpsi2: + sub r12, r14 + subc r13, r15 + jge .L_ge + mov #0, r15 ; a < b return 0 + RETX + +.L_ge: + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + RETX +.L_eq: + mov #1, r15 ; a == b return 1 + RETX +.endfunc +#endif + +#if defined (L_ucmpsi2) + + .global __ucmpsi2 + .func __ucmpsi2 +__ucmpsi2: + sub r12, r14 + subc r13, r15 + jhs .L_ge + mov #0, r15 ; a < b return 0 + RETX + +.L_ge: + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + RETX +.L_eq: + mov #1, r15 ; a == b return 1 + RETX +.endfunc +#endif + +#if defined (L_cmpdi2) + .global __cmpdi2 + .func __cmpdi2 +__cmpdi2: + sub ARG_REFERENCE(0,0), r12 + subc ARG_REFERENCE(0,2), r13 + subc ARG_REFERENCE(0,4), r14 + subc ARG_REFERENCE(0,6), r15 + jge .L_ge + mov #0, r15 ; a < b return 0 + RETX + +.L_ge: + bis r12, r15 + bis r13, r15 + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + RETX +.L_eq: + mov #1, r15 ; a == b return 1 + RETX +.endfunc +#endif + +#if defined (L_ucmpdi2) + + .global __ucmpdi2 + .func __ucmpdi2 +__ucmpdi2: + sub ARG_REFERENCE(0,0), r12 + subc ARG_REFERENCE(0,2), r13 + subc ARG_REFERENCE(0,4), r14 + subc ARG_REFERENCE(0,6), r15 + jhs .L_ge + mov #0, r15 ; a < b return 0 + RETX + +.L_ge: + bis r12, r15 + bis r13, r15 + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + RETX +.L_eq: + mov #1, r15 ; a == b return 1 + RETX +.endfunc +#endif + + +/******************************************************* + Multiplication 8 x 8 +*******************************************************/ +#if defined (L_mulqi3) + .global __mulqi3 + .func __mulqi3 +__mulqi3: + mov.b r15, r13 + clr r15 +1: tst.b r14 + jz 3f + rrc.b r13 + jnc 2f + add.b r14, r15 +2: rla.b r14 + tst.b r13 + jne 1b +3: RETX + .endfunc +#endif /* defined (L_mulqi3) */ + + +#if defined (L_mulqihi3) + .global __mulqihi3 + .func __mulqihi3 +__mulqihi3: + sxt r14 + sxt r15 + br #__mulhi3 +.endfunc +#endif /* defined (L_mulqihi3) */ + +#if defined (L_umulqihi3) + .global __umulqihi3 + .func __umulqihi3 +__umulqihi3: + mov.b r14, r14 + mov.b r15, r15 + br #__mulhi3 + .endfunc +#endif /* defined (L_umulqihi3) */ + +/******************************************************* + Multiplication 16 x 16 +*******************************************************/ +#if defined (L_mulhi3) + .global __mulhi3 + .func __mulhi3 +__mulhi3: + mov r15, r13 + clr r15 +1: tst r14 + jz 3f +#if __MSP430X__ + rrum #1, r13 +#else /* CPUX */ + clrc + rrc r13 +#endif /* CPUX */ + jnc 2f + add r14, r15 +2: rla r14 + tst r13 + jne 1b +3: RETX + .endfunc +#endif /* defined (L_mulhi3) */ + +#if defined (L_mulhisi3) + .global __mulhisi3 + .func __mulhisi3 +__mulhisi3: + mov r14, r12 + mov r15, r14 + clr r15 + tst r14 + jge 1f + mov #-1, r15 +1: clr r13 + tst r12 + jge 2f + mov #-1, r13 +2: br #__mulsi3 + .endfunc +#endif /* defined (L_mulhisi3) */ + +#if defined (L_umulhisi3) + .global __umulhisi3 + .func __umulhisi3 +__umulhisi3: + mov r14, r12 + mov r15, r14 + clr r13 + clr r15 + br #__mulsi3 + .endfunc +#endif /* defined (L_umulhisi3) */ + +#if defined (L_mulsi3) +/******************************************************* + Multiplication 32 x 32 +*******************************************************/ + .global __mulsi3 + .func __mulsi3 + +__mulsi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #2, r11 +#elif __MSP430X__ + pushm #2, r11 +#else /* CPUX */ + push r11 + push r10 +#endif /* CPUX */ + clr r11 + clr r10 + jmp 3f +1: ; b >>= 1 +#if __MSP430X__ + rrum #1, r13 +#else /* CPUX */ + clrc + rrc r13 +#endif /* CPUX */ + rrc r12 + jnc 2f + add r14, r10 ; res = res + a + addc r15, r11 +2: rla r14 + rlc r15 ; a <<= 1 +3: tst r12 ; stop if b zero + jnz 1b + tst r13 + jnz 1b + mov r10, r14 + mov r11, r15 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #2, r11 +#elif __MSP430X__ + popm #2, r11 +#else /* CPUX */ + pop r10 + pop r11 +#endif /* CPUX */ + RETX + .endfunc + +#endif + +#if defined (L_mulsidi3) + .global __mulsidi3 + .func __mulsidi3 + +__mulsidi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #8, r11 +#elif __MSP430X__ + pushm #8, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 + push r7 + push r6 + push r5 + push r4 +#endif /* CPUX */ + + mov r12, r8 + mov r13, r9 + mov #0, r10 + tst r9 + jge 1f + mov #-1, r10 +1: mov r10, r11 + mov r14, r12 + mov r15, r13 + mov #0, r14 + tst r13 + jge 2f + mov #-1, r14 +2: mov r14, r15 + CALLX #__xabi_muldi3 + +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #8, r11 +#elif __MSP430X__ + popm #8, r11 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + .endfunc +#endif + +#if defined (L_umulsidi3) + .global __umulsidi3 + .func __umulsidi3 + +__umulsidi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #8, r11 +#elif __MSP430X__ + pushm #8, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 + push r7 + push r6 + push r5 + push r4 +#endif /* CPUX */ + + mov r12, r8 + mov r13, r9 + mov #0, r10 + mov #0, r11 + mov r14, r12 + mov r15, r13 + mov #0, r14 + mov #0, r15 + + CALLX #__xabi_muldi3 + +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #8, r11 +#elif __MSP430X__ + popm #8, r11 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + .endfunc + +#endif + +#if defined (L_muldi3) +/******************************************************* + Multiplication 64 x 64 +*******************************************************/ + + .global __muldi3 + .func __muldi3 + +__muldi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #8, r11 +#elif __MSP430X__ + pushm #8, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 + push r7 + push r6 + push r5 + push r4 +#endif /* CPUX */ + + mov ARG_REFERENCE(8,0), r8 ; load b + mov ARG_REFERENCE(8,2), r9 + mov ARG_REFERENCE(8,4), r10 + mov ARG_REFERENCE(8,6), r11 + CALLX #__xabi_muldi3 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #8, r11 +#elif __MSP430X__ + popm #8, r11 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + .endfunc + + .global __xabi_muldi3 + .func __xabi_muldi3 +__xabi_muldi3: + clr r4 ; clear result + clr r5 + clr r6 + clr r7 + jmp 3f +1: ; b >>= 1 +#if __MSP430X__ + rrum #1, r11 +#else /* CPUX */ + clrc + rrc r11 +#endif /* CPUX */ + rrc r10 + rrc r9 + rrc r8 + jnc 2f + add r12, r4 ; res = res + a + addc r13, r5 + addc r14, r6 + addc r15, r7 +2: rla r12 ; a <<= 1 + rlc r13 + rlc r14 + rlc r15 +3: tst r8 ; stop if b zero + jnz 1b + tst r9 + jnz 1b + tst r10 + jnz 1b + tst r11 + jnz 1b + mov r4, r12 + mov r5, r13 + mov r6, r14 + mov r7, r15 + + RETX +#endif + +/* Unsigned division uses a non-performing restoring division + * algorithm. Signed division uses the same routine after converting + * numerator and divisor if negative, then adjusts the sign of the + * remainder to match the origin sign of the numerator, and negates + * the quotient if exactly one of the numerator and divisor was + * negative. + * + * The extension routines that do the real work place the return + * values under the assumption that the quotient is the most used + * value. This way the library routines for __divm3 can often alias + * directly to the extension routine. */ + +#if defined (L_udivmod8) + + .global __udivqi3 + .type __udivqi3, @function + .global __ext_udivmod8 + .func __ext_udivmod8 +__ext_udivmod8: +__udivqi3: + ;; r15 = N in ; Q out + ;; r14 = D in ; A = R out + ;; r13 = M + ;; r12 = count + mov.b #8, r12 ; set count + mov.b r14, r13 ; M := D + clr r14 ; A := 0 +1: rla.b r15 ; left shift Q ... + rlc.b r14 ; ... into left shift A + cmp.b r13, r14 ; M > A? + jlo 2f ; yes, skip adjustment + sub.b r13, r14 ; no, A := A - M + bis.b #1, r15 ; set Qi +2: dec r12 + jnz 1b + RETX + .endfunc + + .global __umodqi3 + .type __umodqi3, @function +__umodqi3: + CALLX #__ext_udivmod8 + mov r14, r15 + RETX + +#endif /* _udivmod8 */ + +#if defined (L_divmod8) + + .global __divqi3 + .type __divqi3, @function + .global __ext_divmod8 + .func __ext_divmod8 +__ext_divmod8: +__divqi3: + ;; r15 = N in ; Q out + ;; r14 = D in ; R out + ;; r13 = work, bit 0x02 to invert R, bit 0x01 to invert Q + clr r13 + tst.b r15 ; invert N? + jge 1f + mov #3, r13 + inv.b r15 + inc.b r15 +1: tst.b r14 ; invert D? + jge 2f + xor.b #1, r13 + inv.b r14 + inc.b r14 +2: push r13 ; save flags + CALLX #__ext_udivmod8 ; unsigned divmod + pop r13 ;restore flags + bit.b #2, r13 ; neg rem? + jz 3f + inv.b r14 + inc.b r14 +3: bit.b #1, r13 ; neg quot? + jz 4f + inv.b r15 + inc.b r15 +4: RETX + .endfunc + + .global __modqi3 + .type __modqi3, @function +__modqi3: + CALLX #__ext_divmod8 + mov r14, r15 + RETX + +#endif /* _divmod8 */ + +#if defined (L_udivmod16) + + .global __udivhi3 + .type __udivhi3, @function + .global __ext_udivmod16 + .func __ext_udivmod16 +__ext_udivmod16: +__udivhi3: + ;; r15 = N in ; Q out + ;; r14 = D in ; A = R out + ;; r13 = M + ;; r12 = count + mov.b #16, r12 ; set count + mov r14, r13 ; M := D + clr r14 ; A := 0 +1: rla r15 ; left shift Q ... + rlc r14 ; ... into left shift A + cmp r13, r14 ; M < A? + jlo 2f ; yes, skip adjustment + sub r13, r14 ; no, A := A - M + bis #1, r15 ; set Qi +2: dec r12 + jnz 1b + RETX + .endfunc + + .global __umodhi3 + .type __umodhi3, @function +__umodhi3: + CALLX #__ext_udivmod16 + mov r14, r15 + RETX + +#endif /* _udivmod16 */ + +#if defined (L_divmod16) + + .global __divhi3 + .type __divhi3, @function + .global __ext_divmod16 + .func __ext_divmod16 +__ext_divmod16: +__divhi3: + ;; r15 = N in ; Q out + ;; r14 = D in ; R out + ;; r13 = work, bit 0x02 to invert R, bit 0x01 to invert Q + clr r13 + tst r15 ; invert N? + jge 1f + mov #3, r13 + inv r15 + inc r15 +1: tst r14 ; invert D? + jge 2f + xor.b #1, r13 + inv r14 + inc r14 +2: push r13 ; save flags + CALLX #__ext_udivmod16 ; unsigned divmod + pop r13 ; restore flags + bit.b #2, r13 ; neg rem? + jz 3f + inv r14 + inc r14 +3: bit.b #1, r13 ; neg quot? + jz 4f + inv r15 + inc r15 +4: RETX + .endfunc + + .global __modhi3 + .type __modhi3, @function +__modhi3: + CALLX #__ext_divmod16 + mov r14, r15 + RETX + +#endif /* _divmod16 */ + +#if defined (L_udivmod20) + +#if __MSP430X__ + .global __udivpsi3 + .type __udivpsi3, @function + .global __ext_udivmod20 + .func __ext_udivmod20 +__ext_udivmod20: +__udivpsi3: + ;; r15 = N in ; Q out + ;; r14 = D in ; A = R out + ;; r13 = M + ;; r12 = count + mov.b #20, r12 ; set count + mova r14, r13 ; M := D + clra r14 ; A := 0 +1: adda r15, r15 ; left shift Q ... + rlcx.a r14 ; ... into left shift A + cmpa r13, r14 ; M < A? + jlo 2f ; yes, skip adjustment + suba r13, r14 ; no, A := A - M + bisx.a #1, r15 ; set Qi +2: dec r12 + jnz 1b + RETX + .endfunc + + .global __umodpsi3 + .type __umodpsi3, @function +__umodpsi3: + CALLX #__ext_udivmod20 + mov r14, r15 + RETX + +#endif /* __MSP430X__ */ +#endif /* _udivmod20 */ + +#if defined (L_divmod20) +#if __MSP430X__ + .global __divpsi3 + .type __divpsi3, @function + .global __ext_divmod20 + .func __ext_divmod20 +__ext_divmod20: +__divpsi3: + ;; r15 = N in ; Q out + ;; r14 = D in ; R out + ;; r13 = work, bit 0x02 to invert R, bit 0x01 to invert Q + clra r13 + tsta r15 ; invert N? + jge 1f + mov #3, r13 + invx.a r15 + incx.a r15 +1: tsta r14 ; invert D? + jge 2f + xor.b #1, r13 + invx.a r14 + incx.a r14 +2: push r13 ; save flags + CALLX #__ext_udivmod20 ; unsigned divmod + pop r13 ; restore flags + bit.b #2, r13 ; neg rem? + jz 3f + invx.a r14 + incx.a r14 +3: bit.b #1, r13 ; neg quot? + jz 4f + invx.a r15 + incx.a r15 +4: RETX + .endfunc + + .global __modpsi3 + .type __modpsi3, @function +__modpsi3: + CALLX #__ext_divmod20 + mova r14, r15 + RETX +#endif /* __MSP430X__ */ +#endif /* _divmod20 */ + +#if defined (L_udivmod32) + + .global __udivsi3 + .type __udivsi3, @function + .global __ext_udivmod32 + .func __ext_udivmod32 + +__ext_udivmod32: +__udivsi3: + ;; r14:r15 = N in ; Q out + ;; r12:r13 = D in ; A = R out + ;; r10:r11 = M + ;; r9 = count +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #3, r11 +#elif __MSP430X__ + pushm #3, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 +#endif /* CPUX */ + mov.b #32, r9 ; set count + mov r12, r10 ; M := D + mov r13, r11 + clr r12 ; A := 0 + clr r13 +1: rla r14 ; left shift Q ... + rlc r15 + rlc r12 ; ... into left shift A + rlc r13 + cmp r11, r13 ; M > A? + jlo 3f ; yes at high word, skip adjustment + jne 2f ; no, need adjustment + cmp r10, r12 ; high word M = A; low word M < A? + jlo 3f ; yes, skip adjustment +2: sub r10, r12 ; no, A := A - M + subc r11, r13 + bis #1, r14 ; set Qi +3: dec r9 + jnz 1b +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #3, r11 +#elif __MSP430X__ + popm #3, r11 +#else /* CPUX */ + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + .endfunc + + .global __umodsi3 + .type __umodsi3, @function +__umodsi3: + CALLX #__ext_udivmod32 + mov r12, r14 + mov r13, r15 + RETX + +#endif /* _udivmod32 */ + +#if defined (L_divmod32) + + .global __divsi3 + .type __divsi3, @function + .global __ext_divmod32 + .func __ext_divmod32 + +__ext_divmod32: +__divsi3: + ;; r14:r15 = N in ; Q out + ;; r12:r13 = D in ; R out + ;; r11 = work, bit 0x02 to invert R, bit 0x01 to invert Q +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #1, r11 +#else /* CPUX */ + push r11 +#endif /* CPUX */ + clr r11 + tst r15 ; invert N? + jge 1f + mov #3, r11 + inv r14 + inv r15 + inc r14 + adc r15 +1: tst r13 ; invert D? + jge 2f + xor.b #1, r11 + inv r12 + inv r13 + inc r12 + adc r13 +2: CALLX #__ext_udivmod32 ; unsigned divmod + bit.b #2, r11 ; neg rem? + jz 3f + inv r12 + inv r13 + inc r12 + adc r13 +3: bit.b #1, r11 ; neg quot? + jz 4f + inv r14 + inv r15 + inc r14 + adc r15 +4: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #1, r11 +#else /* CPUX */ + pop r11 +#endif /* CPUX */ + RETX + .endfunc + + .global __modsi3 + .type __modsi3, @function +__modsi3: + CALLX #__ext_divmod32 + mov r12, r14 + mov r13, r15 + RETX + +#endif /* _divmod32 */ + +#if defined (L_udivmod64) + + .global __xabi_udivmod64 + .func __xabi_udivmod64 +__xabi_udivmod64: + ;; r12:r15 = N in ; Q out + ;; r8:r11 = D in ; A = R out + ;; r4:r7 = M + ;; @r1 = count +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #4, r7 +#elif __MSP430X__ + pushm #4, r7 +#else /* CPUX */ + push r7 + push r6 + push r5 + push r4 +#endif /* CPUX */ + push #64 + mov r8, r4 ; M := D + mov r9, r5 + mov r10, r6 + mov r11, r7 + clr r8 ; A := 0 + clr r9 + clr r10 + clr r11 +1: rla r12 ; left shift Q ... + rlc r13 + rlc r14 + rlc r15 + rlc r8 ; ... into left shift A + rlc r9 + rlc r10 + rlc r11 + cmp r7, r11 ; M > A? + jlo 3f ; yes at hhi word, skip adjustment + jne 2f ; no, need adjustment + cmp r6, r10 ; hhi word M = A; hlo word M < A? + jlo 3f ; yes, skip adjustment + jne 2f ; no, need adjustment + cmp r5, r9 ; hlo word M = A; lhi word M < A? + jlo 3f ; yes, skip adjustment + jne 2f ; no, need adjustment + cmp r4, r8 ; lhi word M = A; llo word M < A? + jlo 3f ; yes, skip adjustment +2: sub r4, r8 ; no, A := A - M + subc r5, r9 + subc r6, r10 + subc r7, r11 + bis #1, r12 ; set Qi +3: dec @r1 + jnz 1b + add #2, r1 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #4, r7 +#elif __MSP430X__ + popm #4, r7 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 +#endif /* CPUX */ + RETX + .endfunc + + .global __udivdi3 + .type __udivdi3, @function +__udivdi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #4, r11 +#elif __MSP430X__ + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov ARG_REFERENCE(4,0), r8 + mov ARG_REFERENCE(4,2), r9 + mov ARG_REFERENCE(4,4), r10 + mov ARG_REFERENCE(4,6), r11 + + CALLX #__xabi_udivmod64 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #4, r11 +#elif __MSP430X__ + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + + .global __umoddi3 + .type __umoddi3, @function +__umoddi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #4, r11 +#elif __MSP430X__ + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov ARG_REFERENCE(4,0), r8 + mov ARG_REFERENCE(4,2), r9 + mov ARG_REFERENCE(4,4), r10 + mov ARG_REFERENCE(4,6), r11 + + CALLX #__xabi_udivmod64 + mov r8, r12 + mov r9, r13 + mov r10, r14 + mov r11, r15 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #4, r11 +#elif __MSP430X__ + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + + .global __udivmoddi4 + .func __udivmoddi4 +__udivmoddi4: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #5, r11 +#elif __MSP430X__ + pushm #5, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 + push r7 +#endif /* CPUX */ + mov ARG_REFERENCE(5,0), r8 + mov ARG_REFERENCE(5,2), r9 + mov ARG_REFERENCE(5,4), r10 + mov ARG_REFERENCE(5,6), r11 + + CALLX #__xabi_udivmod64 + + mov ARG_REFERENCE(5,8), r7 + mov r8, @r7 + mov r9, 2(r7) + mov r10, 4(r7) + mov r11, 6(r7) + +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #5, r11 +#elif __MSP430X__ + popm #5, r11 +#else /* CPUX */ + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + +#endif /* _udivmod64 */ + +#if defined (L_divmod64) + + .global __xabi_divmod64 + .func __xabi_divmod64 + +__xabi_divmod64: + ;; r12:r15 = N in ; Q out + ;; r8:r11 = D in ;R out + ;; r7 = work, bit 0x02 to invert R, bit 0x01 to invert Q +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #1, r7 +#else /* CPUX */ + push r7 +#endif /* CPUX */ + clr r7 + tst r15 ; invert N? + jge 1f + mov #3, r7 + inv r12 + inv r13 + inv r14 + inv r15 + inc r12 + adc r13 + adc r14 + adc r15 +1: tst r11 ; invert D? + jge 2f + xor.b #1, r7 + inv r8 + inv r9 + inv r10 + inv r11 + inc r8 + adc r9 + adc r10 + adc r11 +2: CALLX #__xabi_udivmod64 ; unsigned divmod + bit.b #2, r7 ; neg rem? + jz 3f + inv r8 + inv r9 + inv r10 + inv r11 + inc r8 + adc r9 + adc r10 + adc r11 +3: bit.b #1, r7 ; neg quot? + jz 4f + inv r12 + inv r13 + inv r14 + inv r15 + inc r12 + adc r13 + adc r14 + adc r15 +4: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #1, r7 +#else /* CPUX */ + pop r7 +#endif /* CPUX */ + RETX + .endfunc + + .global __divdi3 + .type __divdi3, @function +__divdi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #4, r11 +#elif __MSP430X__ + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov ARG_REFERENCE(4,0), r8 + mov ARG_REFERENCE(4,2), r9 + mov ARG_REFERENCE(4,4), r10 + mov ARG_REFERENCE(4,6), r11 + + CALLX #__xabi_divmod64 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #4, r11 +#elif __MSP430X__ + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + + .global __moddi3 + .type __moddi3, @function +__moddi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #4, r11 +#elif __MSP430X__ + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov ARG_REFERENCE(4,0), r8 + mov ARG_REFERENCE(4,2), r9 + mov ARG_REFERENCE(4,4), r10 + mov ARG_REFERENCE(4,6), r11 + + CALLX #__xabi_divmod64 + mov r8, r12 + mov r9, r13 + mov r10, r14 + mov r11, r15 +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #4, r11 +#elif __MSP430X__ + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + RETX + +#endif /* _divmod64 */ + +/* + ****************** + * Shift operations + ****************** + */ + +#if defined(L_ashlqi3) +; clobber r14, return r15 + .global __ashlqi3 + .type __ashlqi3,@function +__ashlqi3: + and.b #7, r14 + jz 1f +2: rla.b r15 + dec.b r14 + jnz 2b +1: RETX +#endif /* L_ashlqi3 */ + +#if defined(L_ashrqi3) +; clobber r14, return r15 + .global __ashrqi3 + .type __ashrqi3,@function +__ashrqi3: + and.b #7, r14 + jz 1f +2: rra.b r15 + dec.b r14 + jnz 2b +1: RETX +#endif /* L_ashrqi3 */ + +#if defined(L_lshrqi3) +; clobber r14, return r15 + .global __lshrqi3 + .type __lshrqi3,@function +__lshrqi3: + and.b #7, r14 + jz 1f +#if __MSP430X__ + and.b #-1, r15 +2: rrum #1, r15 +#else /* CPUX */ +2: clrc + rrc.b r15 +#endif /* CPUX */ + dec.b r14 + jnz 2b +1: RETX +#endif /* L_lshrqi3 */ + +#if defined(L_ashlhi3) +; clobber r14, return r15 + .global __ashlhi3 + .type __ashlhi3,@function +__ashlhi3: + and.b #0x0f, r14 + jz 1f + cmp.b #8, r14 + jlo 2f + and.b #-1, r15 + swpb r15 + sub.b #8, r14 + jz 1f +2: rla r15 + dec.b r14 + jnz 2b +1: RETX +#endif /* L_ashlhi3 */ + +#if defined(L_ashrhi3) +; clobber r14, return r15 + .global __ashrhi3 + .type __ashrhi3,@function +__ashrhi3: + and.b #0x0f, r14 + jz 1f + cmp.b #8, r14 + jlo 2f + swpb r15 + sxt r15 + sub.b #8, r14 + jz 1f +2: rra r15 + dec.b r14 + jnz 2b +1: RETX +#endif /* L_ashrhi3 */ + +#if defined(L_lshrhi3) +; clobber r14, return r15 + .global __lshrhi3 + .type __lshrhi3,@function +__lshrhi3: + and.b #0x0f, r14 + jz 1f + cmp.b #8, r14 + jlo 2f + swpb r15 + and.b #-1, r15 + sub.b #8, r14 + jz 1f +2: +#if __MSP430X__ + rrum #1, r15 +#else /* CPUX */ + clrc + rrc r15 +#endif /* CPUX */ + dec.b r14 + jnz 2b +1: RETX +#endif /* L_lshrhi3 */ + +#if defined(L_ashlsi3) +; clobber r13, return r14+r15 + .global __ashlsi3 + .type __ashlsi3,@function +__ashlsi3: + and.b #0x1f, r13 + jz 1f + ;; Move whole words, if appropriate + cmp.b #16, r13 + jlo 3f + mov r14, r15 + mov r13, r14 + sub.b #16, r14 + CALLX #__ashlhi3 + clr r14 + jmp 1f +3: cmp.b #8, r13 + jlo 2f + xor.b r14, r15 + xor r14, r15 + swpb r15 + and.b #-1, r14 + swpb r14 + sub.b #8, r13 + jz 1f +2: rla r14 + rlc r15 + dec.b r13 + jnz 2b +1: RETX +#endif /* L_ashlsi3 */ + +#if defined(L_ashrsi3) +; clobber r12+r13, return r14+r15 + .global __ashrsi3 + .type __ashrsi3,@function +__ashrsi3: + and.b #0x1f, r13 + jz 1f + ;; Move whole words, if appropriate + cmp.b #16, r13 + jlo 3f + clr r12 ; r12 is sign extension word, unmodified by __ashrhi3 + tst r15 + jge 4f + mov #-1, r12 +4: mov r13, r14 + sub.b #16, r14 + CALLX #__ashrhi3 + mov r15, r14 + mov r12, r15 + jmp 1f +3: cmp.b #8, r13 + jlo 2f + swpb r14 + swpb r15 + xor.b r15, r14 + xor r15, r14 + sxt r15 + sub.b #8, r13 + jz 1f +2: rra r15 + rrc r14 + dec.b r13 + jnz 2b +1: RETX +#endif /* L_ashrsi3 */ + +#if defined(L_lshrhi3) +; clobber r13, return r14+r15 + .global __lshrsi3 + .type __lshrsi3,@function +__lshrsi3: + and.b #0x1f, r13 + jz 1f + ;; Move whole words, if appropriate + cmp.b #16, r13 + jlo 3f + mov r13, r14 + sub.b #16, r14 + CALLX #__lshrhi3 + mov r15, r14 + clr r15 + jmp 1f +3: cmp.b #8, r13 + jlo 2f + swpb r14 + swpb r15 + xor.b r15, r14 + xor r15, r14 + and.b #-1, r15 + sub.b #8, r13 + jz 1f +2: +#if __MSP430X__ + rrum #1, r15 +#else /* CPUX */ + clrc + rrc r15 +#endif /* CPUX */ + rrc r14 + dec.b r13 + jnz 2b +1: RETX +#endif /* L_lshrsi3 */ + +#if defined(L_ashldi3) +; clobber r11, return r12-r15 + .global __ashldi3 + .type __ashldi3,@function +__ashldi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #1, r11 +#else /* CPUX */ + push r11 +#endif /* CPUX */ + mov.b ARG_REFERENCE(1,0), r11 + and.b #0x3f, r11 + jz 1f + cmp #48, r11 + jlo 3f + mov r12, r15 + mov r11, r14 + sub.b #48, r14 + CALLX #__ashlhi3 + clr r12 + clr r13 + clr r14 + jmp 1f +3: cmp #32, r11 + jlo 4f + mov r13, r15 + mov r12, r14 + mov r11, r13 + sub.b #32, r13 + CALLX #__ashlsi3 + clr r12 + clr r13 + jmp 1f +4: cmp #16, r11 + jlo 5f + mov r14, r15 + mov r13, r14 + mov r12, r13 + clr r12 + jz 1f + sub #16, r11 +5: cmp.b #8, r11 + jlo 2f + xor.b r14, r15 + xor r14, r15 + swpb r15 + xor.b r13, r14 + xor r13, r14 + swpb r14 + xor.b r12, r13 + xor r12, r13 + swpb r13 + and.b #-1, r12 + swpb r12 + sub.b #8, r11 + jz 1f +2: rla r12 + rlc r13 + rlc r14 + rlc r15 + dec.b r11 + jnz 2b +1: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #1, r11 +#else /* CPUX */ + pop r11 +#endif /* CPUX */ + RETX +#endif /* L_ashldi3 */ + +#if defined(L_ashrdi3) +; clobber r11, return r12-r15 + .global __ashrdi3 + .type __ashrdi3,@function +__ashrdi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #1, r11 +#else /* CPUX */ + push r11 +#endif /* CPUX */ + mov.b ARG_REFERENCE(1,0), r11 + and.b #0x3f, r11 + jz 1f + cmp #48, r11 + jlo 4f + clr r13 ; r13 is sign extension word, unmodified by __ashrhi3 + tst r15 + jge 3f + mov #-1, r13 +3: mov r11, r14 + sub.b #48, r14 + CALLX #__ashrhi3 + mov r15, r12 + mov r13, r14 + mov r13, r15 + jmp 1f +4: cmp #32, r11 + jlo 6f + push r10 ; r12+r13 clobbered by __ashrsi3 + clr r10 + tst r15 + jge 5f + mov #-1, r10 +5: mov r11, r13 + sub #32, r13 + CALLX #__ashrsi3 + mov r14, r12 + mov r15, r13 + mov r10, r14 + mov r10, r15 + pop r10 + jmp 1f +6: cmp #16, r11 + jlo 8f + mov r13, r12 + mov r14, r13 + mov r15, r14 + clr r15 + tst r14 + jge 7f + mov #-1, r15 +7: sub #16, r11 + jz 1f +8: cmp #8, r11 + jlo 2f + swpb r12 + swpb r13 + xor.b r13, r12 + xor r13, r12 + swpb r14 + xor.b r14, r13 + xor r14, r13 + swpb r15 + xor.b r15, r14 + xor r15, r14 + sxt r15 + sub.b #8, r11 + jz 1f +2: rra r15 + rrc r14 + rrc r13 + rrc r12 + dec.b r11 + jnz 2b +1: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #1, r11 +#else /* CPUX */ + pop r11 +#endif /* CPUX */ + RETX +#endif /* L_ashrdi3 */ + +#if defined(L_lshrdi3) +; clobber r11, return r12-r15 + .global __lshrdi3 + .type __lshrdi3,@function +__lshrdi3: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + pushm.a #1, r11 +#else /* CPUX */ + push r11 +#endif /* CPUX */ + mov.b ARG_REFERENCE(1,0), r11 + and.b #0x3f, r11 + jz 1f + cmp #48, r11 + jlo 3f + mov r11, r14 + sub.b #48, r14 + CALLX #__lshrhi3 + mov r15, r12 + clr r13 + clr r14 + clr r15 + jmp 1f +3: cmp #32, r11 + jlo 4f + mov r11, r13 + sub #32, r13 + CALLX #__lshrsi3 + mov r14, r12 + mov r15, r13 + clr r14 + clr r15 + jmp 1f +4: cmp #16, r11 + jlo 5f + mov r13, r12 + mov r14, r13 + mov r15, r14 + clr r15 + sub #16, r11 + jz 1f +5: cmp #8, r11 + jlo 2f + swpb r12 + swpb r13 + xor.b r13, r12 + xor r13, r12 + swpb r14 + xor.b r14, r13 + xor r14, r13 + swpb r15 + xor.b r15, r14 + xor r15, r14 + and.b #-1, r15 + sub.b #8, r11 + jz 1f +2: +#if __MSP430X__ + rrum #1, r15 +#else /* CPUX */ + clrc + rrc r15 +#endif /* CPUX */ + rrc r14 + rrc r13 + rrc r12 + dec.b r11 + jnz 2b +1: +#if __MSP430X__ & __MSP430_CPUX_TARGET_SR20__ + popm.a #1, r11 +#else /* CPUX */ + pop r11 +#endif /* CPUX */ + RETX +#endif /* L_lshldi3 */ diff --git gcc-4.7.0.orig/libgcc/config/msp430/t-msp430 gcc-4.7.0/libgcc/config/msp430/t-msp430 new file mode 100644 index 0000000..b4c66f1 --- /dev/null +++ gcc-4.7.0/libgcc/config/msp430/t-msp430 @@ -0,0 +1,96 @@ +# Specific names for MSP430 tools +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = msp430/libgcc.S +LIB1ASMFUNCS = \ + _cmpsi2 \ + _ucmpsi2 \ + _cmpdi2 \ + _ucmpdi2 \ + _mulqi3 \ + _mulqihi3 \ + _umulqihi3 \ + _mulhi3 \ + _mulhisi3 \ + _umulhisi3 \ + _mulsi3 \ + _mulsidi3 \ + _umulsidi3 \ + _muldi3 \ + _udivmod8 \ + _divmod8 \ + _udivmod16 \ + _divmod16 \ + _udivmod20 \ + _divmod20 \ + _udivmod32 \ + _divmod32 \ + _udivmod64 \ + _divmod64 \ + _ashlqi3 \ + _ashrqi3 \ + _lshrqi3 \ + _ashlhi3 \ + _ashrhi3 \ + _lshrhi3 \ + _ashlsi3 \ + _ashrsi3 \ + _lshrsi3 \ + _ashldi3 \ + _ashrdi3 \ + _lshrdi3 + +CRT0ASMFUNCS = \ + _reset_vector__ \ + __watchdog_support \ + __init_stack \ + __low_level_init \ + _copy_data \ + _clear_bss \ + __stop_progExec__ \ + _endless_loop__ \ + _unexpected_ \ + _ctors430 \ + _dtors430 + +CRT0ASMSRC = msp430/crt0.S + +crt0asmfuncs-o = $(patsubst %,$(T)%$(objext),$(CRT0ASMFUNCS)) + +$(crt0asmfuncs-o): %$(objext): $(srcdir)/config/$(CRT0ASMSRC) + $(gcc_compile) -DL$(*F) -xassembler-with-cpp -c $< + +$(T)libcrt0.a: $(crt0asmfuncs-o) + -rm -f $@ + $(AR) $(ARFLAGS) $@ $^ + $(RANLIB) $@ + + +crt0asmfuncs-dwdt-o = $(patsubst %,$(T)%-dwdt$(objext),$(CRT0ASMFUNCS)) + +$(crt0asmfuncs-dwdt-o): %-dwdt$(objext): $(srcdir)/config/$(CRT0ASMSRC) + $(gcc_compile) -DWITH_DISABLE_WDT -DL$(*F) -xassembler-with-cpp -c $< + +$(T)libcrt0dwdt.a: $(crt0asmfuncs-dwdt-o) + -rm -f $@ + $(AR) $(ARFLAGS) $@ $^ + $(RANLIB) $@ + +# Interrupt vector tables. Not part of crt0 because this is completely +# orthogonal to multilib, and we need three alternatives. + +$(T)crt0ivtbl16.o: $(srcdir)/config/msp430/crt0ivtbl.S $(GCC_PASSES) + $(gcc_compile) -c -DINTERRUPT_VECTOR_COUNT=16 $< + + +$(T)crt0ivtbl32.o: $(srcdir)/config/msp430/crt0ivtbl.S $(GCC_PASSES) + $(gcc_compile) -c -DINTERRUPT_VECTOR_COUNT=32 $< + +$(T)crt0ivtbl64.o: $(srcdir)/config/msp430/crt0ivtbl.S $(GCC_PASSES) + $(gcc_compile) -c -DINTERRUPT_VECTOR_COUNT=64 $< + +# We do not have the DF type. +# Most of the C functions in libgcc2 use almost all registers, +TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc -g + +FPBIT = true +FPBIT_CFLAGS = -DFLOAT_ONLY -DDF=SF -DDI=SI -DSMALL_MACHINE