(Updated) Work around bug in gcc 2.95.2 on hppa targets
Paul Green [Mon, 22 Apr 2002 20:35:00 +0000 (16:35 -0400)]
Message-Id: <200204230034.UAA01134@mailhub2.stratus.com>

p4raw-id: //depot/perl@16092

MANIFEST
hints/README.hints
hints/t001.c [new file with mode: 0644]
hints/vos.sh

index f0fa2d6..218a4b8 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -794,6 +794,7 @@ hints/sunos_4_1.sh          Hints for named architecture
 hints/super-ux.sh              Hints for named architecture
 hints/svr4.sh                  Hints for named architecture
 hints/svr5.sh                  Hints for named architecture
+hints/t001.c                   Test case for gcc bug
 hints/ti1500.sh                        Hints for named architecture
 hints/titanos.sh               Hints for named architecture
 hints/ultrix_4.sh              Hints for named architecture
index 0666771..1d0f35c 100644 (file)
@@ -103,6 +103,70 @@ In general, try to avoid hard-wiring something that Configure will
 figure out anyway.  Also try to allow for Configure command-line
 overrides.
 
+=head1 Working around compiler bugs
+
+Occasionally, the root cause of a bug in perl turns out to be due to a bug
+in the compiler.  Often, changing the compilation options (particularly the
+optimization level) can work around the bug.  However, if you try to do
+this on the command line, you will be changing the compilation options for
+every component of perl, which can really hurt perl's performance.
+Instead, consider placing a test case into the hints directory to detect
+whether the compiler bug is present, and add logic to the hints file to
+take a specific and appropriate action
+
+=head2 Test-case conventions
+
+Test cases should be named "tNNN.c", where NNN is the next unused sequence
+number.  The test case must be executable and should display a message
+containing the word "fails" when the compiler bug is present.  It should
+display the word "works" with the compiler bug is not present.  The test
+cases should be liberally commented and may be used by any hints file that
+needs them.  See the first hints file (t001.c) for an example.
+
+=head2 Hint file processing
+
+The hint file must define a call-back unit (see below) that will compile,
+link, and run the test case, and then check for the presence of the string
+"fails" in the output.  If it finds this string, it sets a special variable
+to specify the compilation option(s) for the specific perl source file that
+is affected by the bug.
+
+The special variable is named "XXX_cflags" where "XXX" is the name of
+the source file (without the ".c" suffix).  The value of this variable
+is the string "optimize=YYY", where "YYY" is the compilation option
+necessary to work around the bug.  The default value of this variable
+is "-O" (letter O), which specifies that the C compiler should compile
+the source program at the default optimization level.  If you can
+avoid the compiler bug by disabling optimization, just reset the
+"optimize" variable to the null string.  Sometimes a bug is present at
+a higher optimization level (say, O3) and not present at a lower
+optimization level (say, O1).  In this case, you should specify the
+highest optimization level at which the bug is not present, so that
+you will retain as many of the benefits of code optimization as
+possible.
+
+For example, if the pp_pack.c source file must be compiled at
+optimization level 0 to work around a problem on a particular
+platform, one of the statements
+
+       pp_pack_cflags="optimize=-O0"   or
+       pp_pack_cflags="optimize="
+
+will do the trick, since level 0 is equivalent to no optimization.
+(In case your printer or display device does not distinguish the
+letter O from the digit 0, that is the letter O followed by the digit
+0).  You can specify any compiler option or set of options here, not
+just optimizer options.  These options are appended to the list of all
+other compiler options, so you should be able to override almost any
+compiler option prepared by Configure.  (Obviously this depends on how
+the compiler treats conflicting options, but most seem to go with the
+last value specified on the command line).
+
+You should also allow for the XXX_cflags variable to be overridden on the
+command line.
+
+See the vos.sh hints file for an extended example of these techniques.
+
 =head1 Hint file tricks
 
 =head2 Printing critical messages
@@ -209,16 +273,10 @@ aix 4.1.1.
 
 =over 4
 
-=item Warning
-
-All of the following is experimental and subject to change.  But it
-probably won't change much. :-)
-
 =item Compiler-related flags
 
 The settings of some things, such as optimization flags, may depend on
-the particular compiler used.  For example, for ISC we have the
-following:
+the particular compiler used.  For example, consider the following:
 
     case "$cc" in
     *gcc*)  ccflags="$ccflags -posix"
@@ -256,4 +314,5 @@ say things like "sh Configure -Dcc=gcc -Dusethreads" on the command line.
 
 Have the appropriate amount of fun :-)
 
-    Andy Dougherty             doughera@lafayette.edu
+    Andy Dougherty             doughera@lafayette.edu (author)
+    Paul Green                 paul.green@stratus.com (compiler bugs)
diff --git a/hints/t001.c b/hints/t001.c
new file mode 100644 (file)
index 0000000..51fdefd
--- /dev/null
@@ -0,0 +1,90 @@
+/* Beginning of modification history */
+/* Written 02-04-10 by Paul Green (Paul.Green@stratus.com) */
+/* End of modification history */
+
+/* This test case is extracted from Perl version 5.7.3.  It is
+   in the Perl_unpack_str function of the pp_pack.c source file.
+
+   GCC 2.95.2 improperly assumes that it can compensate for an
+   extra fsub by performing a fadd.  This would work in
+   fixed-point arithmetic, but does not work in floating-point
+   arithmetic.
+
+   This problem has been seen on HP-UX and on Stratus VOS, both
+   of which have an HP PA-RISC target (hppa1.1).  The Stratus
+   bug number is gnu_g++-220.  */
+
+/* #define _POSIX_C_SOURCE 199506L -- added by Configure */
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+void test(double *result)
+{
+       float   afloat;
+       double  adouble;
+       int             checksum = 0;
+       unsigned        cuv = 0;
+       double  cdouble = 0.0;
+       const int       bits_in_uv = 8 * sizeof(cuv);
+
+       checksum = 53;
+       cdouble = -1.0;
+
+       if (checksum) {
+               if (checksum > bits_in_uv) {
+                       double trouble;
+
+                       adouble = (double) (1 << (checksum & 15));
+
+                       while (checksum >= 16) {
+                               checksum -= 16;
+                               adouble *= 65536.0;
+                       }
+
+                       /* At -O1, GCC 2.95.2 compiles the following loop
+                          into:
+
+                          L$0014
+                               fcmp,dbl,>= %fr4,%fr0
+                               ftest
+                               b L$0014
+                               fadd,dbl %fr4,%fr12,%fr4
+                               fsub,dbl %fr4,%fr12,%fr4
+
+                               This code depends on the floading-add and
+                               floating-subtract retaining all of the
+                               precision present in the operands.  There is
+                               no such guarantee when using floating-point,
+                               as this test case demonstrates.
+
+                               The code is okay at -O0.  */
+
+                       while (cdouble < 0.0)
+                               cdouble += adouble;
+
+                       cdouble = modf (cdouble / adouble, &trouble) * adouble;
+               }
+       }
+
+       *result = cdouble;
+}
+
+int main (int argc, char ** argv)
+{
+double value;
+
+       test (&value);
+
+       if (argc == 2 && !strcmp(argv[1],"-v"))
+               printf ("value = %.18e\n", value);
+
+       if (value != 9.007199254740991e+15) {
+               printf ("t001 fails!\n");
+               return -1;
+       }
+       else {
+               printf ("t001 works.\n");
+               return 0;
+       }
+}
index 06dc555..9860a6f 100644 (file)
@@ -90,3 +90,53 @@ hostcat="cat /system/stcp/hosts"
 
 # VOS does not have socketpair() but we supply one in vos.c
 d_sockpair="define"
+
+# Once we have the compiler flags defined, Configure will
+# execute the following call-back script. See hints/README.hints
+# for details.
+cat > UU/cc.cbu <<'EOCBU'
+# This script UU/cc.cbu will get 'called-back' by Configure after it
+# has prompted the user for the C compiler to use.
+
+# Compile and run the a test case to see if bug gnu_g++-220 is
+# present. If so, lower the optimization level when compiling
+# pp_pack.c.  This works around a bug in unpack.
+
+echo " "
+echo "Testing whether bug gnu_g++-220 is fixed in your compiler..."
+
+# Try compiling the test case.
+if $cc -o t001 -O $ccflags $ldflags ../hints/t001.c; then
+       gccbug=`$run ./t001`
+       case "$gccbug" in
+       *fails*)        gccversion=`$cc --version`
+                       cat >&4 <<EOF
+This C compiler ($gccversion) is known to have optimizer
+problems when compiling pp_pack.c.  The Stratus bug number
+for this problem is gnu_g++-220.
+
+Disabling optimization for pp_pack.c.
+EOF
+                       case "$pp_pack_cflags" in
+                       '')     pp_pack_cflags='optimize='
+                               echo "pp_pack_cflags='optimize=\"\"'" >> config.sh ;;
+                       *)  echo "You specified pp_pack_cflags yourself, so we'll go with your value." >&4 ;;
+                       esac
+               ;;
+       *)      echo "Your compiler is ok." >&4
+               ;;
+       esac
+else
+       echo " "
+       echo "*** WHOA THERE!!! ***" >&4
+       echo "    Your C compiler \"$cc\" doesn't seem to be working!" >&4
+       case "$knowitall" in
+       '')
+               echo "    You'd better start hunting for one and let me know about it." >&4
+               exit 1
+               ;;
+       esac
+fi
+
+$rm -f t001$_o t001$_exe t001.kp
+EOCBU