[ARM] Optimize executable size when using softfloat fmul/dmul
authorThomas Preud'homme <thopre01@gcc.gnu.org>
Wed, 19 Dec 2018 17:34:18 +0000 (17:34 +0000)
committerThomas Preud'homme <thopre01@gcc.gnu.org>
Wed, 19 Dec 2018 17:34:18 +0000 (17:34 +0000)
Softfloat single precision and double precision floating-point
multiplication routines in libgcc share some code with the
floating-point division of their corresponding precision. As the code
is structured now, this leads to *all* division code being pulled in an
executable in softfloat mode even if only multiplication is
performed.

This patch create some new LIB1ASMFUNCS macros to also build files with
just the multiplication and shared code as weak symbols. By putting
these earlier in the static library, they can then be picked up when
only multiplication is used and they are overriden by the global
definition in the existing file containing both multiplication and
division code when division is needed.

The patch also removes changes made to the FUNC_START and ARM_FUNC_START
macros in r218124 since the intent was to put multiplication and
division code into their own section in a later patch to achieve the
same size optimization. That approach relied on specific section layout
to ensure multiplication and division were not too far from the shared
bit of code in order to the branches to be within range. Due to lack of
guarantee regarding section layout, in particular with all the
possibility of linker scripts, this approach was chosen instead. This
patch keeps the two testcases that were posted by Tony Wang on the mailing
list to implement this approach and adds a new one.

2018-12-19  Thomas Preud'homme  <thomas.preudhomme@linaro.org>

    libgcc/
    * /config/arm/lib1funcs.S (FUNC_START): Remove unused sp_section
    parameter and corresponding code.
    (ARM_FUNC_START): Likewise in both definitions.
    Also update footer comment about condition that need to match with
    gcc/config/arm/elf.h to also include libgcc/config/arm/t-arm.
    * config/arm/ieee754-df.S (muldf3): Also build it if L_arm_muldf3 is
    defined.  Weakly define it in this case.
    * config/arm/ieee754-sf.S (mulsf3): Likewise with L_arm_mulsf3.
    * config/arm/t-elf (LIB1ASMFUNCS): Build _arm_muldf3.o and
    _arm_mulsf3.o before muldiv versions if targeting Thumb-1 only. Add
    comment to keep condition in sync with the one in
    libgcc/config/arm/lib1funcs.S and gcc/config/arm/elf.h.

    gcc/
    * config/arm/elf.h: Update comment about condition that need to
    match with libgcc/config/arm/lib1funcs.S to also include
    libgcc/config/arm/t-arm.
    * doc/sourcebuild.texi (output-exists, output-exists-not): Rename
    subsubsection these directives are in to "Check for output files".
    Move scan-symbol to that section and add to it new scan-symbol-not
    directive.

2018-12-19  Tony Wang  <tony.wang@arm.com>
    Thomas Preud'homme  <thomas.preudhomme@linaro.org>

    gcc/testsuite/
    * lib/lto.exp (lto-execute): Define output_file and testname_with_flags
    to same value as execname.
    (scan-symbol): Move and rename to ...
    * lib/gcc-dg.exp (scan-symbol-common): This.  Adapt into a
    helper function returning true or false if a symbol is present.
    (scan-symbol): New procedure.
    (scan-symbol-not): Likewise.
    * gcc.target/arm/size-optimization-ieee-1.c: New testcase.
    * gcc.target/arm/size-optimization-ieee-2.c: Likewise.
    * gcc.target/arm/size-optimization-ieee-3.c: Likewise.

From-SVN: r267282

14 files changed:
gcc/ChangeLog
gcc/config/arm/elf.h
gcc/doc/sourcebuild.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/size-optimization-ieee-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/size-optimization-ieee-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/size-optimization-ieee-3.c [new file with mode: 0644]
gcc/testsuite/lib/gcc-dg.exp
gcc/testsuite/lib/lto.exp
libgcc/ChangeLog
libgcc/config/arm/ieee754-df.S
libgcc/config/arm/ieee754-sf.S
libgcc/config/arm/lib1funcs.S
libgcc/config/arm/t-elf

index 365d5931bcf44d62a32af5b26a1c85b0e3037e1e..53cdc837a5c960e28fbc8e1b5977b00b3ded5c30 100644 (file)
@@ -1,3 +1,13 @@
+2018-12-19  Thomas Preud'homme  <thomas.preudhomme@linaro.org>
+
+       * config/arm/elf.h: Update comment about condition that need to
+       match with libgcc/config/arm/lib1funcs.S to also include
+       libgcc/config/arm/t-arm.
+       * doc/sourcebuild.texi (output-exists, output-exists-not): Rename
+       subsubsection these directives are in to "Check for output files".
+       Move scan-symbol to that section and add to it new scan-symbol-not
+       directive.
+
 2018-12-19  Tom de Vries  <tdevries@suse.de>
 
        * config/nvptx/nvptx.c (PTX_CTA_SIZE): Define.
index ad3651ba84117562d016432badcab51f4b588d9f..1e00e99afc674851fd4ea985d230fecd191d25ad 100644 (file)
 
 /* Horrible hack: We want to prevent some libgcc routines being included
    for some multilibs.  The condition should match the one in
-   libgcc/config/arm/lib1funcs.S.  */
+   libgcc/config/arm/lib1funcs.S and libgcc/config/arm/t-elf.  */
 #if __ARM_ARCH_ISA_ARM || __ARM_ARCH_ISA_THUMB != 1
 #undef L_fixdfsi
 #undef L_fixunsdfsi
index 46ef388e109bea5a8a50349a39c886127ffa9733..29c693b9644afd947d3eeacce84b796062dc2e35 100644 (file)
@@ -2668,7 +2668,7 @@ Passes if @var{regex} does not match demangled text in the dump file with
 suffix @var{suffix}.
 @end table
 
-@subsubsection Verify that an output files exists or not
+@subsubsection Check for output files
 
 @table @code
 @item output-exists [@{ target/xfail @var{selector} @}]
@@ -2676,13 +2676,12 @@ Passes if compiler output file exists.
 
 @item output-exists-not [@{ target/xfail @var{selector} @}]
 Passes if compiler output file does not exist.
-@end table
-
-@subsubsection Check for LTO tests
 
-@table @code
 @item scan-symbol @var{regexp} [@{ target/xfail @var{selector} @}]
 Passes if the pattern is present in the final executable.
+
+@item scan-symbol-not @var{regexp} [@{ target/xfail @var{selector} @}]
+Passes if the pattern is absent from the final executable.
 @end table
 
 @subsubsection Checks for @command{gcov} tests
index d1ebfc7c3469577d51597762c30ab21a97029b5f..e199cd09728340a500eca99c39eff115bf8425c7 100644 (file)
@@ -1,3 +1,17 @@
+2018-12-19  Tony Wang  <tony.wang@arm.com>
+           Thomas Preud'homme  <thomas.preudhomme@linaro.org>
+
+       * lib/lto.exp (lto-execute): Define output_file and testname_with_flags
+       to same value as execname.
+       (scan-symbol): Move and rename to ...
+       * lib/gcc-dg.exp (scan-symbol-common): This.  Adapt into a
+       helper function returning true or false if a symbol is present.
+       (scan-symbol): New procedure.
+       (scan-symbol-not): Likewise.
+       * gcc.target/arm/size-optimization-ieee-1.c: New testcase.
+       * gcc.target/arm/size-optimization-ieee-2.c: Likewise.
+       * gcc.target/arm/size-optimization-ieee-3.c: Likewise.
+
 2018-12-19  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * g++.dg/asm-qual-3.C: New testcase.
diff --git a/gcc/testsuite/gcc.target/arm/size-optimization-ieee-1.c b/gcc/testsuite/gcc.target/arm/size-optimization-ieee-1.c
new file mode 100644 (file)
index 0000000..34090f2
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do link { target arm_soft_ok } } */
+/* { dg-options "-mfloat-abi=soft" } */
+
+int
+foo (void)
+{
+  volatile float a;
+  volatile float b;
+  volatile float c = a * b;
+  return 0;
+}
+
+int
+bar (void)
+{
+  volatile double a;
+  volatile double b;
+  volatile double c = a * b;
+  return 0;
+}
+
+int
+main (void)
+{
+  foo ();
+  bar ();
+  return 0;
+}
+
+/* { dg-final { scan-symbol "__aeabi_fmul" } } */
+/* { dg-final { scan-symbol "__aeabi_dmul" } } */
+/* { dg-final { scan-symbol-not "__aeabi_fdiv" } } */
+/* { dg-final { scan-symbol-not "__aeabi_ddiv" } } */
diff --git a/gcc/testsuite/gcc.target/arm/size-optimization-ieee-2.c b/gcc/testsuite/gcc.target/arm/size-optimization-ieee-2.c
new file mode 100644 (file)
index 0000000..7533789
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do link { target arm_soft_ok } } */
+/* { dg-options "-mfloat-abi=soft" } */
+
+int
+foo (void)
+{
+  volatile float a;
+  volatile float b;
+  volatile float c = a / b;
+  return 0;
+}
+
+int
+bar (void)
+{
+  volatile double a;
+  volatile double b;
+  volatile double c = a / b;
+  return 0;
+}
+
+int
+main (void)
+{
+  foo ();
+  bar ();
+  return 0;
+}
+
+/* { dg-final { scan-symbol "__aeabi_fdiv" } } */
+/* { dg-final { scan-symbol "__aeabi_ddiv" } } */
diff --git a/gcc/testsuite/gcc.target/arm/size-optimization-ieee-3.c b/gcc/testsuite/gcc.target/arm/size-optimization-ieee-3.c
new file mode 100644 (file)
index 0000000..63c92b3
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do link { target arm_soft_ok } } */
+/* { dg-options "-mfloat-abi=soft" } */
+
+int
+foo (void)
+{
+  volatile float a;
+  volatile float b;
+  volatile float c = a * b + a / b;
+  return 0;
+}
+
+int
+bar (void)
+{
+  volatile double a;
+  volatile double b;
+  volatile double c = a * b + a / b;
+  return 0;
+}
+
+int
+main (void)
+{
+  foo ();
+  bar ();
+  return 0;
+}
+
+/* { dg-final { scan-symbol "__aeabi_fmul" } } */
+/* { dg-final { scan-symbol "__aeabi_dmul" } } */
+/* { dg-final { scan-symbol "__aeabi_fdiv" } } */
+/* { dg-final { scan-symbol "__aeabi_ddiv" } } */
index 054d8848abc63193e75534df75097213f9866151..e47f80de3f41147287fd2ba7f6fb574c422f5a22 100644 (file)
@@ -1244,5 +1244,81 @@ proc gdb-exists { args } {
     return 0;
 }
 
+# Helper function for scan-symbol and scan-symbol-not. It scans a symbol in
+# the final executable and return 1 if present, otherwise fail.
+#
+# Argument 0 is the regexp to match.
+# Argument 1 handles expected failures and the like
+proc scan-symbol-common { scan_directive args } {
+    global nm
+    global base_dir
+
+    # Access variable from gcc-dg-test-1 or lto-execute.
+    upvar 3 output_file output_file
+
+    if { [llength $args] >= 2 } {
+       switch [dg-process-target [lindex $args 1]] {
+           "S" { }
+           "N" { return }
+           "F" { setup_xfail "*-*-*" }
+           "P" { }
+       }
+    }
+
+    # Find nm like we find g++ in g++.exp.
+    if ![info exists nm]  {
+       set nm [findfile $base_dir/../../../binutils/nm \
+               $base_dir/../../../binutils/nm \
+               [findfile $base_dir/../../nm $base_dir/../../nm \
+                     [findfile $base_dir/nm $base_dir/nm \
+                      [transform nm]]]]
+       verbose -log "nm is $nm"
+    }
+
+    set output_file "[glob -nocomplain $output_file]"
+    if { $output_file == "" } {
+       fail "$scan_directive $args: output file does not exist"
+       return
+    }
+
+    set fd [open "| $nm $output_file" r]
+    set text [read $fd]
+    close $fd
+
+    if [regexp -- [lindex $args 0] $text] {
+       return 1
+    } else {
+       return 0
+    }
+}
+
+# Utility for scanning a symbol in the final executable, invoked via dg-final.
+# Call pass if pattern is present, otherwise fail.
+#
+# Argument 0 is the regexp to match.
+# Argument 1 handles expected failures and the like
+proc scan-symbol { args } {
+    set testcase [testname-for-summary]
+    if { [scan-symbol-common "scan-symbol" $args]} {
+       pass "$testcase   scan-symbol $args"
+    } else {
+       fail "$testcase   scan-symbol $args"
+    }
+}
+
+# Utility for scanning a symbol in the final executable, invoked via dg-final.
+# Call pass if pattern is absent, otherwise fail.
+#
+# Argument 0 is the regexp to match.
+# Argument 1 handles expected failures and the like
+proc scan-symbol-not { args } {
+    set testcase [testname-for-summary]
+    if { [scan-symbol-common "scan-symbol-not" $args]} {
+       fail "$testcase   scan-symbol-not $args"
+    } else {
+       pass "$testcase   scan-symbol-not $args"
+    }
+}
+
 set additional_prunes ""
 set dg_runtest_extra_prunes ""
index 58a84aa19369a459fd047f2e37a864202d6d87ef..c2c35698827199c71b192faf9f2b427d06b541f0 100644 (file)
@@ -712,6 +712,17 @@ proc lto-execute { src1 sid } {
 
        # There's a unique name for each executable we generate.
        set execname "${execbase}-${count}1.exe"
+
+       # The LTO tests don't use dg-test, so testname_with_flags and
+       # output_file need to be defined explicitly for each file.  scan-symbol
+       # directives rely on both of these to be defined to find the symbol to
+       # scan and for the text to print in the PASS/FAIL since they can also
+       # be called from dg-test.  testname_with_flags is also used via
+       # testname-for-summary when calling into generic function below to
+       # clean temporary files.
+       set output_file $execname
+       set testname_with_flags $execname
+
        incr count
 
        file_on_host delete $execname
@@ -774,11 +785,7 @@ proc lto-execute { src1 sid } {
            }
        }
 
-       # Clean up after -save-temps.  The LTO tests don't use dg-test, so
-       # testname-for-summary needs to be defined explicitly for each
-       # file that needs to be removed.
-       set testname_with_flags $execname
-
+       # Clean up after -save-temps.
        eval "cleanup-saved-temps"
 
        for {set i 0} {$i < $num_srcs} {incr i} {
@@ -801,52 +808,6 @@ proc lto-execute { src1 sid } {
     }
 }
 
-# Utility for scanning a symbol in the final executable, invoked via dg-final.
-# Call pass if pattern is present, otherwise fail.
-#
-# Argument 0 is the regexp to match.
-# Argument 1 handles expected failures and the like
-proc scan-symbol { args } {
-    global nm
-    global base_dir
-    upvar 2 execname execname
-
-    if { [llength $args] >= 2 } {
-       switch [dg-process-target [lindex $args 1]] {
-           "S" { }
-           "N" { return }
-           "F" { setup_xfail "*-*-*" }
-           "P" { }
-       }
-    }
-
-    # Find nm like we find g++ in g++.exp.
-    if ![info exists nm]  {
-       set nm [findfile $base_dir/../../../binutils/nm \
-               $base_dir/../../../binutils/nm \
-               [findfile $base_dir/../../nm $base_dir/../../nm \
-                     [findfile $base_dir/nm $base_dir/nm \
-                      [transform nm]]]]
-       verbose -log "nm is $nm"
-    }
-
-    set output_file "[glob -nocomplain $execname]"
-    if { $output_file == "" } {
-       fail "scan-symbol $args: dump file does not exist"
-       return
-    }
-
-    set fd [open "| $nm $output_file" r]
-    set text [read $fd]
-    close $fd
-
-    if [regexp -- [lindex $args 0] $text] {
-       pass "scan-symbol $args"
-    } else {
-       fail "scan-symbol $args"
-    }
-}
-
 # Call pass if object readelf is ok, otherwise fail.
 # example: /* { dg-final { object-readelf Tag_ABI_enum_size int} } */
 proc object-readelf { args } {
index 2075567766db33f1085e84cb4ecd5bb09ccef433..1879424524d5f1cb8256b82aaf6e7904ffecafac 100644 (file)
@@ -1,3 +1,18 @@
+2018-12-19  Thomas Preud'homme  <thomas.preudhomme@linaro.org>
+
+       * /config/arm/lib1funcs.S (FUNC_START): Remove unused sp_section
+       parameter and corresponding code.
+       (ARM_FUNC_START): Likewise in both definitions.
+       Also update footer comment about condition that need to match with
+       gcc/config/arm/elf.h to also include libgcc/config/arm/t-arm.
+       * config/arm/ieee754-df.S (muldf3): Also build it if L_arm_muldf3 is
+       defined.  Weakly define it in this case.
+       * config/arm/ieee754-sf.S (mulsf3): Likewise with L_arm_mulsf3.
+       * config/arm/t-elf (LIB1ASMFUNCS): Build _arm_muldf3.o and
+       _arm_mulsf3.o before muldiv versions if targeting Thumb-1 only. Add
+       comment to keep condition in sync with the one in
+       libgcc/config/arm/lib1funcs.S and gcc/config/arm/elf.h.
+
 2018-12-18  Wei Xiao  <wei3.xiao@intel.com>
 
        * config/i386/cpuinfo.c (get_intel_cpu): Handle cascadelake.
index 480e33da31fd1b3f093ea66ea7f2dd54a89a5272..1765c5f1f6089a4a8db35ce001dfa481a55616d8 100644 (file)
@@ -617,7 +617,18 @@ ARM_FUNC_ALIAS aeabi_l2d floatdidf
 
 #endif /* L_addsubdf3 */
 
-#ifdef L_arm_muldivdf3
+#if defined(L_arm_muldf3) || defined(L_arm_muldivdf3)
+
+@ Define multiplication as weak in _arm_muldf3.o so that it can be overriden
+@ by the global definition in _arm_muldivdf3.o.  This allows a program only
+@ using multiplication to take the weak definition which does not contain the
+@ division code. Programs using only division or both division and
+@ multiplication will pull _arm_muldivdf3.o from which both the multiplication
+@ and division are taken thanks to the override.
+#ifdef L_arm_muldf3
+WEAK muldf3
+WEAK aeabi_dmul
+#endif
 
 ARM_FUNC_START muldf3
 ARM_FUNC_ALIAS aeabi_dmul muldf3
@@ -870,6 +881,8 @@ LSYM(Lml_n):
        FUNC_END aeabi_dmul
        FUNC_END muldf3
 
+#ifdef L_arm_muldivdf3
+
 ARM_FUNC_START divdf3
 ARM_FUNC_ALIAS aeabi_ddiv divdf3
        CFI_START_FUNCTION
@@ -1067,6 +1080,7 @@ LSYM(Ldv_s):
        FUNC_END divdf3
 
 #endif /* L_muldivdf3 */
+#endif /* L_arm_muldf3 || L_arm_muldivdf3 */
 
 #ifdef L_arm_cmpdf2
 
index 28e0d7932810f299748739109885de3d99d9a6c8..0b4d1ab377d683be37becd9fa322be87d0259860 100644 (file)
@@ -428,7 +428,18 @@ ARM_FUNC_ALIAS aeabi_l2f floatdisf
 
 #endif /* L_addsubsf3 */
 
-#ifdef L_arm_muldivsf3
+#if defined(L_arm_mulsf3) || defined(L_arm_muldivsf3)
+
+@ Define multiplication as weak in _arm_mulsf3.o so that it can be overriden
+@ by the global definition in _arm_muldivsf3.o.  This allows a program only
+@ using multiplication to take the weak definition which does not contain the
+@ division code. Programs using only division or both division and
+@ multiplication will pull _arm_muldivsf3.o from which both the multiplication
+@ and division are taken thanks to the override.
+#ifdef L_arm_mulsf3
+WEAK mulsf3
+WEAK aeabi_fmul
+#endif
 
 ARM_FUNC_START mulsf3
 ARM_FUNC_ALIAS aeabi_fmul mulsf3
@@ -613,6 +624,8 @@ LSYM(Lml_n):
        FUNC_END aeabi_fmul
        FUNC_END mulsf3
 
+#ifdef L_arm_muldivsf3
+
 ARM_FUNC_START divsf3
 ARM_FUNC_ALIAS aeabi_fdiv divsf3
        CFI_START_FUNCTION
@@ -756,6 +769,7 @@ LSYM(Ldv_s):
        FUNC_END divsf3
 
 #endif /* L_muldivsf3 */
+#endif /* L_arm_mulsf3 || L_arm_muldivsf3 */
 
 #ifdef L_arm_cmpsf2
 
index ff06d504a4c940e1fe04cb9b17d5eece131ccc16..193fb251fdb23271107f4b03b1fb1826f6116ad4 100644 (file)
@@ -359,12 +359,8 @@ SYM (\name):
 #define THUMB_SYNTAX
 #endif
 
-.macro FUNC_START name sp_section=
-  .ifc \sp_section, function_section
-       .section        .text.__\name,"ax",%progbits
-  .else
+.macro FUNC_START name
        .text
-  .endif
        .globl SYM (__\name)
        TYPE (__\name)
        .align 0
@@ -390,8 +386,8 @@ SYM (\name):
 #if defined(__thumb2__)
 
 /* For Thumb-2 we build everything in thumb mode.  */
-.macro ARM_FUNC_START name sp_section=
-       FUNC_START \name \sp_section
+.macro ARM_FUNC_START name
+       FUNC_START \name
        .syntax unified
 .endm
 #define EQUIV .thumb_set
@@ -422,12 +418,8 @@ _L__\name:
 #ifdef NOT_ISA_TARGET_32BIT
 #define EQUIV .thumb_set
 #else
-.macro ARM_FUNC_START name sp_section=
-  .ifc \sp_section, function_section
-       .section        .text.__\name,"ax",%progbits
-  .else
+.macro ARM_FUNC_START name
        .text
-  .endif
        .globl SYM (__\name)
        TYPE (__\name)
        .align 0
@@ -2169,7 +2161,8 @@ LSYM(Lchange_\register):
 .endm
 
 #ifndef __symbian__
-/* The condition here must match the one in gcc/config/arm/elf.h.  */
+/* The condition here must match the one in gcc/config/arm/elf.h and
+   libgcc/config/arm/t-elf.  */
 #ifndef NOT_ISA_TARGET_32BIT
 #include "ieee754-df.S"
 #include "ieee754-sf.S"
index 9e7a3170f177865645b2fa291d08390f123a3518..9da6cd370546bcc88d9071e61a468437e58dc4a6 100644 (file)
@@ -1,3 +1,19 @@
+ifeq (,$(findstring __symbian__,$(shell $(gcc_compile_bare) -dM -E - </dev/null)))
+
+ARM_ISA:=$(findstring __ARM_ARCH_ISA_ARM,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
+THUMB1_ISA:=$(findstring __ARM_ARCH_ISA_THUMB 1,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
+
+# The condition here must match the one in gcc/config/arm/elf.h and
+# libgcc/config/arm/lib1funcs.S.  _arm_muldf3 and _arm_mulsf3 must be included
+# first so that the weak multiplication symbols in the corresponding files are
+# chosen over the global symbols that _arm_muldivdf3 and _arm_muldivsf3
+# inclusion create when only multiplication is used, thus avoiding pulling in
+# useless division code.
+ifneq (__ARM_ARCH_ISA_THUMB 1,$(ARM_ISA)$(THUMB1_ISA))
+LIB1ASMFUNCS += _arm_muldf3 _arm_mulsf3
+endif
+endif # !__symbian__
+
 # For most CPUs we have an assembly soft-float implementations.
 # However this is not true for ARMv6M.  Here we want to use the soft-fp C
 # implementation.  The soft-fp code is only build for ARMv6M.  This pulls