aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>2015-12-04 17:24:30 +0000
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>2015-12-04 17:24:30 +0000
commit7ed86ba5787700903cbae053e141edb5c724cfe1 (patch)
tree567b5a149156fde352ef52d1373ff08ead34394d /libgcc
parentf133c660af37b660aeabb09539b4e6a169eef8fc (diff)
gcc * config.gcc (extra_gcc_objs): Define for MSP430.
* common/config/msp430/msp430-common.c (msp430_handle_option): Pass both -mmcu and -mcpu on to the back end if they are both defined. * config/msp430/msp430.c (hwmult_name): New function. (msp430_option_override): If an unrecognised MCU name is detected only warn if the user has not provided suitable -mhwmult and -mcpu options. Use msp430_warn_mcu to control warning messages. Generate warnings about conflicts between -mmcu and -mcpu and -mhwmult options. If neither -mcpu nor -mmcu have been specified but -mhwmult= f5series has the select the 430X isa. (msp430_no_hwmult): If -mmcu has not been specified and msp430_hwmult_type is AUTO then return true. * config/msp430/msp430.h (EXTRA_SPEC_FUNCTIONS): Define. (LIB_SPEC): Add hardware multiply library selection. * config/msp430/t-msp430: Delete hardware multiply multilibs. Add rule to build driver-msp430.o * config/msp430/driver-msp430.c: New file. * config/msp430/msp430.opt (warn-mcu): New option. * doc/invoke.texi: Update description of -mhwmult=auto. Document -mwarn-mcu option. tests * gcc.target/msp430/msp_abi_div_funcs.c: New test. * gcc.target/msp430/mul_main.h: New test support file. * gcc.target/msp430/mul_none.c: New test. * gcc.target/msp430/mul_16bit.c: New test. * gcc.target/msp430/mul_32bit.c: New test. * gcc.target/msp430/mul_f5.c: New test. libgcc * config/msp430/mpy.c (__mulhi3): Use a faster algorithm. Allow for the second argument being negative. * config.host (extra_parts): Define for MSP430. Create separate libraries for each of the hardware multiply formats. * config/msp430/lib2hw_mul.S: Build only the multiply routines that are needed. * config/msp430/lib2mul.c: Likewise. * config/msp430/t-msp430 (LIB2ADD): Remove lib2hw_mul.S. Add rules to build hardware multiply libraries. * config/msp430/lib2divSI.c: (__mspabi_divlu): Alias for __mspabi_divul function. (__mspabi_divllu): New stub function. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@231286 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgcc')
-rw-r--r--libgcc/ChangeLog15
-rw-r--r--libgcc/config.host1
-rw-r--r--libgcc/config/msp430/lib2divSI.c29
-rw-r--r--libgcc/config/msp430/lib2hw_mul.S215
-rw-r--r--libgcc/config/msp430/lib2mul.c37
-rw-r--r--libgcc/config/msp430/mpy.c21
-rw-r--r--libgcc/config/msp430/t-msp43028
7 files changed, 293 insertions, 53 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 8143db2222e..003971b0cdc 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,18 @@
+2015-12-04 Nick Clifton <nickc@redhat.com>
+
+ * config/msp430/mpy.c (__mulhi3): Use a faster algorithm.
+ Allow for the second argument being negative.
+ * config.host (extra_parts): Define for MSP430. Create separate
+ libraries for each of the hardware multiply formats.
+ * config/msp430/lib2hw_mul.S: Build only the multiply routines
+ that are needed.
+ * config/msp430/lib2mul.c: Likewise.
+ * config/msp430/t-msp430 (LIB2ADD): Remove lib2hw_mul.S.
+ Add rules to build hardware multiply libraries.
+ * config/msp430/lib2divSI.c: (__mspabi_divlu): Alias for
+ __mspabi_divul function.
+ (__mspabi_divllu): New stub function.
+
2015-12-01 John David Anglin <danglin@gcc.gnu.org>
* config/pa/fptr.c (__canonicalize_funcptr_for_compare): Initialize
diff --git a/libgcc/config.host b/libgcc/config.host
index 9a58beb7847..b16f52a54cc 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -942,6 +942,7 @@ moxie-*-rtems*)
;;
msp430*-*-elf)
tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430"
+ extra_parts="$extra_parts libmul_none.a libmul_16.a libmul_32.a libmul_f5.a"
;;
nds32*-elf*)
# Basic makefile fragment and extra_parts for crt stuff.
diff --git a/libgcc/config/msp430/lib2divSI.c b/libgcc/config/msp430/lib2divSI.c
index cc45c4c87ea..fa6ac4552e6 100644
--- a/libgcc/config/msp430/lib2divSI.c
+++ b/libgcc/config/msp430/lib2divSI.c
@@ -40,3 +40,32 @@ typedef int word_type __attribute__ ((mode (__word__)));
#define NAME_MODE si
#include "msp430-divmod.h"
+
+/* ---------------------------------------------------------------------*/
+
+/* There is a typo in the MSP430 ABI document. It calls the unsigned
+ long integer division function __mspabi_divlu when it should be
+ __mspabi_divul. Likewise the unsigned long long integer division
+ function is called __mspabi_divllu when it should be __mspabi_divull.
+
+ Earlier versions of this toolchain used generate the ABI compliant
+ names, so in order to support object files built with those tools
+ we provide stub functions that call the correct routines. */
+
+asm (".global __mspabi_divlu\n\
+ .set __mspabi_divlu, __mspabi_divul");
+
+/* We cannot use the same trick for __mspabi_divllu as that is defined
+ in a different file. Instead we create a stub here. The cost of
+ executing the branch instruction will be trivial compared to the
+ cost of executing a long long division. */
+
+#ifdef __MSP430X_LARGE__
+asm (".global __mspabi_divllu\n\
+ __mspabi_divllu:\n\
+ BRA #__mspabi_divull");
+#else
+asm (".global __mspabi_divllu\n\
+ __mspabi_divllu:\n\
+ BR #__mspabi_divull");
+#endif
diff --git a/libgcc/config/msp430/lib2hw_mul.S b/libgcc/config/msp430/lib2hw_mul.S
index b686d8ec26b..908451d89f2 100644
--- a/libgcc/config/msp430/lib2hw_mul.S
+++ b/libgcc/config/msp430/lib2hw_mul.S
@@ -20,17 +20,42 @@
; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
; <http://www.gnu.org/licenses/>.
-.macro start_func name
- .pushsection .text.\name,"ax",@progbits
+ ;; Macro to start a multiply function. Each function has three
+ ;; names, and hence three entry points - although they all go
+ ;; through the same code. The first name is the version generated
+ ;; by GCC. The second is the MSP430 EABI mandated name for the
+ ;; *software* version of the function. The third is the EABI
+ ;; mandated name for the *hardware* version of the function.
+ ;;
+ ;; Since we are using the hardware and software names to point
+ ;; to the same code this effectively means that we are mapping
+ ;; the software function onto the hardware function. Thus if
+ ;; the library containing this code is linked into an application
+ ;; (before the libgcc.a library) *all* multiply functions will
+ ;; be mapped onto the hardware versions.
+ ;;
+ ;; We construct each function in its own section so that linker
+ ;; garbage collection can be used to delete any unused functions
+ ;; from this file.
+.macro start_func gcc_name eabi_soft_name eabi_hard_name
+ .pushsection .text.\gcc_name,"ax",@progbits
.p2align 1
- .global \name
- .type \name , @function
-\name:
+ .global \eabi_hard_name
+ .type \eabi_hard_name , @function
+\eabi_hard_name:
+ .global \eabi_soft_name
+ .type \eabi_soft_name , @function
+\eabi_soft_name:
+ .global \gcc_name
+ .type \gcc_name , @function
+\gcc_name:
PUSH.W sr ; Save current interrupt state
DINT ; Disable interrupts
NOP ; Account for latency
.endm
+
+ ;; End a function started with the start_func macro.
.macro end_func name
#ifdef __MSP430X_LARGE__
POP.W sr
@@ -42,6 +67,29 @@
.popsection
.endm
+
+ ;; Like the start_func macro except that it is used to
+ ;; create a false entry point that just jumps to the
+ ;; software function (implemented elsewhere).
+.macro fake_func gcc_name eabi_soft_name eabi_hard_name
+ .pushsection .text.\gcc_name,"ax",@progbits
+ .p2align 1
+ .global \eabi_hard_name
+ .type \eabi_hard_name , @function
+\eabi_hard_name:
+ .global \gcc_name
+ .type \gcc_name , @function
+\gcc_name:
+#ifdef __MSP430X_LARGE__
+ BRA \eabi_soft_name
+#else
+ BR \eabi_soft_name
+#endif
+ .size \gcc_name , . - \gcc_name
+ .popsection
+.endm
+
+
.macro mult16 OP1, OP2, RESULT
;* * 16-bit hardware multiply: int16 = int16 * int16
;*
@@ -160,7 +208,66 @@
.endm
-;; First generation MSP430 hardware multiplies ....
+;; EABI mandated names:
+;;
+;; int16 __mspabi_mpyi (int16 x, int16 y)
+;; Multiply int by int.
+;; int16 __mspabi_mpyi_hw (int16 x, int16 y)
+;; Multiply int by int. Uses hardware MPY16 or MPY32.
+;; int16 __mspabi_mpyi_f5hw (int16 x, int16 y)
+;; Multiply int by int. Uses hardware MPY32 (F5xx devices and up).
+;;
+;; int32 __mspabi_mpyl (int32 x, int32 y);
+;; Multiply long by long.
+;; int32 __mspabi_mpyl_hw (int32 x, int32 y)
+;; Multiply long by long. Uses hardware MPY16.
+;; int32 __mspabi_mpyl_hw32 (int32 x, int32 y)
+;; Multiply long by long. Uses hardware MPY32 (F4xx devices).
+;; int32 __mspabi_mpyl_f5hw (int32 x, int32 y)
+;; Multiply long by long. Uses hardware MPY32 (F5xx devices and up).
+;;
+;; int64 __mspabi_mpyll (int64 x, int64 y)
+;; Multiply long long by long long.
+;; int64 __mspabi_mpyll_hw (int64 x, int64 y)
+;; Multiply long long by long long. Uses hardware MPY16.
+;; int64 __mspabi_mpyll_hw32 (int64 x, int64 y)
+;; Multiply long long by long long. Uses hardware MPY32 (F4xx devices).
+;; int64 __mspabi_mpyll_f5hw (int64 x, int64 y)
+;; Multiply long long by long long. Uses hardware MPY32 (F5xx devices and up).
+;;
+;; int32 __mspabi_mpysl (int16 x, int16 y)
+;; Multiply int by int; result is long.
+;; int32 __mspabi_mpysl_hw(int16 x, int16 y)
+;; Multiply int by int; result is long. Uses hardware MPY16 or MPY32
+;; int32 __mspabi_mpysl_f5hw(int16 x, int16 y)
+;; Multiply int by int; result is long. Uses hardware MPY32 (F5xx devices and up).
+;;
+;; int64 __mspabi_mpysll(int32 x, int32 y)
+;; Multiply long by long; result is long long.
+;; int64 __mspabi_mpysll_hw(int32 x, int32 y)
+;; Multiply long by long; result is long long. Uses hardware MPY16.
+;; int64 __mspabi_mpysll_hw32(int32 x, int32 y)
+;; Multiply long by long; result is long long. Uses hardware MPY32 (F4xx devices).
+;; int64 __mspabi_mpysll_f5hw(int32 x, int32 y)
+;; Multiply long by long; result is long long. Uses hardware MPY32 (F5xx devices and up).
+;;
+;; uint32 __mspabi_mpyul(uint16 x, uint16 y)
+;; Multiply unsigned int by unsigned int; result is unsigned long.
+;; uint32 __mspabi_mpyul_hw(uint16 x, uint16 y)
+;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY16 or MPY32
+;; uint32 __mspabi_mpyul_f5hw(uint16 x, uint16 y)
+;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY32 (F5xx devices and up).
+;;
+;; uint64 __mspabi_mpyull(uint32 x, uint32 y)
+;; Multiply unsigned long by unsigned long; result is unsigned long long.
+;; uint64 __mspabi_mpyull_hw(uint32 x, uint32 y)
+;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY16
+;; uint64 __mspabi_mpyull_hw32(uint32 x, uint32 y)
+;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F4xx devices).
+;; uint64 _ _mspabi_mpyull_f5hw(uint32 x, uint32 y)
+;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F5xx devices and up)
+
+
.set MPY_OP1, 0x0130
.set MPY_OP1_S, 0x0132
@@ -169,58 +276,94 @@
.set MAC_OP2, 0x0138
.set RESULT_LO, 0x013A
.set RESULT_HI, 0x013C
-
- start_func __mulhi2
+
+#if defined MUL_16
+;; First generation MSP430 hardware multiplies ...
+
+ start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
mult16 MPY_OP1, MPY_OP2, RESULT_LO
- end_func __mulhi2
+ end_func __mulhi2
- start_func __mulsihi2
+ start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw
mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI
- end_func __mulsihi2
+ end_func __mulsihi2
- start_func __umulsihi2
+ start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw
mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI
- end_func __umulsihi2
+ end_func __umulsihi2
- start_func __mulsi2
+ start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw
mult32 MPY_OP1, MPY_OP2, MAC_OP1, MAC_OP2, RESULT_LO, RESULT_HI
- end_func __mulsi2
+ end_func __mulsi2
- start_func __mulsi2_hw32
+ ;; FIXME: We do not have hardware implementations of these
+ ;; routines, so just jump to the software versions instead.
+ fake_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw
+ fake_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw
+ fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw
+
+#elif defined MUL_32
+;; Second generation MSP430 hardware multiplies ...
+
+ start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
+ mult16 MPY_OP1, MPY_OP2, RESULT_LO
+ end_func __mulhi2
+
+ start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw
+ mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI
+ end_func __mulsihi2
+
+ start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw
+ mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI
+ end_func __umulsihi2
+
+ start_func __mulsi2_hw32 __mspabi_mpyl __mspabi_mpyl_hw32
mult32_hw 0x0140, 0x0142, 0x0150, 0x0152, 0x0154, 0x0156
- end_func __mulsi2_hw32
+ end_func __mulsi2_hw32
- start_func __muldisi2_hw32
+ start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw32
mult3264_hw 0x0144, 0x146, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A
- end_func __muldisi2_hw32
+ end_func __muldisi2
- start_func __umuldisi2_hw32
+ start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw32
mult3264_hw 0x0140, 0x142, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A
- end_func __umuldisi2_hw32
-
-/* The F5xxx series of MCUs support the same 16-bit hardware
- multiply, but it is accessed from different memory registers. */
+ end_func __umuldisi2
+
+ ;; FIXME: Add a hardware version of this function.
+ fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw32
- start_func __mulhi2_f5
+#elif defined MUL_F5
+/* The F5xxx series of MCUs support the same 16-bit and 32-bit multiply
+ as the second generation hardware, but they are accessed from different
+ memory registers. */
+
+ start_func __mulhi2_f5 __mspabi_mpyi __mspabi_mpyi_f5hw
mult16 0x04C0, 0x04C8, 0x04CA
- end_func __mulhi2_f5
+ end_func __mulhi2_f5
- start_func __mulsihi2_f5
+ start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_f5hw
mult1632 0x04C2, 0x04C8, 0x04CA, 0x04CC
- end_func __mulsihi2_f5
+ end_func __mulsihi2
- start_func __umulsihi2_f5
+ start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_f5hw
mult1632 0x04C0, 0x04C8, 0x04CA, 0x04CC
- end_func __umulsihi2_f5
+ end_func __umulsihi2
- start_func __mulsi2_f5
+ start_func __mulsi2_f5 __mspabi_mpyl __mspabi_mpyl_f5hw
mult32_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6
- end_func __mulsi2_f5
+ end_func __mulsi2_f5
- start_func __muldisi2_f5
+ start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_f5hw
mult3264_hw 0x04D4, 0x04D6, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA
- end_func __muldisi2_f5
+ end_func __muldisi2
- start_func __umuldisi2_f5
+ start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_f5hw
mult3264_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA
- end_func __umuldisi2_f5
+ end_func __umuldisi2
+
+ ;; FIXME: Add a hardware version of this function.
+ fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_f5hw
+
+#else
+#error MUL type not defined
+#endif
diff --git a/libgcc/config/msp430/lib2mul.c b/libgcc/config/msp430/lib2mul.c
index ecd3b854e6e..3aa0f924fa6 100644
--- a/libgcc/config/msp430/lib2mul.c
+++ b/libgcc/config/msp430/lib2mul.c
@@ -30,29 +30,44 @@ typedef unsigned int uint08_type __attribute__ ((mode (QI)));
#define C3B(a,b,c) a##b##c
#define C3(a,b,c) C3B(a,b,c)
+#if defined MUL_NONE
-#define UINT_TYPE uint16_type
-#define BITS_MINUS_1 15
-#define NAME_MODE hi
-
-#include "msp430-mul.h"
+/* The software multiply library needs __mspabi_mpyll. */
#undef UINT_TYPE
#undef BITS_MINUS_1
#undef NAME_MODE
-#define UINT_TYPE uint08_type
-#define BITS_MINUS_1 7
-#define NAME_MODE qi
+#define UINT_TYPE uint32_type
+#define BITS_MINUS_1 31
+#define NAME_MODE si
#include "msp430-mul.h"
+#elif defined MUL_16
+
+signed long long
+__mspabi_mpysll (signed long a, signed long b)
+{
+ return (signed long long) a * (signed long long) b;
+}
+
+unsigned long long
+__mspabi_mpyull (unsigned long a, unsigned long b)
+{
+ return (unsigned long long) a * (unsigned long long) b;
+}
+
+#else
+
#undef UINT_TYPE
#undef BITS_MINUS_1
#undef NAME_MODE
-#define UINT_TYPE uint32_type
-#define BITS_MINUS_1 31
-#define NAME_MODE si
+#define UINT_TYPE uint08_type
+#define BITS_MINUS_1 7
+#define NAME_MODE qi
#include "msp430-mul.h"
+
+#endif /* MUL_NONE */
diff --git a/libgcc/config/msp430/mpy.c b/libgcc/config/msp430/mpy.c
index 57cffd0ba2a..3842d86fc35 100644
--- a/libgcc/config/msp430/mpy.c
+++ b/libgcc/config/msp430/mpy.c
@@ -4,12 +4,23 @@ extern int __mulhi3 (int, int);
int
__mulhi3 (int x, int y)
{
- volatile int rv = 0;
+ char bit;
+ int neg = 0;
+ int rv = 0;
- while (y > 0)
+ if (y < 0)
{
- rv += x;
- y --;
+ y = - y;
+ neg = 1;
}
- return rv;
+
+ for (bit = 0; y && bit < sizeof (y) * 8; bit ++)
+ {
+ if (y & 1)
+ rv += x;
+ x <<= 1;
+ y >>= 1;
+ }
+
+ return neg ? - rv : rv;
}
diff --git a/libgcc/config/msp430/t-msp430 b/libgcc/config/msp430/t-msp430
index 5c0cccd5b3e..3ac99558382 100644
--- a/libgcc/config/msp430/t-msp430
+++ b/libgcc/config/msp430/t-msp430
@@ -35,7 +35,6 @@ LIB2ADD = \
$(srcdir)/config/msp430/srai.S \
$(srcdir)/config/msp430/srli.S \
$(srcdir)/config/msp430/cmpsi2.S \
- $(srcdir)/config/msp430/lib2hw_mul.S \
$(srcdir)/config/msp430/floatunhisf.c \
$(srcdir)/config/msp430/floatunhidf.c \
$(srcdir)/config/msp430/floathidf.c \
@@ -44,6 +43,33 @@ LIB2ADD = \
HOST_LIBGCC2_CFLAGS += -Os -ffunction-sections -fdata-sections -mhwmult=none
+lib2_mul_none.o: $(srcdir)/config/msp430/lib2mul.c
+ $(gcc_compile) $^ -c -DMUL_NONE
+
+lib2_mul_16bit.o: $(srcdir)/config/msp430/lib2mul.c
+ $(gcc_compile) $^ -c -DMUL_16
+
+lib2hw_mul_16.o: $(srcdir)/config/msp430/lib2hw_mul.S
+ $(gcc_compile) $^ -c -DMUL_16
+
+lib2hw_mul_32.o: $(srcdir)/config/msp430/lib2hw_mul.S
+ $(gcc_compile) $^ -c -DMUL_32
+
+lib2hw_mul_f5.o: $(srcdir)/config/msp430/lib2hw_mul.S
+ $(gcc_compile) $^ -c -DMUL_F5
+
+libmul_none.a: lib2_mul_none.o
+ $(AR_CREATE_FOR_TARGET) $@ $^
+
+libmul_16.a: lib2hw_mul_16.o lib2_mul_16bit.o
+ $(AR_CREATE_FOR_TARGET) $@ $^
+
+libmul_32.a: lib2hw_mul_32.o
+ $(AR_CREATE_FOR_TARGET) $@ $^
+
+libmul_f5.a: lib2hw_mul_f5.o
+ $(AR_CREATE_FOR_TARGET) $@ $^
+
# Local Variables:
# mode: Makefile
# End: