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.6.3 (dffc052d8762f398d8d0198accbcb12185b0610a) and gcc-4_6/gcc-4.6.3 (d005eb492eb2e3c41d4f77ef22e8f91c1e0bf27c) To build, obtain the upstream release distribution from: ftp://ftp.gnu.org/pub/gnu/gcc/gcc-4.6.3/gcc-4.6.3.tar.bz2 Unpack the distribution, apply the patch, and build. (Note: The example commands are in Bourne-shell syntax.) tar xjf gcc-4.6.3.tar.bz2 ( cd gcc-4.6.3 ; patch -p1 < ../msp430-gcc-4.6.3-20120406.patch ) mkdir -p BUILD/gcc cd BUILD/gcc ../../gcc-4.6.3/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: 32f42c9 [2012-04-06 11:08:42 -0500] Update DEV-PHASE for release e33bad7 [2012-04-06 08:36:12 -0500] Update for release 80e4799 [2012-03-30 19:26:05 -0500] Update DEV-PHASE for release 79a5b04 [2012-03-21 16:00:08 -0500] Add msp430 target support to GCC 2cc7120 [2012-03-30 19:22:48 -0500] Revert "Add msp430 target support to GCC" 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 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 57c0b69 [2012-03-11 13:12:37 -0500] Update DEV-PHASE for release 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 ac421b7 [2012-02-24 14:28:04 -0600] Update DEV-PHASE for release 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" 6932fa0 [2012-01-25 13:37:08 -0600] Update DEV-PHASE for release 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 e313f64 [2012-01-19 17:54:37 -0600] Update DEV-PHASE for release 135695f [2011-10-30 11:49:46 -0500] Add msp430 target support to GCC ec1dfda [2011-10-30 11:48:55 -0500] Revert "Add msp430 target support to GCC" 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 1f0ec33 [2011-12-05 08:55:43 -0600] Regenerate 7bc944e [2011-09-22 09:22:25 -0500] SF 3412886 pre-patch pr50213/tree-optimization 1e1a365 [2011-09-22 09:25:24 -0500] SF 3412439 address IRA issue in upstream pr50427/rtl-optimization 35b555b [2011-01-18 13:13:21 -0600] Add %:include-noerr as spec function. aee9347 [2011-02-21 03:47:03 -0600] Anticipatory patch for PR middle-end/42722 (SF 3148801) 2240a54 [2011-07-16 12:21:25 -0500] Add msp430 target support to GCC 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.6.3.orig/configure gcc-4.6.3/configure index 6be5e9d..fefe43a 100755 --- gcc-4.6.3.orig/configure +++ gcc-4.6.3/configure @@ -3467,6 +3467,9 @@ case "${target}" in mn10300-*-*) noconfigdirs="$noconfigdirs ${libgcj}" ;; + msp430-*-*) + noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj} target-libssp" + ;; mt-*-*) noconfigdirs="$noconfigdirs sim" ;; diff --git gcc-4.6.3.orig/configure.ac gcc-4.6.3/configure.ac index ba6d84d..56d8506 100644 --- gcc-4.6.3.orig/configure.ac +++ gcc-4.6.3/configure.ac @@ -913,6 +913,9 @@ case "${target}" in mn10300-*-*) noconfigdirs="$noconfigdirs ${libgcj}" ;; + msp430-*-*) + noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 ${libgcj} target-libssp" + ;; mt-*-*) noconfigdirs="$noconfigdirs sim" ;; diff --git gcc-4.6.3.orig/gcc/DEV-PHASE gcc-4.6.3/gcc/DEV-PHASE index e69de29..f914eb5 100644 --- gcc-4.6.3.orig/gcc/DEV-PHASE +++ gcc-4.6.3/gcc/DEV-PHASE @@ -0,0 +1 @@ +mspgcc LTS 20120406 unpatched diff --git gcc-4.6.3.orig/gcc/config.gcc gcc-4.6.3/gcc/config.gcc index 39d9a19..714612d 100644 --- gcc-4.6.3.orig/gcc/config.gcc +++ gcc-4.6.3/gcc/config.gcc @@ -930,6 +930,12 @@ avr-*-*) extra_gcc_objs="driver-avr.o avr-devices.o" extra_objs="avr-devices.o" ;; +msp430-*-*) + tm_file="msp430/msp430.h dbxelf.h" + c_target_objs="msp430-c.o" + cxx_target_objs="msp430-c.o" + extra_objs="msp430-builtins.o msp430-function.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.6.3.orig/gcc/config/msp430/constraints.md gcc-4.6.3/gcc/config/msp430/constraints.md new file mode 100644 index 0000000..4eab121 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/constraints.md @@ -0,0 +1,81 @@ +;; -*- 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 GHIJKL 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 "msp430_cpu & MSP430_CPU_MSP430X && 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 "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.6.3.orig/gcc/config/msp430/crt0.S gcc-4.6.3/gcc/config/msp430/crt0.S new file mode 100644 index 0000000..112ef09 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/crt0.S @@ -0,0 +1,336 @@ +/* -*- 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 */ +/******* 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 + call @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 + call @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.6.3.orig/gcc/config/msp430/crt0ivtbl.S gcc-4.6.3/gcc/config/msp430/crt0ivtbl.S new file mode 100644 index 0000000..696f6aa --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/crt0ivtbl.S @@ -0,0 +1,102 @@ +/* -*- Mode: Asm -*- */ + + .section .text.crt0, "ax", @progbits + +/*************************************************************** + * Interrupt Vectors: + * WARNING!!! All vectors must be defined here!!! + * User may not define its interrupt service routines! + ***************************************************************/ + +.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 + + 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 */ +#if 32 < INTERRUPT_VECTOR_COUNT + INITIALIZE_ISR_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.6.3.orig/gcc/config/msp430/libgcc.S gcc-4.6.3/gcc/config/msp430/libgcc.S new file mode 100644 index 0000000..8d7bc44 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/libgcc.S @@ -0,0 +1,1489 @@ +/* -*- 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. */ + + +/* Flag in __MSP430_CPU__ denoting CPUX instructions available */ +#define MSP430_CPU_MSP430X 0x0002 + +/* Offset from r1 to first word of stack-pushed arguments. */ +#define ARGP_OFFSET 2 + + .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 + ret + +.L_ge: + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + ret +.L_eq: + mov #1, r15 ; a == b return 1 + ret +.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 + ret + +.L_ge: + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + ret +.L_eq: + mov #1, r15 ; a == b return 1 + ret +.endfunc +#endif + +#if defined (L_cmpdi2) + .global __cmpdi2 + .func __cmpdi2 +__cmpdi2: + sub ARGP_OFFSET(r1), r12 + subc 2+ARGP_OFFSET(r1), r13 + subc 4+ARGP_OFFSET(r1), r14 + subc 6+ARGP_OFFSET(r1), r15 + jge .L_ge + mov #0, r15 ; a < b return 0 + ret + +.L_ge: + bis r12, r15 + bis r13, r15 + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + ret +.L_eq: + mov #1, r15 ; a == b return 1 + ret +.endfunc +#endif + +#if defined (L_ucmpdi2) + + .global __ucmpdi2 + .func __ucmpdi2 +__ucmpdi2: + sub ARGP_OFFSET(r1), r12 + subc 2+ARGP_OFFSET(r1), r13 + subc 4+ARGP_OFFSET(r1), r14 + subc 6+ARGP_OFFSET(r1), r15 + jhs .L_ge + mov #0, r15 ; a < b return 0 + ret + +.L_ge: + bis r12, r15 + bis r13, r15 + bis r14, r15 + tst r15 + jz .L_eq + + mov #2, r15 ; a > b return 2 + ret +.L_eq: + mov #1, r15 ; a == b return 1 + ret +.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: ret + .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 __MSP430_CPU__ & MSP430_CPU_MSP430X + rrum #1, r13 +#else /* CPUX */ + clrc + rrc r13 +#endif /* CPUX */ + jnc 2f + add r14, r15 +2: rla r14 + tst r13 + jne 1b +3: ret + .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: + push r11 + push r10 + clr r11 + clr r10 + jmp 3f +1: ; b >>= 1 +#if __MSP430_CPU__ & MSP430_CPU_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 + pop r10 + pop r11 + ret + .endfunc + +#endif + +#if defined (L_mulsidi3) + .global __mulsidi3 + .func __mulsidi3 + +__mulsidi3: +#if __MSP430_CPU__ & MSP430_CPU_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 + call #__xabi_muldi3 + +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #8, r11 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + .endfunc +#endif + +#if defined (L_umulsidi3) + .global __umulsidi3 + .func __umulsidi3 + +__umulsidi3: +#if __MSP430_CPU__ & MSP430_CPU_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 + + call #__xabi_muldi3 + +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #8, r11 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + .endfunc + +#endif + +#if defined (L_muldi3) +/******************************************************* + Multiplication 64 x 64 +*******************************************************/ + + .global __muldi3 + .func __muldi3 + +__muldi3: +#if __MSP430_CPU__ & MSP430_CPU_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 16+ARGP_OFFSET(r1), r8 ; load b + mov 2+16+ARGP_OFFSET(r1), r9 + mov 4+16+ARGP_OFFSET(r1), r10 + mov 6+16+ARGP_OFFSET(r1), r11 + call #__xabi_muldi3 +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #8, r11 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + .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 __MSP430_CPU__ & MSP430_CPU_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 + + ret +#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 + ret + .endfunc + + .global __umodqi3 + .type __umodqi3, @function +__umodqi3: + call #__ext_udivmod8 + mov r14, r15 + ret + +#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 + call #__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: ret + .endfunc + + .global __modqi3 + .type __modqi3, @function +__modqi3: + call #__ext_divmod8 + mov r14, r15 + ret + +#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 + ret + .endfunc + + .global __umodhi3 + .type __umodhi3, @function +__umodhi3: + call #__ext_udivmod16 + mov r14, r15 + ret + +#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 + call #__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: ret + .endfunc + + .global __modhi3 + .type __modhi3, @function +__modhi3: + call #__ext_divmod16 + mov r14, r15 + ret + +#endif /* _divmod16 */ + +#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 __MSP430_CPU__ & MSP430_CPU_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 __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #3, r11 +#else /* CPUX */ + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + .endfunc + + .global __umodsi3 + .type __umodsi3, @function +__umodsi3: + call #__ext_udivmod32 + mov r12, r14 + mov r13, r15 + ret + +#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 + push r11 + 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: call #__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: pop r11 + ret + .endfunc + + .global __modsi3 + .type __modsi3, @function +__modsi3: + call #__ext_divmod32 + mov r12, r14 + mov r13, r15 + ret + +#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 __MSP430_CPU__ & MSP430_CPU_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 __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #4, r7 +#else /* CPUX */ + pop r4 + pop r5 + pop r6 + pop r7 +#endif /* CPUX */ + ret + .endfunc + + .global __udivdi3 + .type __udivdi3, @function +__udivdi3: +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov 8+ARGP_OFFSET(r1), r8 + mov 2+8+ARGP_OFFSET(r1), r9 + mov 4+8+ARGP_OFFSET(r1), r10 + mov 6+8+ARGP_OFFSET(r1), r11 + + call #__xabi_udivmod64 +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + + .global __umoddi3 + .type __umoddi3, @function +__umoddi3: +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov 8+ARGP_OFFSET(r1), r8 + mov 2+8+ARGP_OFFSET(r1), r9 + mov 4+8+ARGP_OFFSET(r1), r10 + mov 6+8+ARGP_OFFSET(r1), r11 + + call #__xabi_udivmod64 + mov r8, r12 + mov r9, r13 + mov r10, r14 + mov r11, r15 +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + + .global __udivmoddi4 + .func __udivmoddi4 +__udivmoddi4: +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + pushm #5, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 + push r7 +#endif /* CPUX */ + mov 10+ARGP_OFFSET(r1), r8 + mov 2+10+ARGP_OFFSET(r1), r9 + mov 4+10+ARGP_OFFSET(r1), r10 + mov 6+10+ARGP_OFFSET(r1), r11 + + call #__xabi_udivmod64 + + mov 8+10+ARGP_OFFSET(r1), r7 + mov r8, @r7 + mov r9, 2(r7) + mov r10, 4(r7) + mov r11, 6(r7) + +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #5, r11 +#else /* CPUX */ + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + +#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 + push r7 + 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: call #__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: pop r7 + ret + .endfunc + + .global __divdi3 + .type __divdi3, @function +__divdi3: +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov 8+ARGP_OFFSET(r1), r8 + mov 2+8+ARGP_OFFSET(r1), r9 + mov 4+8+ARGP_OFFSET(r1), r10 + mov 6+8+ARGP_OFFSET(r1), r11 + + call #__xabi_divmod64 +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + + .global __moddi3 + .type __moddi3, @function +__moddi3: +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + pushm #4, r11 +#else /* CPUX */ + push r11 + push r10 + push r9 + push r8 +#endif /* CPUX */ + mov 8+ARGP_OFFSET(r1), r8 + mov 2+8+ARGP_OFFSET(r1), r9 + mov 4+8+ARGP_OFFSET(r1), r10 + mov 6+8+ARGP_OFFSET(r1), r11 + + call #__xabi_divmod64 + mov r8, r12 + mov r9, r13 + mov r10, r14 + mov r11, r15 +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + popm #4, r11 +#else /* CPUX */ + pop r8 + pop r9 + pop r10 + pop r11 +#endif /* CPUX */ + ret + +#endif /* _divmod64 */ + +/********* PROLOGE / EPILOGUE aux routines ******************/ +#if defined (L__prologue_saver) + .global __prologue_saver + .func __prologue_saver +__prologue_saver: + mov r4, 0(r1) + mov r5, 2(r1) + mov r6, 4(r1) + mov r7, 6(r1) + mov r8, 8(r1) + mov r9, 10(r1) + mov r10, 12(r1) + mov r11, 14(r1) + br r12 ; now jump to the function body +.endfunc + +#endif + + +#if defined (L__epilogue_restorer) + .global __epilogue_restorer + .func __epilogue_restorer +__epilogue_restorer: + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 + ret +.endfunc + +#endif + + +#if defined (L__epilogue_restorer_intr) + .global __epilogue_restorer_intr + .func __epilogue_restorer_intr +__epilogue_restorer_intr: + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + reti +.endfunc + +#endif + +/* + ****************** + * 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: ret +#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: ret +#endif /* L_ashrqi3 */ + +#if defined(L_lshrqi3) +; clobber r14, return r15 + .global __lshrqi3 + .type __lshrqi3,@function +__lshrqi3: + and.b #7, r14 + jz 1f +#if __MSP430_CPU__ & MSP430_CPU_MSP430X + and.b #-1, r15 +2: rrum #1, r15 +#else /* CPUX */ +2: clrc + rrc.b r15 +#endif /* CPUX */ + dec.b r14 + jnz 2b +1: ret +#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: ret +#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: ret +#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 __MSP430_CPU__ & MSP430_CPU_MSP430X + rrum #1, r15 +#else /* CPUX */ + clrc + rrc r15 +#endif /* CPUX */ + dec.b r14 + jnz 2b +1: ret +#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 + call #__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: ret +#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 + call #__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: ret +#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 + call #__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 __MSP430_CPU__ & MSP430_CPU_MSP430X + rrum #1, r15 +#else /* CPUX */ + clrc + rrc r15 +#endif /* CPUX */ + rrc r14 + dec.b r13 + jnz 2b +1: ret +#endif /* L_lshrsi3 */ + +#if defined(L_ashldi3) +; clobber r11, return r12-r15 + .global __ashldi3 + .type __ashldi3,@function +__ashldi3: + push r11 + mov.b 2+ARGP_OFFSET(r1), r11 + and.b #0x3f, r11 + jz 1f + cmp #48, r11 + jlo 3f + mov r12, r15 + mov r11, r14 + sub.b #48, r14 + call #__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 + call #__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: pop r11 + ret +#endif /* L_ashldi3 */ + +#if defined(L_ashrdi3) +; clobber r11, return r12-r15 + .global __ashrdi3 + .type __ashrdi3,@function +__ashrdi3: + push r11 + mov.b 2+ARGP_OFFSET(r1), 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 + call #__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 + call #__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: pop r11 + ret +#endif /* L_ashrdi3 */ + +#if defined(L_lshrdi3) +; clobber r11, return r12-r15 + .global __lshrdi3 + .type __lshrdi3,@function +__lshrdi3: + push r11 + mov.b 2+ARGP_OFFSET(r1), r11 + and.b #0x3f, r11 + jz 1f + cmp #48, r11 + jlo 3f + mov r11, r14 + sub.b #48, r14 + call #__lshrhi3 + mov r15, r12 + clr r13 + clr r14 + clr r15 + jmp 1f +3: cmp #32, r11 + jlo 4f + mov r11, r13 + sub #32, r13 + call #__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 __MSP430_CPU__ & MSP430_CPU_MSP430X + rrum #1, r15 +#else /* CPUX */ + clrc + rrc r15 +#endif /* CPUX */ + rrc r14 + rrc r13 + rrc r12 + dec.b r11 + jnz 2b +1: pop r11 + ret +#endif /* L_lshldi3 */ diff --git gcc-4.6.3.orig/gcc/config/msp430/msp430-builtins.c gcc-4.6.3/gcc/config/msp430/msp430-builtins.c new file mode 100644 index 0000000..ca76762 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430-builtins.c @@ -0,0 +1,444 @@ +/* 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_last_enum +}; + +void +msp430_init_builtins (void) +{ + 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); +} + +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 (Pmode, + 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 (HImode); + 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 loop_test; + 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)); + loop_test = gen_rtx_NE (itercnt_mode, iterreg0, const0_rtx); + gcc_assert (HImode == itercnt_mode); + emit_jump_insn (gen_cbranchhi4 (loop_test, iterreg0, const0_rtx, loop_label)); + cycles -= itercnt0 * iter0_cycles; + if (iterreg1 != NULL_RTX) + { + emit_insn (gen_delay_cycles_decr (iterreg1)); + loop_test = gen_rtx_NE (itercnt_mode, iterreg1, const0_rtx); + emit_jump_insn (gen_cbranchhi4 (loop_test, iterreg1, const0_rtx, 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; + } + + 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.6.3.orig/gcc/config/msp430/msp430-c.c gcc-4.6.3/gcc/config/msp430/msp430-c.c new file mode 100644 index 0000000..1c023c8 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430-c.c @@ -0,0 +1,62 @@ +/* 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; +} diff --git gcc-4.6.3.orig/gcc/config/msp430/msp430-function.c gcc-4.6.3/gcc/config/msp430/msp430-function.c new file mode 100644 index 0000000..684fd2a --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430-function.c @@ -0,0 +1,772 @@ +/* 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, tree type); + +static const char *S_signal = "signal"; +static const char *S_interrupt = "interrupt"; +static const char *S_naked = "naked"; +static const char *S_task = "task"; +static const char *S_wakeup = "wakeup"; +static const char *S_critical = "critical"; +static const char *S_reentrant = "reentrant"; +static const char *S_saveprologue = "saveprologue"; +static const char *S_noint_hwmul = "noint_hwmul"; +static const char *S_hosted = "hosted"; + +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; + +void +msp430_set_current_function (tree decl) +{ + struct machine_function *mfp; + tree attributes; + tree naked; + tree interrupt; + tree task; + tree saveprologue; + tree noint_hwmul; + tree critical; + tree reentrant; + tree wakeup; + tree signal; + tree hosted; + + if ((decl == NULL_TREE) || (!cfun) || (!cfun->machine) + || cfun->machine->initialized) + return; + gcc_assert ((cfun->decl == NULL_TREE) || (cfun->decl == decl)); + attributes = DECL_ATTRIBUTES (decl); + + mfp = cfun->machine; + signal = lookup_attribute (S_signal, attributes); + interrupt = lookup_attribute (S_interrupt, attributes); + naked = lookup_attribute (S_naked, attributes); + task = lookup_attribute (S_task, attributes); + wakeup = lookup_attribute (S_wakeup, attributes); + critical = lookup_attribute (S_critical, attributes); + reentrant = lookup_attribute (S_reentrant, attributes); + saveprologue = lookup_attribute (S_saveprologue, attributes); + noint_hwmul = lookup_attribute (S_noint_hwmul, attributes); + hosted = lookup_attribute (S_hosted, attributes); + + /* 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); + +#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"; + + 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; + + 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_subhi3 (reg_rtx, reg_rtx, gen_int_mode (-offset, HImode)); + return gen_addhi3 (reg_rtx, reg_rtx, gen_int_mode (offset, HImode)); +} + +static rtx +emit_prolog_pushm (int regno, int numregs) +{ + rtx note = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (1 + numregs)); + rtx insn; + int i; + + insn = gen_rtx_SET (HImode, 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 (HImode, + plus_constant (stack_pointer_rtx, + UNITS_PER_WORD * (numregs - i - 1))); + insn = gen_rtx_SET (HImode, spr, gen_rtx_REG (HImode, regno - i)); + RTX_FRAME_RELATED_P (insn) = 1; + XVECEXP (note, 0, 1 + i) = insn; + } + + insn = + emit_insn (gen_pushmhi2 (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) + { + for (i = MSP430_MAX_GENERAL_REGNUM; i >= MSP430_MIN_GENERAL_REGNUM; --i) + if (is_savable_register (i)) + { + if (MSP430_CPU_MSP430X <= msp430_cpu) + { + 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); + i = i - n + 1; + continue; + } + } + insn = emit_insn (gen_pushhi1 (gen_rtx_REG (HImode, 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) + { + for (i = MSP430_MIN_GENERAL_REGNUM; i <= MSP430_MAX_GENERAL_REGNUM; i++) + if (is_savable_register (i)) + { + if (MSP430_CPU_MSP430X <= msp430_cpu) + { + 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_popmhi2 (GEN_INT (n), GEN_INT (i))); + continue; + } + } + insn = emit_insn (gen_pophi1 (gen_rtx_REG (HImode, 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 (Pmode, 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.word .L%d\n", value); +} + +/* Controls whether a function argument is passed +in a register, and which register. */ +rtx +msp430_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, + int named ATTRIBUTE_UNUSED) +{ + 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 * cum, enum machine_mode mode, + tree type, int named ATTRIBUTE_UNUSED) +{ + 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, tree type) +{ + int size; + + if (mode == BLKmode) + size = int_size_in_bytes (type); + else + size = GET_MODE_SIZE (mode); + + if (size < UNITS_PER_WORD) + size = UNITS_PER_WORD; + + /* we do not care if argument is passed in odd register + so, do not align the size ... + BUT!!! even char argument passed in 16 bit register + so, align the size */ + return STACK_ALIGN_SIZE (size) / UNITS_PER_WORD; +} + +int +msp430_initial_elimination_offset (int from, int to) +{ + const struct machine_function *mfp = cfun->machine; + int offset_words = 0; + int offset_bytes = 0; + + switch (from) + { + case ARG_POINTER_REGNUM: + if (mfp->interrupt) + offset_words += 2; + else + offset_bytes += GET_MODE_SIZE (Pmode); + switch (to) + { + case HARD_FRAME_POINTER_REGNUM: + break; + case STACK_POINTER_REGNUM: + if (MSP430_FF_prologue_push_sr & mfp->frame_flags) + ++offset_words; + offset_words += 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_words += 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.6.3.orig/gcc/config/msp430/msp430-gcc.c gcc-4.6.3/gcc/config/msp430/msp430-gcc.c new file mode 100644 index 0000000..dece83d --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/config/msp430/msp430-protos.h gcc-4.6.3/gcc/config/msp430/msp430-protos.h new file mode 100644 index 0000000..ce687a6 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430-protos.h @@ -0,0 +1,121 @@ +/* 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. */ + + +extern void gas_output_limited_string (FILE * file, const char *str); +extern void gas_output_ascii (FILE * file, const char *str, size_t length); + +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 rtx msp430_function_arg (CUMULATIVE_ARGS * cum, + enum machine_mode mode, tree type, int named); +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); +extern rtx msp430_function_incoming_arg (CUMULATIVE_ARGS * cum, + enum machine_mode mode, tree type, + int named); + + + +#endif /* RTX_CODE inside TREE_CODE */ + +#ifdef HAVE_MACHINE_MODES /* inside TREE_CODE */ +extern void msp430_function_arg_advance (CUMULATIVE_ARGS * cum, + enum machine_mode mode, tree type, + int named); +#endif /* HAVE_MACHINE_MODES 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, + int src_operand, + const char *init_op, + const char *next_op, + const char *prefix); +const char * msp430_output_reverse_template (enum machine_mode mode, + 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[]); + +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); + +#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.6.3.orig/gcc/config/msp430/msp430.c gcc-4.6.3/gcc/config/msp430/msp430.c new file mode 100644 index 0000000..2defd6c --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430.c @@ -0,0 +1,3071 @@ +/* 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 "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 + +msp430_cpu_e msp430_cpu = MSP430_CPU_MSP430; +msp430_mpy_e msp430_mpy = MSP430_MPY_NONE; +int msp430_ivcnt = 16; + +int msp430_case_values_threshold = 30000; +int msp430_has_hwmul = 0; + +/* Defined in msp430-builtins.c */ +void msp430_init_builtins (void); +rtx msp430_expand_builtin (tree, rtx, rtx, enum machine_mode, int); + +static struct machine_function * +msp430_init_machine_status (void) +{ + return ggc_alloc_cleared_machine_function (); +} + +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; + +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 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; +} + +/****** ATTRIBUTES *************************************/ + +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in +struct attribute_spec.handler. */ +static tree +handle_fndecl_attribute (tree * pnode, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool * no_add_attrs) +{ + if (TREE_CODE (*pnode) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + return NULL_TREE; +} + + +const struct attribute_spec msp430_attribute_table[] = { + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + {"signal", 0, 0, true, false, false, handle_fndecl_attribute}, + {"interrupt", 0, 1, true, false, false, handle_fndecl_attribute}, + {"naked", 0, 0, true, false, false, handle_fndecl_attribute}, + {"task", 0, 0, true, false, false, handle_fndecl_attribute}, + {"wakeup", 0, 0, true, false, false, handle_fndecl_attribute}, + {"critical", 0, 0, true, false, false, handle_fndecl_attribute}, + {"reentrant", 0, 0, true, false, false, handle_fndecl_attribute}, + {"saveprologue", 0, 0, true, false, false, handle_fndecl_attribute}, + {"noint_hwmul", 0, 0, true, false, false, handle_fndecl_attribute}, + {"hosted", 0, 0, true, false, false, handle_fndecl_attribute}, + {NULL, 0, 0, false, false, false, NULL} +}; + +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); +} + +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"); + } + return flags; +} + +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_tag (const char *tag, const struct tag_value_pair_t *map) +{ + while (map->tag) + { + if (0 == strcmp (tag, map->tag)) + return map; + ++map; + } + return 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; +} + +static void +msp430_option_override (void) +{ + const struct tag_value_pair_t *mp; + + 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 (msp430_opt_cpu) + { + mp = find_pair_by_tag (msp430_opt_cpu, cpu_tag_value_map); + if (!mp) + { + error (_("mcpu %s not recognized"), msp430_opt_cpu); + return; + } + msp430_cpu = (msp430_cpu_e) mp->value; + } + + if (msp430_opt_mpy) + { + mp = find_pair_by_tag (msp430_opt_mpy, mpy_tag_value_map); + if (!mp) + { + error (_("mmpy %s not recognized"), msp430_opt_mpy); + return; + } + msp430_mpy = (msp430_mpy_e) mp->value; + } + + if (msp430_opt_ivcnt) + { + char *ep; + msp430_ivcnt = strtol (msp430_opt_ivcnt, &ep, 0); + if (*msp430_opt_ivcnt && *ep) + { + error (_("ivcnt %s must be integer"), msp430_opt_ivcnt); + gcc_unreachable (); + return; + } + if ((16 != msp430_ivcnt) && (32 != msp430_ivcnt) + && (64 != msp430_ivcnt)) + { + error (_("ivcnt %s must be 16, 32, or 64"), msp430_opt_ivcnt); + gcc_unreachable (); + return; + } + } + + if (TARGET_NVWA) + warning (OPT_Wdeprecated, _("-mno-volatile-workaround ignored")); + + if (TARGET_NO_HWMUL) + { + warning (OPT_Wdeprecated, "-mdisable-hwmul deprecated, use -mmpy=none"); + msp430_mpy = MSP430_MPY_NONE; + } + msp430_has_hwmul = ! !(msp430_mpy & MSP430_MPY_TYPE_ANY); + + msp430_case_values_threshold = 8; /* ? or there is a better value ? */ + + flag_defer_pop = 0; + + msp430_init_once (); +} + +/* 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; +} + +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; +} + +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; + } + } + + fprintf (file, "%s", TYPE_ASM_OP); + assemble_name (file, name); + putc (',', file); + fprintf (file, TYPE_OPERAND_FMT, "function"); + putc ('\n', file); + 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_LABEL (file, name); + if (0 <= vector) + { + char isrname[32]; + snprintf (isrname, sizeof (isrname), "__isr_%u", vector); + fprintf (file, ".global\t%s\n", isrname); + fprintf (file, "%s:\n", isrname); + } + +} + +static bool +msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x, bool strict) +{ + 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_P (XEXP (x, 1)); + default: + return CONSTANT_P (x); + } + gcc_unreachable (); +} + +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 (); +} + +void +msp430_print_operand (FILE * file, rtx x, int code) +{ + int shift = 0; + + if (code >= 'A' && code <= 'D') + shift = code - 'A'; + else if (code != 0 && code != 'S') + gcc_unreachable (); + + if (REG_P (x)) + fprintf (file, reg_names[REGNO (x) + shift]); + else if (GET_CODE (x) == CONST_INT) + { + HOST_WIDE_INT intval = INTVAL (x); + + /* For improved ASM readability, omit #llo(const) for small constants */ + if (!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) + { + fprintf (file, "#"); + output_addr_const (file, x); + if (shift) + fprintf (file, "+%d", shift * UNITS_PER_WORD); + } + 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 (); +} + +/* 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 (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, + int src_operand, bool reversep, + const char *init_op, const char *next_op, + const char *prefix) +{ + char buffer[1024]; + int offset = 0; + + if (!next_op) + next_op = init_op; + buffer[offset] = 0; + if (prefix) + offset += snprintf (buffer, sizeof (buffer) - offset, + "%s\n\t", prefix); + 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 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 (); + } + 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, + int src_operand, + const char *init_op, const char *next_op, + const char *prefix) +{ + return output_template (mode, src_operand, 0, init_op, next_op, prefix); +} + +const char * +msp430_output_reverse_template (enum machine_mode mode, + int src_operand, + const char *init_op, const char *next_op, + const char *prefix) +{ + return output_template (mode, src_operand, 1, 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[]) +{ + static const char si_fwdtempl[] = "mov\t%A1, %A0\n\tmov\t%B1, %B0"; + static const char si_revtempl[] = "mov\t%B1, %B0\n\tmov\t%A1, %A0"; + static const char di_fwdtempl[] = + "mov\t%A1, %A0\n\tmov\t%B1, %B0\n\tmov\t%C1, %C0\n\tmov\t%D1, %D0"; + static const char di_revtempl[] = + "mov\t%D1, %D0\n\tmov\t%C1, %C0\n\tmov\t%B1, %B0\n\tmov\t%A1, %A0"; + static const char di_xBtempl[] = + "mov\t%A1, %A0\n\tmov\t%C1, %C0\n\tmov\t%D1, %D0\n\tmov\t%B1, %B0"; + static const char di_xCtempl[] = + "mov\t%A1, %A0\n\tmov\t%B1, %B0\n\tmov\t%D1, %D0\n\tmov\t%C1, %C0"; + + const char *fwdtempl; + const char *revtempl; + int dst_regno; + int dst_end_regno; + int index_reg; + + switch (GET_MODE (operands[0])) + { + case SFmode: + case SImode: + fwdtempl = si_fwdtempl; + revtempl = si_revtempl; + break; + case DImode: + fwdtempl = di_fwdtempl; + revtempl = di_revtempl; + break; + default: + debug_rtx (operands[0]); + gcc_unreachable (); + } + + if (!REG_P (operands[0]) + || safe_from_earlyclobber (operands[1], operands[0])) + return fwdtempl; + + if (REG_P (operands[1])) + return REGNO (operands[0]) > REGNO (operands[1]) ? revtempl : fwdtempl; + + gcc_assert (MEM_P (operands[1])); + dst_regno = REGNO (operands[0]); + dst_end_regno = END_REGNO (operands[0]); + 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) + return revtempl; + if (index_reg + 1 == dst_end_regno) + return fwdtempl; + if (index_reg == dst_regno + 1) + return di_xBtempl; + if (index_reg == dst_regno + 2) + return di_xCtempl; + + gcc_unreachable (); +} + +/* 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) + +/* 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; +} + + +static rtx +msp430_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +{ + int words; + + words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + 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)); +} + +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) && (GET_MODE_SIZE (tmpmode) < bytes)) + tmpmode = GET_MODE_WIDER_MODE (tmpmode); + gcc_assert (tmpmode != VOIDmode); + 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)); +} + +/* 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))); +} + +/* The routine used to output NUL terminated strings. We use a special +version of this for most svr4 targets because doing so makes the +generated assembly code more compact (and thus faster to assemble) +as well as more readable, especially for targets like the i386 +(where the only alternative is to output character sequences as +comma separated lists of numbers). */ + +#define ESCAPES \ +"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" +/* A table of bytes codes used by the ASM_OUTPUT_ASCII and + ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table + corresponds to a particular byte value [0..255]. For any + given byte value, if the value in the corresponding table + position is zero, the given character can be output directly. + If the table value is 1, the byte must be output as a \ooo + octal escape. If the tables value is anything else, then the + byte value should be output as a \ followed by the value + in the table. Note that we can use standard UN*X escape + sequences for many control characters, but we don't use + \a to represent BEL because some svr4 assemblers (e.g. on + the i386) don't know about that. Also, we don't use \v + since some versions of gas, such as 2.2 did not accept it. */ + +void +gas_output_limited_string (FILE * file, const char *str) +{ + const unsigned char *_limited_str = (const unsigned char *) str; + unsigned ch; + fputs ("\t.string\t\"", file); + for (; (ch = *_limited_str); _limited_str++) + { + int escape; + switch (escape = ESCAPES[ch]) + { + case 0: + putc (ch, file); + break; + case 1: + fprintf (file, "\\%03o", ch); + break; + default: + putc ('\\', file); + putc (escape, file); + break; + } + } + fprintf (file, "\"\n"); +} + +/* The routine used to output sequences of byte values. We use a special +version of this for most svr4 targets because doing so makes the +generated assembly code more compact (and thus faster to assemble) +as well as more readable. Note that if we find subparts of the +character sequence which end with NUL (and which are shorter than +STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */ + +#define STRING_LIMIT ((unsigned) 64) + +void +gas_output_ascii (FILE * file, const char *str, size_t length) +{ + const unsigned char *_ascii_bytes = (const unsigned char *) str; + const unsigned char *limit = _ascii_bytes + length; + unsigned bytes_in_chunk = 0; + for (; _ascii_bytes < limit; _ascii_bytes++) + { + const unsigned char *p; + if (bytes_in_chunk >= 60) + { + fprintf (file, "\"\n"); + bytes_in_chunk = 0; + } + for (p = _ascii_bytes; p < limit && *p != '\0'; p++) + continue; + if (p < limit && (p - _ascii_bytes) <= (signed) STRING_LIMIT) + { + if (bytes_in_chunk > 0) + { + fprintf (file, "\"\n"); + bytes_in_chunk = 0; + } + gas_output_limited_string (file, (const char *) _ascii_bytes); + _ascii_bytes = p; + } + else + { + int escape; + unsigned ch; + if (bytes_in_chunk == 0) + fprintf (file, "\t.ascii\t\""); + switch (escape = ESCAPES[ch = *_ascii_bytes]) + { + case 0: + putc (ch, file); + bytes_in_chunk++; + break; + case 1: + fprintf (file, "\\%03o", ch); + bytes_in_chunk += 4; + break; + default: + putc ('\\', file); + putc (escape, file); + bytes_in_chunk += 2; + break; + } + } + } + if (bytes_in_chunk > 0) + fprintf (file, "\"\n"); +} + + +static section * +msp430_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) +{ + /* For now, the only thing we override is const strings. In the + * future we might be looking at near/far attributes. */ + if (TREE_CODE (decl) == STRING_CST) + return default_function_rodata_section (current_function_decl); + return default_select_section (decl, reloc, align); +} + +/* Outputs to the stdio stream FILE some +appropriate text to go at the start of an assembler file. */ + +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); + fprintf (file, "\n"); +} + +int +msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return 1; +} + +static bool +msp430_frame_pointer_required (void) +{ + return cfun->machine->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; +} + +/* 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; + 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 (HImode, INTVAL (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; + 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; + } + } + 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); + 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: + src = dst; + format = INSTR_FORMAT_FMT1; + break; + case INSTR_FORMAT_FMT1: + case INSTR_FORMAT_FMT2: + case INSTR_FORMAT_FMT2S: + case INSTR_FORMAT_CONDJMP: + break; + default: + gcc_unreachable (); + } + + + if (immediate_operand (src, VOIDmode)) + len += length_adjustment_for_immediate (src, mode); + else if (register_operand (src, VOIDmode)) + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + else if (format == INSTR_FORMAT_FMT1 || format == INSTR_FORMAT_FMT2S) + { + 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 + && 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 src "); + debug_rtx (src); +#endif /* CHECK_INSN_LENGTH */ + } + switch (format) + { + case INSTR_FORMAT_FMT1: + if (register_operand (dst, mode) || PC == GET_CODE (dst)) + len -= UNITS_PER_WORD * get_attr_instr_mult (insn); + break; + case INSTR_FORMAT_FMT2: + case INSTR_FORMAT_FMT2S: + 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: + 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 (hi, si) */ + 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; + + switch (GET_MODE (operands[0])) + { + case HImode: + dst_lo = operands[0]; + 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 = !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 (0xff00))); + return; + } + if (need_copy) + { + if (!signed_p && register_operand (dst_lo, HImode)) + emit_insn (gen_loadqi2 (dst_lo, operands[1])); + else + emit_move_insn (dst_qi, operands[1]); + } + if (signed_p) + { + 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) + 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) + { + extended_value = gen_reg_rtx (HImode); + emit_insn (gen_ashrhi3 (extended_value, dst_lo, + GEN_INT (GET_MODE_BITSIZE (HImode) - 1))); + } + } + 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_BITSIZE (HImode) - 1))); + } + dst_hi = NULL_RTX; + } + else + gcc_unreachable (); + 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); + } +} + +/***** SIGN EXTEND *********/ + +/* 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); +} + +/**** ZERO EXTEND *****/ + +/* 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 == GET_MODE_WIDER_MODE (op1mode)); + gcc_assert (widen || op0mode == 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 void +expand_shift_bitsizem1 (rtx r_dst, rtx r_src, enum shift_type_e shift_type) +{ + enum machine_mode opmode = GET_MODE (r_dst); + rtx parts[4]; + rtx r_hi; + 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; + r_hi = gen_reg_rtx (HImode); + if (QImode == opmode) + { + emit_insn (gen_loadqi2 (r_hi, parts[pmax - pres])); + r_qi = gen_lowpart (QImode, r_hi); + } + else + emit_move_insn (r_hi, parts[pmax - pres]); + + r_fill = const0_rtx; + if (ST_ashl == shift_type) + { + emit_insn (gen_rrahi1 (r_hi)); + emit_move_insn (r_hi, const0_rtx); + if (QImode == opmode) + emit_insn (gen_rrcqi1 (r_qi)); + else + emit_insn (gen_rrchi1 (r_hi)); + } + else if (ST_ashr == shift_type) + { + if (QImode == opmode) + { + emit_insn (gen_extend8bithi1 (r_hi)); + emit_insn (gen_bswaphi1 (r_hi)); + } + else + { + emit_insn (gen_bswaphi1 (r_hi)); + emit_insn (gen_extend8bithi1 (r_hi)); + emit_insn (gen_bswaphi1 (r_hi)); + emit_insn (gen_extend8bithi1 (r_hi)); + } + r_fill = r_hi; + } + else + { + gcc_assert (ST_lshr == shift_type); + if (QImode == opmode) + emit_insn (gen_rlaqi1 (r_qi)); + else + emit_insn (gen_rlahi1 (r_hi)); + emit_move_insn (r_hi, const0_rtx); + emit_insn (gen_rlchi1 (r_hi)); + } + + if (QImode == opmode) + emit_insn (gen_storeqi2 (r_dst, r_hi)); + 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_hi : r_fill); + } +} + +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]; + 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_BITSIZE (opmode); + operands[2] = GEN_INT (count); + } + else + count = -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_BITSIZE (opmode) - 1) + { + expand_shift_bitsizem1 (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. */ + if (!optimize_function_for_size_p (cfun) && 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_loadqi2 (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]) + { + for (pi = 0; pi < nparts; ++pi) + op_parts[pi] = gen_reg_rtx (HImode); + } + + 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_loadqi2 + (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_loadqi2 + (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 (0 < count && msp430_cpu & MSP430_CPU_MSP430X && !op_is_mem && 1 == nparts) + { + rtx (*gen_shift_m) (rtx, rtx, rtx); + + gen_shift_m = left_shift ? gen_ashlhi_m : (arith_shift ? gen_ashrhi_m : gen_lshrhi_m); + while (count >= MSP430_CPUX_MULTISHIFT_MAX) + { + emit_insn (gen_shift_m + (op_parts[pmin], op_parts[pmin], + GEN_INT (MSP430_CPUX_MULTISHIFT_MAX))); + count -= MSP430_CPUX_MULTISHIFT_MAX; + } + if (count) + { + emit_insn (gen_shift_m + (op_parts[pmin], 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 r_cnt = NULL_RTX; + rtx l_top = NULL_RTX; + rtx l_bottom = NULL_RTX; + rtx t_ne = NULL_RTX; + rtx t_eq = 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 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 = + (GET_MODE_SIZE (opmode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + 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) + { + r_cnt = gen_reg_rtx (QImode); + l_top = gen_label_rtx (); + t_ne = gen_rtx_NE (QImode, r_cnt, const0_rtx); + + if (0 < count) + emit_move_insn (r_cnt, GEN_INT (count)); + else + { + l_bottom = gen_label_rtx (); + t_eq = gen_rtx_EQ (QImode, r_cnt, const0_rtx); + emit_move_insn (r_cnt, operands[2]); + emit_insn (gen_andqi3 + (r_cnt, r_cnt, + GEN_INT (GET_MODE_BITSIZE (GET_MODE (r_dst)) - 1))); + emit_jump_insn (gen_cbranchqi4 + (t_eq, r_cnt, const0_rtx, l_bottom)); + } + emit_label (l_top); + count = 1; + } + + while (count--) + emit_insn (gen_shift_1 (r_dst)); + + 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); +} + +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; +} + +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); + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) + { + 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 + { + 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; +} + +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); +} + +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"); +} + +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); +} + +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"); + +} + +/* ---------------------------------------------------------------------------------------------------------------------------------------------- */ + +static bool +msp430_rtx_cost (rtx x, int code, int outer_code 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 is_430x = msp430_cpu & MSP430_CPU_MSP430X; + 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_BITSIZE (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_BITSIZE (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 (is_430x && 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_BITSIZE (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; +} + +static int +msp430_address_cost (rtx x, bool speed) +{ + /* Nothing special now; at some point auto increment/decrement might + * affect this. */ + return rtx_cost (x, MEM, speed); +} + +/* 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} +}; + +static void +msp430_globalize_label (FILE * stream, const char *name) +{ + if (*name == '*' || *name == '@') + name++; + if (*name >= '0' && *name <= '9') + return; + fputs (".global\t", stream); + assemble_name (stream, name); + putc ('\n', stream); +} + +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; +} + +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; +} + +/* 17.2 Driver -- no hooks */ +/* 17.3 Run-time Target */ +#undef TARGET_OPTION_OPTIMIZATION_TABLE +#define TARGET_OPTION_OPTIMIZATION_TABLE msp430_option_optimization_table + +/* 17.4 Per-Function Data -- no hooks*/ +/* 17.5: Storage Layout */ + +/* 17.6 Type Layout */ +/* SF 3191528: TARGET_DEFAULT_SHORT_ENUMS */ + +/* 17.7 Registers */ + +/* 17.8 Register Classes */ +/* TODO TARGET_IRA_COVER_CLASSES seems important */ + +/* 17.9 Old Constraints */ + +/* 17.10 Stack and Calling */ +/* 17.10.5 Elimination */ +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE msp430_can_eliminate +/* 17.10.8 Scalar Return */ +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE msp430_function_value +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE msp430_libcall_value +/* 17.19.9 Aggregate Return */ +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY msp430_return_in_memory +/* 17.10.11 Function Entry */ +#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 */ +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE msp430_asm_trampoline_template +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT msp430_trampoline_init + +/* 17.13 Library Calls */ +#undef TARGET_INIT_LIBFUNCS +#define TARGET_INIT_LIBFUNCS msp430_init_libfuncs + +/* 17.14 Addressing Modes */ +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p + +/* 17.15 Anchored Addresses */ + +/* 17.16 Condition Code */ + +/* 17.17 Costs */ +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS msp430_rtx_cost +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST msp430_address_cost + +/* 17.18 Scheduling */ + +/* 17.19 Sections */ +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION msp430_select_section + +/* 17.20 PIC -- not supported */ + +/* 17.21 Assembler Format */ +/* 17.21.1 File Framework */ +#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 */ +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS msp430_section_type_flags +/* 17.21.2 Data Output */ +/* TODO: Verify these */ +#undef TARGET_ASM_ALIGNED_HI_OP +#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" +/* 17.21.4 Label Output */ +#undef TARGET_ASM_GLOBALIZE_LABEL +#define TARGET_ASM_GLOBALIZE_LABEL msp430_globalize_label +/* 17.21.9 Assembler Commands for Exception Regions */ +#undef TARGET_EXCEPT_UNWIND_INFO +#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info + +/* 17.25 Target Attributes */ +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table +#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 */ +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS msp430_init_builtins +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN msp430_expand_builtin +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION msp430_set_current_function +#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.6.3.orig/gcc/config/msp430/msp430.h gcc-4.6.3/gcc/config/msp430/msp430.h new file mode 100644 index 0000000..79ee686 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430.h @@ -0,0 +1,826 @@ +/* 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. */ + +/* 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 20120406 + +/** 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; + +extern msp430_cpu_e msp430_cpu; +extern msp430_mpy_e msp430_mpy; +extern int msp430_ivcnt; +extern int msp430_has_hwmul; + +#define MSP430_HAS_HWMUL_INTERNAL (msp430_has_hwmul) + +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) + +/* 16.19.5 Insn Lengths */ +#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ + (LENGTH = msp430_adjust_insn_length (INSN, LENGTH)) + +/* 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 normalize any legacy mcu descriptions, + * then ensure we have -mcpu and -mmpy configurations derived from + * the mcu. */ +#define DRIVER_SELF_SPECS \ + "%:include-noerr(msp430mcu.spec)" \ + " %(msp430_cpu)" \ + " %(msp430_mpy)" \ + " %(msp430_ivcnt)" +/* 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}" +#define ENDFILE_SPEC \ + "%{mno-disable-watchdog|!mdisable-watchdog:-lcrt0; :-lcrt0dwdt}" +extern const char *msp430_mcucpp (int argc, const char **argv); +extern const char *msp430_mculdscriptpaths (int argc, const char **argv); +#define EXTRA_SPEC_FUNCTIONS \ + { "msp430_mcucpp", msp430_mcucpp }, \ + { "msp430_mculdscriptpaths", msp430_mculdscriptpaths }, +#define EXTRA_SPECS \ + { "msp430_cpu", "%{!mcpu=*:%{mcpu=430}}" }, \ + { "msp430_mpy", "%{!mmpy=*:%{mmpy=none}}" }, \ + { "msp430_ivcnt", "%{!mivcnt=*:%{mivcnt=16}}" }, +/* 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) \ + %{"PLUGIN_COND": \ + -plugin %(linker_plugin_file) \ + -plugin-opt=%(lto_wrapper) \ + -plugin-opt=-fresolution=%u.res \ + %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \ + }"PLUGIN_COND_CLOSE" \ + %{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 CONSTANT_ADDRESS_P(X) (CONSTANT_P (X) && GET_CODE (X) != CONST_DOUBLE) +#define MAX_REGS_PER_ADDRESS 1 +#define LEGITIMATE_CONSTANT_P(X) 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)==SImode ? 2 : \ + (MODE)==SFmode ? 2 : 4) +/* TODO: SF 3192592 */ +#define MEMORY_MOVE_COST(MODE, CLASS, IN) ((MODE)==QImode ? 2 : \ + (MODE)==HImode ? 2 : \ + (MODE)==SImode ? 4 : \ + (MODE)==SFmode ? 4 : 8) +/* TODO: SF 3192592 */ +#define BRANCH_COST(SPEED_P, PREDICTABLE_P) 0 +/* TODO: SF 3192592 */ +#define SLOW_BYTE_ACCESS 0 +#define NO_FUNCTION_CSE + +/* 17.18 Scheduling */ + +/* 17.19 Sections */ +/* See also 17.21.6 for CTORS/DTORS */ +#define TEXT_SECTION_ASM_OP "\t.text" +#define DATA_SECTION_ASM_OP "\t.data" +#define BSS_SECTION_ASM_OP "\t.section\t.bss" +#define READONLY_DATA_SECTION_ASM_OP "\t.section\t.rodata" + +/* 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" +/* Define this hook here so TARGET_HAVE_NAMED_SECTIONS is defaulted to + * true in c-common.c */ +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section +/* 17.21.2 Data Output */ +#define ASM_OUTPUT_ASCII(FILE, P, SIZE) gas_output_ascii (FILE, P, SIZE) +/* TODO: this is probably a misinterpretation of "logical line separator" */ +#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == '\n') +/* 17.21.3 Uninitialized Data */ +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + do { \ + const char *p = NAME; \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + fputs ("\t.comm ", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ",%lu%s", (unsigned long)(SIZE), (SIZE)>1?",2\n":"\n"); \ + } while (0) +#define ASM_OUTPUT_BSS(FILE, DECL, NAME, SIZE, ROUNDED) \ + do { \ + const char *p = (NAME); \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + asm_output_bss ((FILE), (DECL), (NAME), (SIZE), (ROUNDED)); \ + } while(0) +#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ + do { \ + const char *p = NAME; \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + fputs ("\t.local ", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fputs ("\n",(STREAM)); \ + fputs ("\t.comm ", (STREAM)); \ + assemble_name ((STREAM), (NAME)); \ + fprintf ((STREAM), ",%lu%s", (unsigned long)(SIZE),(SIZE)>1?",2\n":"\n"); \ + } while (0) +/* 17.21.4 Label Output */ +/* TODO: what's this workaround for? came in at mspgcc4 */ +#define ASM_OUTPUT_LABEL(STREAM, NAME) \ + { \ + int __msp430_data_name_workaround = (((NAME)[0] == '*') && ((NAME)[1] == '0')); \ + if (__msp430_data_name_workaround) \ + { \ + static int repeatable_pseudolabels_resolver = 0; \ + fprintf (STREAM, "__"); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "_%d", ++repeatable_pseudolabels_resolver); \ + } \ + else \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ":\n"); \ + } +#define SIZE_ASM_OP "\t.size\t" +#define TYPE_ASM_OP "\t.type\t" +#define TYPE_OPERAND_FMT "@%s" +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + msp430_asm_declare_function_name (FILE, NAME, DECL) +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do { \ + if (!flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_LABEL (FILE, label); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE,"\n;; End of function \n\n"); \ + } \ + } while (0) +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ + do { \ + int __msp430_data_name_workaround = (((NAME)[0] == '*') && ((NAME)[1] == '0')); \ + if (__msp430_data_name_workaround) \ + fprintf (FILE, "#"); \ + fprintf (FILE, "%s", "\t.type\t"); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + if (__msp430_data_name_workaround) \ + fprintf (FILE, "#"); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, ",%lu\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + } while (0) +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ + do { \ + const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + fprintf (FILE, ",%lu\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + } while (0) +#define ASM_WEAKEN_LABEL(FILE, NAME) \ + do \ + { \ + fputs ("\t.weak\t", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fputc ('\n', (FILE)); \ + } \ + while (0) +#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \ + sprintf (STRING, "*.%s%lu", PREFIX, (unsigned long)NUM) +#define SUPPORTS_WEAK 1 +/* 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) +#define SET_ASM_OP "\t.set\t" +/* 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 "\t.global\t__do_global_ctors\n\t.section\t.ctors" +#define DTORS_SECTION_ASM_OP "\t.global\t__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) \ +{ \ + gcc_assert (MSP430_HARD_REGISTER_NUM_P(REGNO)); \ + fprintf (STREAM, "\tpush\tr%d", REGNO); \ +} +#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ +{ \ + gcc_assert (MSP430_HARD_REGISTER_NUM_P(REGNO)); \ + fprintf (STREAM, "\tpop\tr%d", REGNO); \ +} +/* 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_SKIP(STREAM, N) \ + fprintf (STREAM, "\t.skip %lu,0\n", (unsigned long)N) +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ + fprintf (STREAM, "\t.p2align %d,0\n", POWER) + +/* 17.22 Debugging Info */ +/* 17.22.1 All Debuggers */ +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG +/* 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_DEBUGGING_INFO 1 +/* 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 HImode +#define MOVE_MAX 2 +#define SHIFT_COUNT_TRUNCATED 1 +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 +#define Pmode HImode +#define FUNCTION_MODE HImode +#define REGISTER_TARGET_PRAGMAS() do { \ + c_register_pragma_with_expansion (0, "vector", msp430_pr_vector); \ + } while (0) +#define DOLLARS_IN_IDENTIFIERS 0 +#define NO_DOLLAR_IN_LABEL 1 + +/* Undocumented but legitimate */ +#define OBJECT_FORMAT_ELF + +/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +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 +}; + +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; +}; diff --git gcc-4.6.3.orig/gcc/config/msp430/msp430.md gcc-4.6.3/gcc/config/msp430/msp430.md new file mode 100644 index 0000000..d07ddea --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430.md @@ -0,0 +1,1344 @@ +;; -*- 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_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 "type" "branch,branch1,arith" + (const_string "arith")) + +(define_attr "msp430_has_hwmul" "yes,no" + (const (if_then_else (symbol_ref "MSP430_HAS_HWMUL_INTERNAL") + (const_string "yes") + (const_string "no")))) + +(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) +; fmtx : MSP430X, two words : no extension word, single-operand +(define_attr "instr_format" + "undef,fmt1,fmt2,fmt2s,emu1dd,condjmp" + (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" "fmt1,emu1dd") ; insn, src word, dst word + (mult (const_int 6) (attr "instr_mult")) + (eq_attr "instr_format" "fmt2,fmt2s") ; insn, dst 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))) + +;; 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]) + +;; Integer modes that can be widened +(define_mode_iterator WidenableINTModes [SI HI QI]) + +;; Integer modes +(define_mode_iterator INTModes [DI SI 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 + (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 allow anything + (HI "UmQi") + (SI "rmQi") ; SI, DI remove frame and stack pointer + (DI "rmQi")]) + +(define_mode_attr INTModes_constraint_matchdst + [(QI "0") + (HI "0") + (SI "0") + (DI "0")]) + +; Variant for commutative operations +(define_mode_attr INTModes_commutative_matchdst + [(QI "%0") + (HI "%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 + (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") ; SI, DI remove frame and stack pointer + (SI "rmQi") + (DI "rmQi")]) + +; For LSW-first arithmetic on values that might be multiple words +(define_mode_attr INTModes_cc_VNZC + [(QI "VNZC") + (HI "VNZC") + (SI "N") + (DI "N")]) + +(define_mode_attr INTModes_cc_NZC + [(QI "NZC") + (HI "NZC") + (SI "N") + (DI "N")]) + +(define_mode_attr INTModes_cc_NZ + [(QI "NZ") + (HI "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") + (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")]) + +;; Integer modes that fit in a single register +(define_mode_iterator INTRegModes [HI QI]) + +;; ================== +;; 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))] + "" + "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))] + "" + "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))] + "" + "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))] + "" + "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))] + "" + "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))] + "" + "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))] + "" + "bic\t%1, %0" + [(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))] + "" + "bis\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; read_stack_pointer(retloc) +(define_insn "read_stack_pointer" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (unspec_volatile:HI [(reg:HI REGNO_SP)] UNSPECV_READ_STACK_POINTER))] + "" + "mov\tr1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; write_stack_pointer(sr_value) +(define_insn "write_stack_pointer" + [(set (reg:HI REGNO_SP) + (unspec_volatile:HI [(match_operand:HI 0 "msp430_source_operand" "rmQi")] UNSPECV_WRITE_STACK_POINTER))] + "" + "mov\t%0, r1" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; 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")]) + +; 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))] + "" + "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)] + "" + "mov\t%0, &__wdt_clear_value" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; watchdog_clear() +(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 "extend8bithi1" + [(set (match_operand:HI 0 "nonimmediate_operand" "+rmQ") + (sign_extend:HI (subreg:QI (match_dup 0) 0)))] + "" + "sxt\t%0" + [(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 "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_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;") + +;; 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")))] + "" +"swpb\t%0" + [(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:HI (reg:HI REGNO_SP) (plus:HI (reg:HI REGNO_SP) (const_int -2)))) + (match_operand:QI 0 "general_operand" "rmi"))] + "" + "push.b\t%S0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s")]) + +(define_insn "loadqi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "msp430_source_operand" "UmQi")))] + "" + "mov.b\t%1, %0" + [(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))] + "" + "mov.b\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*movqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=rm") + (match_operand:QI 1 "msp430_source_operand" "UmQi"))] + "" + "mov.b\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + "") + +; pushmhi2(num_regs, high_regno) +(define_insn "pushmhi2" + [(set (reg:HI REGNO_SP) + (unspec:HI [(match_operand:HI 0 "const_int_operand" "i") + (match_operand:HI 1 "const_int_operand" "N")] + UNSPEC_PUSH_MULTI))] + "" + { + rtx xoperands[2]; + xoperands[0] = operands[0]; + xoperands[1] = gen_rtx_REG (HImode, INTVAL (operands[1])); + output_asm_insn ("pushm\t%0, %1", xoperands); + return ""; + } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s")]) + +; popmhi2(num_regs, high_regno) +(define_insn "popmhi2" + [(set (reg:HI REGNO_SP) + (unspec:HI [(match_operand:HI 0 "const_int_operand" "i") + (match_operand:HI 1 "const_int_operand" "N")] + UNSPEC_POP_MULTI))] + "" + { + rtx xoperands[2]; + xoperands[0] = operands[0]; + xoperands[1] = gen_rtx_REG (HImode, INTVAL (operands[1])); + output_asm_insn ("popm\t%0, %1", xoperands); + return ""; + } + [(set_attr "cc" "none") ; not true if REGNO_SR covered + (set_attr "instr_format" "fmt2s")]) + +(define_insn "pushhi1" + [(set (mem:HI (pre_dec:HI (reg:HI REGNO_SP))) + (match_operand:HI 0 "general_operand" "Wmi"))] + "" + "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:HI (reg:HI REGNO_SP))))] + "" + "pop\t%0" + [(set_attr "cc" "none,clobber") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*movhi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=Um") + (match_operand:HI 1 "msp430_source_operand" "UmQi"))] + "" + "mov\t%1, %0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + "") + +(define_insn "*pushm1" + [(set (mem:SISF (pre_dec:HI (reg:HI REGNO_SP))) + (match_operand:SISF 0 "register_operand" "r"))] + "msp430_cpu & MSP430_CPU_MSP430X" + "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:HI (reg:HI REGNO_SP))) + (match_operand:SISF 0 "general_operand" "ST,rmi"))] + "" + "@ +push\t2+%S0\;push\t2+%S0 +push\t%B0\;push\t%A0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s") + (set_attr "instr_mult" "2")]) + +(define_insn "*mov2" + [(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_expand "mov" + [(set (match_operand:SISF 0 "nonimmediate_operand" "") + (match_operand:SISF 1 "general_operand" ""))] + "" + "") + +(define_insn "*pushmdi1" + [(set (mem:DI (pre_dec:HI (reg:HI REGNO_SP))) + (match_operand:DI 0 "register_operand" "r"))] + "msp430_cpu & MSP430_CPU_MSP430X" + "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:HI (reg:HI REGNO_SP))) + (match_operand:DI 0 "general_operand" "ST,rmi"))] + "" + "@ +push\t6+%S0\;push\t6+%S0\;push\t6+%S0\;push\t6+%S0 +push\t%D0\;push\t%C0\;push\t%B0\;push\t%A0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt2s") + (set_attr "instr_mult" "4")]) + +(define_insn "*movdi2" + [(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")]) + +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + "") + +;; 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 "*add3_std" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (plus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "" + { return msp430_output_template (mode, 2, "add", "addc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*sub3_std" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (minus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "" + { return msp430_output_template (mode, 2, "sub", "subc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt1")]) + +(define_expand "add3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (plus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "general_operand" "")))] + "" + "") + +(define_expand "sub3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (minus: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "general_operand" "")))] + "" + "") + +;; one_cmplm2 (invert) + +(define_expand "one_cmpl2" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (not: (match_operand: 1 "nonimmediate_operand" "")))] + "" + { + if (! rtx_equal_p (operands[0], operands[1])) + { + emit_move_insn (operands[0], operands[1]); + operands[1] = operands[0]; + } + }) + +(define_insn "*one_cmpl2_insn" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "=rm") + (not: (match_operand: 1 "nonimmediate_operand" "0")))] + "" + { return msp430_output_template (mode, 0, "inv", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +;; negm2 + +(define_insn "negsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] + "" + "xor\t#0x8000, %B0" + [(set_attr "cc" "clobber") + (set_attr "length" "4,6")]) + +(define_expand "neg2" + [(match_operand:INTModes 0 "nonimmediate_operand" "") + (match_operand: 1 "general_operand" "")] + "" + { + 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:INTModes 0 "nonimmediate_operand" "") + (and: (not: (match_operand: 1 "msp430_source_operand" "")) + (match_operand: 2 "general_operand" "")))] + "" + { return msp430_output_template (mode, 1, "bic", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +; 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:INTModes 0 "nonimmediate_operand" "") + (and: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "" + { return msp430_output_template (mode, 2, "and", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt1")]) + +(define_insn "ior3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (ior: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "" + { return msp430_output_template (mode, 2, "bis", NULL, NULL); } + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +(define_insn "xor3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (xor: (match_operand: 1 "nonimmediate_operand" "") + (match_operand: 2 "msp430_source_operand" "")))] + "" + { return msp430_output_template (mode, 2, "xor", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt1")]) + +;; absm2 +(define_expand "abs2" + [(match_operand:INTModes 0 "nonimmediate_operand" "") + (match_operand: 1 "general_operand" "")] + "" + { + 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")))] + "" + "and\t#0x7fff, %B0" + [(set_attr "cc" "clobber,clobber") + (set_attr "length" "2,3")]) ; BAD LENGTH + +;; strlenm + +(define_expand "strlenhi" + [(match_operand:HI 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")] + "" + { + 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_subhi3 (sp_rtx, sp_rtx, const1_rtx)); + emit_label (loop_label); + emit_insn (gen_addhi3 (sp_rtx, sp_rtx, const1_rtx)); + emit_jump_insn (gen_cbranchqi4 (test_ne, sp_deref_rtx, guard_rtx, loop_label)); + emit_insn (gen_subhi3 (operands[0], sp_rtx, XEXP (operands[1], 0))); + DONE; + }) + +;;======================================================================== +;; compare + +(define_expand "cbranch4" + [(set (cc0) (compare + (match_operand:INTModes 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)))] + "" + { msp430_expand_cbranch (operands); DONE; }) + +(define_insn "setcc2" + [(set (cc0) (compare + (match_operand:INTRegModes 0 "nonimmediate_operand" "Um") + (match_operand: 1 "general_operand" "Umi")))] + "" + { return msp430_output_template (mode, 1, "cmp", NULL, NULL); } + [(set_attr "cc" "explicit") + (set_attr "instr_format" "fmt1")]) + +(define_insn "*bittest2" + [(set (cc0) (compare + (and:INTRegModes + (match_operand: 0 "nonimmediate_operand" "Um") + (match_operand: 1 "general_operand" "Umi")) + (const_int 0)))] + "" + { return msp430_output_template (mode, 1, "bit", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt1")]) + +(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_expand "call" + [(call (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + "") + +(define_insn "*call_insn" + [(call (mem:HI (match_operand:HI 0 "general_operand" "rmi")) + (match_operand:HI 1 "general_operand" "X"))] + "" + "call\t%S0" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2s")]) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "") + (call (match_operand:HI 1 "general_operand" "") + (match_operand:HI 2 "general_operand" "")))] + "" + "") + +(define_insn "*call_value_insn" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:HI (match_operand:HI 1 "general_operand" "rmi")) + (match_operand:HI 2 "general_operand" "X")))] + "" + "call\t%S1" + [(set_attr "cc" "clobber") + (set_attr "instr_format" "fmt2s")]) + +;;======================================================================== +;; Multiplication + +(define_insn "mpy_inhibit_intr" + [(set (mem:HI (pre_dec:HI (reg:HI REGNO_SP))) + (unspec_volatile:HI [(const_int 0)] UNSPECV_MPY_INHIBIT_INTR))] + "" + "push\tr2\;dint\;nop" + [(set_attr "cc" "none") + (set_attr "length" "6")]) + +(define_insn "mpy_restore_intr" + [(set (mem:HI (post_inc:HI (reg:HI REGNO_SP))) + (unspec_volatile:HI [(const_int 0)] UNSPECV_MPY_RESTORE_INTR))] + "" + "pop\tr2" + [(set_attr "cc" "clobber") + (set_attr "length" "2")]) + +(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 operations + +(define_insn "trunchiqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,m") + (truncate:QI (match_operand:HI 1 "register_operand" "r,r")))] + "" + "mov.b\t%1, %0" + [(set_attr "cc" "none,none") + (set_attr "length" "1,2")]) ; BAD LENGTH + +(define_insn "truncsihi" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "register_operand" "r")))] + "" + "mov\t%1, %0" + [(set_attr "cc" "none") + (set_attr "length" "1")]) ; BAD LENGTH + + +(define_insn "truncsiqi" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "register_operand" "r")))] + "" + "mov.b\t%1, %0" + [(set_attr "cc" "none") + (set_attr "length" "1")]) ; BAD LENGTH + +(define_insn "truncdiqi" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:DI 1 "register_operand" "r")))] + "" + "mov.b\t%1, %0" + [(set_attr "cc" "none") + (set_attr "length" "1")]) ; BAD LENGTH + +(define_insn "truncdisi" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI (match_operand:DI 1 "register_operand" "r")))] + "" + "mov\t%A1, %A0\;mov\t%B1, %B0" + [(set_attr "cc" "none") + (set_attr "length" "2")]) ; BAD LENGTH + +(define_expand "ashl3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (ashift: (match_operand: 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "msp430_expand_ashl (operands); DONE;") + +(define_expand "ashr3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (ashiftrt: (match_operand: 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "msp430_expand_ashr (operands); DONE;") + +(define_expand "lshr3" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "") + (lshiftrt: (match_operand: 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] + "" + "msp430_expand_lshr (operands); DONE;") + +;; 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")]) + +;; Arithmetic shift left multiple positions + +(define_expand "ashlhi_m" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] + "" + "") + +(define_insn "*ashlhi_m_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "M")))] + "msp430_cpu & MSP430_CPU_MSP430X && 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" "fmt2")]) + +;; Arithmetic shift right multiple positions + +(define_expand "ashrhi_m" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] + "" + "") + +(define_insn "*ashrhi_m_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "M")))] + "msp430_cpu & MSP430_CPU_MSP430X && 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" "fmt2")]) + +(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")]) + +;; Logical shift right multiple positions (CPUX, HI only) + +(define_expand "lshrhi_m" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "const_int_operand" "")))] + "" + "") + +(define_insn "*lshrhi_1_x" + [(set (match_operand:HI 0 "nonimmediate_operand" "+r") + (lshiftrt:HI (match_dup 0) (const_int 1)))] + "msp430_cpu & MSP430_CPU_MSP430X" + "rrum\t#1, %0" + [(set_attr "cc" "NZ") + (set_attr "instr_format" "fmt2")]) + +(define_insn "*lshrhi_m_insn" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "M")))] + "msp430_cpu & MSP430_CPU_MSP430X && 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" "fmt2")]) + +;; Basic single-position shifts + +(define_insn "ashl_1" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "+rm") + (ashift: (match_dup 0) (const_int 1))) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_template (mode, 0, "rla", "rlc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "emu1dd")]) ; emulated add dst, dst + +(define_insn "rla1" + [(set (match_operand:INTRegModes 0 "nonimmediate_operand" "+rm") + (ashift: + (unspec_volatile [(match_dup 0)] UNSPECV_RLA) + (const_int 1)))] + "" + { return msp430_output_template (mode, 0, "rla", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "emu1dd")]) ; emulated add dst, dst + +(define_insn "rlc1" + [(set (match_operand:INTRegModes 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, 0, "rlc", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "emu1dd")]) ; emulated add dst, dst + +(define_insn "ashr_1" + [(set (match_operand:INTModes 0 "nonimmediate_operand" "+rm") + (ashiftrt: (match_dup 0) (const_int 1))) + (clobber (reg:CC REGNO_SR))] + "" + { return msp430_output_reverse_template (mode, 0, "rra", "rrc", NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(define_insn "rra1" + [(set (match_operand:INTRegModes 0 "nonimmediate_operand" "+rm") + (ashiftrt: + (unspec_volatile [(match_dup 0)] UNSPECV_RRA) + (const_int 1)))] + "" + { return msp430_output_reverse_template (mode, 0, "rra", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(define_insn "rrc1" + [(set (match_operand:INTRegModes 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, 0, "rrc", NULL, NULL); } + [(set_attr "cc" "") + (set_attr "instr_format" "fmt2")]) + +(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, 0, "rrc", NULL, "clrc"); } + [(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)))] + "msp430_cpu & MSP430_CPU_MSP430X" + "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, 0, "rrc", NULL, "clrc"); } + [(set_attr "cc" "") + (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, 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 (dist<500 && dist>-500) + return "jmp\t%0"; + return "br\t#%0"; + } + [(set_attr "cc" "none") + (set_attr "length" "2")]) + +; indirect jump +(define_insn "indirect_jump" + [(set (pc) (match_operand:HI 0 "general_operand" "rmi"))] + "" + "br\t%0" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + + +;; Table helper +(define_insn "tablejump" + [(set (pc) (match_operand:HI 0 "general_operand" "rRP,i,m")) + (use (label_ref (match_operand 1 "" "")))] + "" + "br\t%0\t; %1" + [(set_attr "cc" "none") + (set_attr "instr_format" "fmt1")]) + +;; 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\t#"); + 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))" + "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.6.3.orig/gcc/config/msp430/msp430.opt gcc-4.6.3/gcc/config/msp430/msp430.opt new file mode 100644 index 0000000..885eee9 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/msp430.opt @@ -0,0 +1,57 @@ +; 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)". + +mdisable-hwmul +Target Report Mask(NO_HWMUL) +Disable hardware multiplier (DEPRECATED; use -mmpy=none) + +minline-hwmul +Target Report Mask(INLINESIHWMUL) +Issue inline multiplication code for 32-bit integers + +mnoint-hwmul +Target Report Mask(NOINT_HWMUL) +Assume interrupt routine does not do hardware multiply + +mno-volatile-workaround +Target Report Mask(NVWA) +(OBSOLETE) Do not perform volatile workaround for bitwise operations + +msave-prologue +Target Report Mask(SAVE_PROLOGUE) +Use subroutine call for function prologue/epilogue when possible + +mdisable-watchdog +Target Var(msp430_disable_watchdog) Init(0) +Link the crt0 modules that disable the watchdog on startup + +menable-libcall-shift +Target Var(msp430_enable_libcall_shift) Init(0) +Use library routines for non-constant shifts + +; ---------------------------------------- Here start the string options imported from TARGET_OPTIONS macro ---------------------------------------- + +mmcu= +Target RejectNegative Joined Var(msp430_mcu_name) +-mmcu=MCU Select the target MCU + +mcpu= +Target RejectNegative Joined Var(msp430_opt_cpu) +-mcpu=CPU Select the CPU model: 430, 430x, 430xv2 + +mmpy= +Target RejectNegative Joined Var(msp430_opt_mpy) +-mmpy=MPY Define available hardware multiply: none, 16, 16se, 32, 32dw + +mivcnt= +Target RejectNegative Joined Var(msp430_opt_ivcnt) +-mivcnt=IVCNT Specify number of interrupt vectors on chip: 16, 32, 64 diff --git gcc-4.6.3.orig/gcc/config/msp430/peephole.md gcc-4.6.3/gcc/config/msp430/peephole.md new file mode 100644 index 0000000..907c615 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/peephole.md @@ -0,0 +1,235 @@ +;; -*- 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 &m3, r2; op4 g5, r2; mov r2, @r0 => op g4, &c1 [r0 dead, r2 dead] +; see testsuite vwa4.c +(define_peephole2 + [(set (match_operand 0 "pmode_register_operand" "") + (match_operand 1 "immediate_operand" "")) + (set (match_operand:INTRegModes 2 "register_operand" "") + (match_operand: 3 "nonimmediate_operand" "")) + (set (match_dup 2) + (match_operator: 4 "msp430_rmw_operator" + [(match_dup 2) + (match_operand: 5 "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 4 [(mem: (match_dup 1)) (match_dup 5)]))] + "") + + +;; 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_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 "" "")))] + "") + diff --git gcc-4.6.3.orig/gcc/config/msp430/predicates.md gcc-4.6.3/gcc/config/msp430/predicates.md new file mode 100644 index 0000000..10f29b5 --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/predicates.md @@ -0,0 +1,45 @@ +;; -*- 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 +(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"))) + +;; Identify identity comparisons +(define_special_predicate "equality_operator" + (match_code "eq,ne")) + diff --git gcc-4.6.3.orig/gcc/config/msp430/t-msp430 gcc-4.6.3/gcc/config/msp430/t-msp430 new file mode 100644 index 0000000..e58c19a --- /dev/null +++ gcc-4.6.3/gcc/config/msp430/t-msp430 @@ -0,0 +1,164 @@ +# Specific names for MSP430 tools +AR_FOR_TARGET = msp430-ar +RANLIB_FOR_TARGET = msp430-ranlib +NM_FOR_TARGET = msp430-nm + +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 \ + _udivmod32 \ + _divmod32 \ + _udivmod64 \ + _divmod64 \ + __prologue_saver \ + __epilogue_restorer \ + __epilogue_restorer_intr \ + _ashlqi3 \ + _ashrqi3 \ + _lshrqi3 \ + _ashlhi3 \ + _ashrhi3 \ + _lshrhi3 \ + _ashlsi3 \ + _ashrsi3 \ + _lshrsi3 \ + _ashldi3 \ + _ashrdi3 \ + _lshrdi3 + +# libgcc... +LIBGCC1_TEST = + +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_FOR_TARGET) $(MULTILIB_CFLAGS) -DL$(*F) -xassembler-with-cpp \ + -o $*.o -c $(srcdir)/config/$(CRT0ASMSRC) + +$(T)libcrt0.a: $(crt0asmfuncs-o) + -rm -f $@ + $(AR) $(ARFLAGS) $@ $^ + $(RANLIB) $@ + +EXTRA_MULTILIB_PARTS += $(T)libcrt0.a + +crt0asmfuncs-dwdt-o = $(patsubst %,$(T)%-dwdt$(objext),$(CRT0ASMFUNCS)) + +$(crt0asmfuncs-dwdt-o): %-dwdt$(objext): $(srcdir)/config/$(CRT0ASMSRC) + $(GCC_FOR_TARGET) -DWITH_DISABLE_WDT $(MULTILIB_CFLAGS) -DL$(*F) -xassembler-with-cpp \ + -o $*-dwdt.o -c $(srcdir)/config/$(CRT0ASMSRC) + +$(T)libcrt0dwdt.a: $(crt0asmfuncs-dwdt-o) + -rm -f $@ + $(AR) $(ARFLAGS) $@ $^ + $(RANLIB) $@ + +EXTRA_MULTILIB_PARTS += $(T)libcrt0dwdt.a + +# Interrupt vector tables. Not part of crt0 because this is completely +# orthogonal to multilib, and we need three alternatives. +EXTRA_PARTS += crt0ivtbl16$(objext) crt0ivtbl32$(objext) crt0ivtbl64$(objext) + +$(T)crt0ivtbl16.o: $(srcdir)/config/msp430/crt0ivtbl.S $(GCC_PASSES) + $(GCC_FOR_TARGET) -c -DINTERRUPT_VECTOR_COUNT=16 \ + $(srcdir)/config/msp430/crt0ivtbl.S \ + -o $(T)crt0ivtbl16$(objext) + +$(T)crt0ivtbl32.o: $(srcdir)/config/msp430/crt0ivtbl.S $(GCC_PASSES) + $(GCC_FOR_TARGET) -c -DINTERRUPT_VECTOR_COUNT=32 \ + $(srcdir)/config/msp430/crt0ivtbl.S \ + -o $(T)crt0ivtbl32$(objext) + +$(T)crt0ivtbl64.o: $(srcdir)/config/msp430/crt0ivtbl.S $(GCC_PASSES) + $(GCC_FOR_TARGET) -c -DINTERRUPT_VECTOR_COUNT=64 \ + $(srcdir)/config/msp430/crt0ivtbl.S \ + -o $(T)crt0ivtbl64$(objext) + +# 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 + +fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/msp430/t-msp430 + echo '#define FLOAT' > fp-bit.c + echo '#define FLOAT_ONLY' >> fp-bit.c + echo '#define CMPtype HItype' >> fp-bit.c + echo '#define DF SF' >> fp-bit.c + echo '#define DI SI' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#define SMALL_MACHINE' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +FPBIT = fp-bit.c + +# 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, currently the msp430 +# back end generates code only for the 16 variant, which works on the other +# variants. The other options map to 16. +TM_MSP430_MPY=none/16 + +MULTILIB_OPTIONS = \ + mcpu=$(subst /,/mcpu=,$(TM_MSP430_CPU)) \ + mmpy=$(subst /,/mmpy=,$(TM_MSP430_MPY)) +MULTILIB_MATCHES = \ + mcpu?430x=mcpu?430xv2 \ + mmpy?16=mmpy?16se \ + mmpy?16=mmpy?32 \ + mmpy?16=mmpy?32dw +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +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 + +EXTRA_GCC_OBJS += msp430-gcc.o + +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.6.3.orig/gcc/configure gcc-4.6.3/gcc/configure index 1960d5a..6fb5855 100755 --- gcc-4.6.3.orig/gcc/configure +++ gcc-4.6.3/gcc/configure @@ -24967,6 +24967,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 | xstormy16 | xtensa) insn="nop" ;; diff --git gcc-4.6.3.orig/gcc/configure.ac gcc-4.6.3/gcc/configure.ac index 505a54d..2310dc6 100644 --- gcc-4.6.3.orig/gcc/configure.ac +++ gcc-4.6.3/gcc/configure.ac @@ -3841,6 +3841,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 | xstormy16 | xtensa) insn="nop" ;; diff --git gcc-4.6.3.orig/gcc/expr.c gcc-4.6.3/gcc/expr.c index 0ccdd2e..f13b3e1 100644 --- gcc-4.6.3.orig/gcc/expr.c +++ gcc-4.6.3/gcc/expr.c @@ -935,7 +935,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; diff --git gcc-4.6.3.orig/gcc/gcc.c gcc-4.6.3/gcc/gcc.c index 75f522e..3dd8846 100644 --- gcc-4.6.3.orig/gcc/gcc.c +++ gcc-4.6.3/gcc/gcc.c @@ -258,6 +258,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 **); @@ -1231,6 +1232,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 }, @@ -8006,6 +8008,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.6.3.orig/gcc/ira-lives.c gcc-4.6.3/gcc/ira-lives.c index 5c5c415..2548cb0 100644 --- gcc-4.6.3.orig/gcc/ira-lives.c +++ gcc-4.6.3/gcc/ira-lives.c @@ -932,16 +932,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 cover_class; @@ -993,13 +991,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.6.3.orig/gcc/testsuite/gcc.target/msp430/bic_sr_irq.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/bic_sr_irq.c new file mode 100644 index 0000000..282fe08 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/bis_sr_irq.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/bis_sr_irq.c new file mode 100644 index 0000000..56f9444 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/bswap.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/bswap.c new file mode 100644 index 0000000..0db1432 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtin_address.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtin_address.c new file mode 100644 index 0000000..9f92c77 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_1.c new file mode 100644 index 0000000..757bdbf --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_bic_sr.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_bic_sr.c new file mode 100644 index 0000000..ee1e6ab --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_bis_sr.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_bis_sr.c new file mode 100644 index 0000000..2f8d023 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_gsistate.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_gsistate.c new file mode 100644 index 0000000..06cbf9b --- /dev/null +++ gcc-4.6.3/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, r14\n" } } */ + sv = __get_interrupt_state(); + /* { dg-final { scan-assembler "mov\t\&svp, r15\n\tmov\tr2, @r15\n" } } */ + *svp = __get_interrupt_state(); + /* { dg-final { scan-assembler "mov\tr14, 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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_read_sr.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_read_sr.c new file mode 100644 index 0000000..f2683c1 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_sp.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_sp.c new file mode 100644 index 0000000..12b54ac --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_swap_bytes.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_swap_bytes.c new file mode 100644 index 0000000..41f4858 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/builtins_write_sr.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/builtins_write_sr.c new file mode 100644 index 0000000..c891527 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/critical_attribute.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/critical_attribute.c new file mode 100644 index 0000000..b60ea3b --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/elimination.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/elimination.c new file mode 100644 index 0000000..22b4334 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/framesaver_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/framesaver_1.c new file mode 100644 index 0000000..c1a29ad --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/framesaver_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/framesaver_2.c new file mode 100644 index 0000000..73978ef --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/gen_return_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/gen_return_1.c new file mode 100644 index 0000000..8dac65e --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/gen_return_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/gen_return_2.c new file mode 100644 index 0000000..12d81a8 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/msp430.exp gcc-4.6.3/gcc/testsuite/gcc.target/msp430/msp430.exp new file mode 100644 index 0000000..735bb9b --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/section_attribute.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/section_attribute.c new file mode 100644 index 0000000..ce69a18 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3090574_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3090574_1.c new file mode 100644 index 0000000..fec0e99 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3090574_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3090574_2.c new file mode 100644 index 0000000..506a4a6 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3104943_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3104943_1.c new file mode 100644 index 0000000..e4079da --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3104943_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3104943_2.c new file mode 100644 index 0000000..26401d9 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3104943_3.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3104943_3.c new file mode 100644 index 0000000..931c4ab --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3104943_4.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3104943_4.c new file mode 100644 index 0000000..a809957 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3104943_5.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3104943_5.c new file mode 100644 index 0000000..69085b2 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3112089.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3112089.c new file mode 100644 index 0000000..ed177ba --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3148801.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3148801.c new file mode 100644 index 0000000..d10da65 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3177314_base.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3177314_base.c new file mode 100644 index 0000000..24a3cf2 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3177314_ext.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3177314_ext.c new file mode 100644 index 0000000..061519d --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3188386.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3188386.c new file mode 100644 index 0000000..877edb2 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3188386_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3188386_2.c new file mode 100644 index 0000000..e18575c --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_1.c new file mode 100644 index 0000000..6a755dc --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_2.c new file mode 100644 index 0000000..3e079a7 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_3.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_3.c new file mode 100644 index 0000000..b9055d4 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_4.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_4.c new file mode 100644 index 0000000..f9c54e8 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_5.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_5.c new file mode 100644 index 0000000..9fdafd5 --- /dev/null +++ gcc-4.6.3/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.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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_6.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_6.c new file mode 100644 index 0000000..92c9937 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_7.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_7.c new file mode 100644 index 0000000..b291112 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3200763_8.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3200763_8.c new file mode 100644 index 0000000..4c2fd4c --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3201686.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3201686.c new file mode 100644 index 0000000..a81bd7a --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3207853.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3207853.c new file mode 100644 index 0000000..ba9072e --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_1.c new file mode 100644 index 0000000..6733638 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_11.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_11.c new file mode 100644 index 0000000..57665af --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_2.c new file mode 100644 index 0000000..e0bd991 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_3.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_3.c new file mode 100644 index 0000000..2d51a60 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_4.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_4.c new file mode 100644 index 0000000..1cc43b9 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_5.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_5.c new file mode 100644 index 0000000..4a7b71f --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_6.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_6.c new file mode 100644 index 0000000..7bca3fb --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_7.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_7.c new file mode 100644 index 0000000..c1df8a6 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3237005_check.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3237005_check.c new file mode 100644 index 0000000..0e02bba --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3257192_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3257192_1.c new file mode 100644 index 0000000..034144b --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3261372.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3261372.c new file mode 100644 index 0000000..f6ab6a3 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3273856.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3273856.c new file mode 100644 index 0000000..ef92512 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3290923.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3290923.c new file mode 100644 index 0000000..2dbbb1b --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3296698.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3296698.c new file mode 100644 index 0000000..eabf89d --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3300205.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3300205.c new file mode 100644 index 0000000..745a80f --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3383371_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3383371_1.c new file mode 100644 index 0000000..23801f5 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3383371_2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3383371_2.c new file mode 100644 index 0000000..1f60be3 --- /dev/null +++ gcc-4.6.3/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#llo\\(-1\\), \&clear_value\n\tmov\t#llo\\(-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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3397068.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3397068.c new file mode 100644 index 0000000..788c352 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3423822_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3423822_1.c new file mode 100644 index 0000000..5307439 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3426468.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3426468.c new file mode 100644 index 0000000..33b9a09 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3428439.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3428439.c new file mode 100644 index 0000000..9e39b86 --- /dev/null +++ gcc-4.6.3/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@r15\\+, r13\n" } } */ + rv += *sv++; + } + return rv; +} diff --git gcc-4.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3433730.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3433730.c new file mode 100644 index 0000000..b8d114f --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3474171.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3474171.c new file mode 100644 index 0000000..3a75a02 --- /dev/null +++ gcc-4.6.3/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.global\t__isr_7\n__isr_7:\n" } } */ + +#define VECT 22 + +#pragma vector=VECT +__attribute__((interrupt)) +void isrD22 () { } +/* { dg-final { scan-assembler "isrD22:\n.global\t__isr_11\n__isr_11:\n" } } */ + +#define PVECT (24) + +#pragma vector=PVECT +__attribute__((interrupt)) +void isrD24 () { } +/* { dg-final { scan-assembler "isrD24:\n.global\t__isr_12\n__isr_12:\n" } } */ diff --git gcc-4.6.3.orig/gcc/testsuite/gcc.target/msp430/sf3474171_1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/sf3474171_1.c new file mode 100644 index 0000000..6223566 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vararg-1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vararg-1.c new file mode 100644 index 0000000..531fd0c --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/volpeep_mem.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/volpeep_mem.c new file mode 100644 index 0000000..d029063 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/volpeep_reg.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/volpeep_reg.c new file mode 100644 index 0000000..4e4fe76 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/volpeep_volmem.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/volpeep_volmem.c new file mode 100644 index 0000000..b58de05 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa1.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa1.c new file mode 100644 index 0000000..cb1432d --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa2.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa2.c new file mode 100644 index 0000000..4f1b344 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa3.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa3.c new file mode 100644 index 0000000..5da9526 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa4.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa4.c new file mode 100644 index 0000000..630c905 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa5.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa5.c new file mode 100644 index 0000000..20bf44f --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa_error.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa_error.c new file mode 100644 index 0000000..20bf9c8 --- /dev/null +++ gcc-4.6.3/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.6.3.orig/gcc/testsuite/gcc.target/msp430/vwa_regression.c gcc-4.6.3/gcc/testsuite/gcc.target/msp430/vwa_regression.c new file mode 100644 index 0000000..cb12a33 --- /dev/null +++ gcc-4.6.3/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\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.6.3.orig/gcc/tree-flow.h gcc-4.6.3/gcc/tree-flow.h index 77948cd..1923454 100644 --- gcc-4.6.3.orig/gcc/tree-flow.h +++ gcc-4.6.3/gcc/tree-flow.h @@ -601,6 +601,7 @@ extern void dump_dominator_optimization_stats (FILE *); extern void debug_dominator_optimization_stats (void); int loop_depth_of_name (tree); tree degenerate_phi_result (gimple); +bool simple_iv_increment_p (gimple); /* In tree-ssa-copy.c */ extern void propagate_value (use_operand_p, tree); diff --git gcc-4.6.3.orig/gcc/tree-ssa-dom.c gcc-4.6.3/gcc/tree-ssa-dom.c index c7614d7..495c506 100644 --- gcc-4.6.3.orig/gcc/tree-ssa-dom.c +++ gcc-4.6.3/gcc/tree-ssa-dom.c @@ -1396,9 +1396,10 @@ record_equality (tree x, tree y) i_1 = phi (..., i_2) i_2 = i_1 +/- ... */ -static bool +bool simple_iv_increment_p (gimple stmt) { + enum tree_code code; tree lhs, preinc; gimple phi; size_t i; @@ -1410,12 +1411,13 @@ simple_iv_increment_p (gimple stmt) if (TREE_CODE (lhs) != SSA_NAME) return false; - if (gimple_assign_rhs_code (stmt) != PLUS_EXPR - && gimple_assign_rhs_code (stmt) != MINUS_EXPR) + code = gimple_assign_rhs_code (stmt); + if (code != PLUS_EXPR + && code != MINUS_EXPR + && code != POINTER_PLUS_EXPR) return false; preinc = gimple_assign_rhs1 (stmt); - if (TREE_CODE (preinc) != SSA_NAME) return false; diff --git gcc-4.6.3.orig/gcc/tree-ssa-forwprop.c gcc-4.6.3/gcc/tree-ssa-forwprop.c index 7e1e7c0..c0f1d8d 100644 --- gcc-4.6.3.orig/gcc/tree-ssa-forwprop.c +++ gcc-4.6.3/gcc/tree-ssa-forwprop.c @@ -1999,10 +1999,12 @@ tree_ssa_forward_propagate_single_use_vars (void) else gsi_next (&gsi); } - else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR - && can_propagate_from (stmt)) + else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) { - if (TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST + tree off = gimple_assign_rhs2 (stmt); + if (TREE_CODE (off) == INTEGER_CST + && can_propagate_from (stmt) + && !simple_iv_increment_p (stmt) /* ??? Better adjust the interface to that function instead of building new trees here. */ && forward_propagate_addr_expr @@ -2014,7 +2016,7 @@ tree_ssa_forward_propagate_single_use_vars (void) rhs, fold_convert (ptr_type_node, - gimple_assign_rhs2 (stmt)))))) + off))))) { release_defs (stmt); todoflags |= TODO_remove_unused_locals; diff --git gcc-4.6.3.orig/libgcc/config.host gcc-4.6.3/libgcc/config.host index 25e949e..8a5af73 100644 --- gcc-4.6.3.orig/libgcc/config.host +++ gcc-4.6.3/libgcc/config.host @@ -223,6 +223,8 @@ avr-*-*) # Make HImode functions for AVR tmake_file=${cpu_type}/t-avr ;; +msp430-*-*) + ;; bfin*-elf*) ;; bfin*-uclinux*)