From: partain Date: Thu, 27 Jun 1996 16:00:09 +0000 (+0000) Subject: [project @ 1996-06-27 15:55:53 by partain] X-Git-Tag: Approximately_1000_patches_recorded~907 X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=commitdiff_plain;h=a7e6cdbfc4f27c2e0ab9c12ebe6431c246c74c6d [project @ 1996-06-27 15:55:53 by partain] partain 1.3 changes to 960626 --- diff --git a/ANNOUNCE-2.01 b/ANNOUNCE-2.01 new file mode 100644 index 0000000..0fc4ab0 --- /dev/null +++ b/ANNOUNCE-2.01 @@ -0,0 +1,165 @@ + The Glasgow Haskell Compiler -- version 2.01 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We are proud to announce the first public release of the Glasgow +Haskell Compiler (GHC) for the revised Haskell 1.3 language. Sources +and binaries are freely available by anonymous FTP and on the +World-Wide Web; details below. + +GHC 2.01 is a test-quality release, worth trying if you are a gung-ho +Haskell user or if you want to ensure that we quickly fix bugs that +affect your programs :-) We advise *AGAINST* deleting your copy of +that old workhorse GHC 0.26 (for Haskell 1.2), and *AGAINST* relying +on this compiler (2.01) in any way. With your help in testing 2.01, +we hope to release a more solid Haskell 1.3 compiler relatively soon. + +Haskell is "the" standard lazy functional programming language [see +SIGPLAN Notices, May 1992]. The current language version is 1.3, +agreed in May, 1996. + +The Glasgow Haskell project seeks to bring the power and elegance of +functional programming to bear on real-world problems. To that end, +GHC lets you call C (including cross-system garbage collection), +provides good profiling tools, supports ever richer I/O, and +concurrency and parallelism. Our goal is to make it the "tool of +choice for real-world applications". + +GHC 2.01 is quite different from 0.26 (July 1995), as the new version +number suggests. (The 1.xx numbers are reserved for any Haskell-1.2 +compiler releases.) Changes worth noting include: + +....... + + * Concurrent Haskell: with this, you can build programs out of many + I/O-performing, interacting `threads'. We have a draft paper + about Concurrent Haskell, and our forthcoming Haggis GUI toolkit + uses it. + + * Parallel Haskell, running on top of PVM (Parallel Virtual Machine) + and hence portable to pretty much any parallel architecture, + whether shared memory or distributed memory. With this, your + Haskell program runs on multiple processors, guided by `par` and + `seq` annotations. The first pretty-much-everyone-can-try-it + parallel functional programming system! NB: The parallel stuff is + "research-tool quality"... consider this an alpha release. + + * "Foldr/build" deforestation (by Andy Gill) is in, as are + "SPECIALIZE instance" pragmas (by Patrick Sansom). + + * The LibPosix library provides an even richer I/O interface than + the standard 1.3 I/O library. A program like a shell or an FTP + client can be written in Haskell -- examples included. + + * Yet more cool libraries: Readline (GNU command-line editing), + Socket (BSD sockets), Regex and MatchPS (GNU regular expressions). + By Darren Moffat and Sigbjorn Finne. + + * New ports -- Linux (a.out) and MIPS (Silicon Graphics). + + * NB: configuration has changed yet again -- for the better, of + course :-) + +Please see the release notes for a complete discussion of What's New. + +To run this release, you need a machine with 16+MB memory, GNU C +(`gcc'), and `perl'. We have seen GHC 0.26 work on these platforms: +alpha-dec-osf2, hppa1.1-hp-hpux9, i386-unknown-linuxaout, +m68k-sun-sunos4, mips-sgi-irix5, and sparc-sun-{sunos4,solaris2}. +Similar platforms should work with minimal hacking effort. +The installer's guide give a full what-ports-work report. + +Binaries are now distributed in `bundles', e.g. a "profiling bundle" +or a "concurrency bundle" for your platform. Just grab the ones you +need. + +Once you have the distribution, please follow the pointers in +ghc/README to find all of the documentation about this release. NB: +preserve modification times when un-tarring the files (no `m' option +for tar, please)! + +We run mailing lists for GHC users and bug reports; to subscribe, send +mail to glasgow-haskell-{users,bugs}-request@dcs.glasgow.ac.uk. +Please send bug reports to glasgow-haskell-bugs. + +Particular thanks to: Jim Mattson (author of much of the code) who has +now moved to HP in California; and the Turing Institute who donated a +lot of SGI cycles for the SGI port. + +Simon Peyton Jones and Will Partain + +Dated: 95/07/24 + +Relevant URLs on the World-Wide Web: + +GHC home page http://www.dcs.glasgow.ac.uk/fp/software/ghc.html +Glasgow FP group page http://www.dcs.glasgow.ac.uk/fp/ +comp.lang.functional FAQ http://www.cs.nott.ac.uk/Department/Staff/mpj/faq.html + +====================================================================== +How to get GHC 0.26: + +This release is available by anonymous FTP from the main Haskell +archive sites, in the directory pub/haskell/glasgow: + + ftp.dcs.glasgow.ac.uk (130.209.240.50) + ftp.cs.chalmers.se (129.16.227.140) + haskell.cs.yale.edu (128.36.11.43) + +The Glasgow site is mirrored by src.doc.ic.ac.uk (146.169.43.1), in +computing/programming/languages/haskell/glasgow. + +These are the available files (.gz files are gzipped) -- some are `on +demand', ask if you don't see them: + +ghc-0.26-src.tar.gz The source distribution; about 3MB. + +ghc-0.26.ANNOUNCE This file. + +ghc-0.26.{README,RELEASE-NOTES} From the distribution; for those who + want to peek before FTPing... + +ghc-0.26-ps-docs.tar.gz Main GHC documents in PostScript format; in + case your TeX setup doesn't agree with our + DVI files... + +ghc-0.26-.tar.gz Basic binary distribution for a particular + . Unpack and go: you can compile + and run Haskell programs with nothing but one + of these files. NB: does *not* include + profiling (see below). + + ==> alpha-dec-osf2 + hppa1.1-hp-hpux9 + i386-unknown-linuxaout + i386-unknown-solaris2 + m68k-sun-sunos4 + mips-sgi-irix5 + sparc-sun-sunos4 + sparc-sun-solaris2 + +ghc-0.26--.tar.gz + + ==> as above + ==> prof (profiling) + conc (concurrent Haskell) + par (parallel) + gran (GranSim parallel simulator) + ticky (`ticky-ticky' counts -- for implementors) + prof-conc (profiling for "conc[urrent]") + prof-ticky (ticky for "conc[urrent]") + +ghc-0.26-hc-files.tar.gz Basic set of intermediate C (.hc) files for the + compiler proper, the prelude, and `Hello, + world'. Used for bootstrapping the system. + About 4MB. + +ghc-0.26--hc-files.tar.gz Further sets of .hc files, for + building other "bundles", e.g., profiling. + +ghc-0.26-hi-files-.tar.gz Sometimes it's more convenient to + use a different set of interface files than + the ones in *-src.tar.gz. (The installation + guide will advise you of this.) + +We could provide diffs from previous versions of GHC, should you +require them. A full set would be very large (7MB). diff --git a/Makefile.in b/Makefile.in index 3626858..93b4582 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,6 +31,6 @@ Makefile: Makefile.in config.status config.status: configure $(SHELL) config.status --recheck configure: configure.in - cd $(srcdir); autoconf < configure.in > configure.new + cd $(srcdir) && autoconf < configure.in > configure.new grep -v '# Generated automatically from' < configure.new > configure diff --git a/STARTUP.in b/STARTUP.in index 814426a..0416b7f 100644 --- a/STARTUP.in +++ b/STARTUP.in @@ -30,15 +30,15 @@ esac for i in @DoingMkWorld@ @DoingGlaFpUtils@ @DoingLiterate@ ; do if [ -d $i ] ; then - ( set -e; \ - cd $i ; \ - echo '' ; \ - echo "*** configuring $i ..." ; \ - make -f Makefile.BOOT BOOT_DEFINES="-P none -S std -DTopDirPwd=$hardtop"; \ - echo '' ; \ - echo "*** making Makefiles in $i ..." ; \ - make Makefile ; \ - make Makefiles \ + ( set -e; \ + cd $i ; \ + echo '' ; \ + echo "*** configuring $i ..." ; \ + @MakeCmd@ -f Makefile.BOOT BOOT_DEFINES="-P none -S std -DTopDirPwd=$hardtop"; \ + echo '' ; \ + echo "*** making Makefiles in $i ..." ; \ + @MakeCmd@ Makefile ; \ + @MakeCmd@ Makefiles \ ) else echo warning: $i is not a directory -- doing nothing for it @@ -49,14 +49,14 @@ done for i in @DoingMkWorld@ @DoingGlaFpUtils@ @DoingLiterate@ ; do if [ -d $i ] ; then - ( set -e; \ - cd $i ; \ - echo '' ; \ - echo "*** making dependencies in $i ..." ; \ - make depend ; \ - echo '' ; \ - echo "*** making all in $i ..." ; \ - make all \ + ( set -e; \ + cd $i ; \ + echo '' ; \ + echo "*** making dependencies in $i ..." ; \ + @MakeCmd@ depend ; \ + echo '' ; \ + echo "*** making all in $i ..." ; \ + @MakeCmd@ all \ ) else echo warning: $i is not a directory -- doing nothing for it @@ -67,22 +67,22 @@ done passed_in_setup="-S @MkWorldSetup@" -for i in @DoingGHC@ @DoingHappy@ @DoingHaggis@ @DoingNoFib@ EndOfList ; do +for i in @DoingGHC@ @DoingHsLibs@ @DoingHappy@ @DoingHaggis@ @DoingNoFib@ EndOfList ; do if [ $i = nofib ] ; then setup=$passed_in_setup else setup='' fi if [ -d $i ] ; then - ( set -e; \ - cd $i ; \ - echo '' ; \ - echo "*** configuring $i ..." ; \ - make -f Makefile.BOOT BOOT_DEFINES="-P $i $setup -C mkworld -DTopDirPwd=$hardtop"; \ - echo '' ; \ - echo "*** making Makefiles in $i ..." ; \ - make Makefile ; \ - make Makefiles \ + ( set -e; \ + cd $i ; \ + echo '' ; \ + echo "*** configuring $i ..." ; \ + @MakeCmd@ -f Makefile.BOOT BOOT_DEFINES="-P $i $setup -C mkworld -DTopDirPwd=$hardtop"; \ + echo '' ; \ + echo "*** making Makefiles in $i ..." ; \ + @MakeCmd@ Makefile ; \ + @MakeCmd@ Makefiles \ ) else if [ $i != EndOfList ] ; then @@ -93,13 +93,13 @@ done # Finally, the dependencies -for i in @DoingGHC@ @DoingHappy@ @DoingHaggis@ @DoingNoFib@ EndOfList ; do +for i in @DoingGHC@ @DoingHsLibs@ @DoingHappy@ @DoingHaggis@ @DoingNoFib@ EndOfList ; do if [ -d $i ] ; then - ( set -e; \ - cd $i ; \ - echo '' ; \ - echo "*** making dependencies in $i ..." ; \ - make depend \ + ( set -e; \ + cd $i ; \ + echo '' ; \ + echo "*** making dependencies in $i ..." ; \ + @MakeCmd@ depend \ ) else if [ $i != EndOfList ] ; then @@ -112,7 +112,7 @@ echo '' echo '*******************************************************************' echo "* Looking good! All you should need to do now is... *" echo '* *' -for i in @DoingGHC@ @DoingHappy@ @DoingHaggis@ @DoingNoFib@ EndOfList ; do +for i in @DoingGHC@ @DoingHsLibs@ @DoingHappy@ @DoingHaggis@ @DoingNoFib@ EndOfList ; do if [ $i != EndOfList ] ; then echo " cd $i" if [ $i = nofib ] ; then diff --git a/config.guess b/config.guess index 41f828a..c3c4e79 100644 --- a/config.guess +++ b/config.guess @@ -1,6 +1,6 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +# Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -14,7 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -51,14 +51,21 @@ trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - alpha:OSF1:V*:*) + alpha:OSF1:[VX]*:*) # After 1.2, OSF1 uses "V1.3" for uname -r. - echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'` + # After 4.x, OSF1 uses "X4.x" for uname -r. + echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VX]//'` exit 0 ;; alpha:OSF1:*:*) # 1.2 uses "1.2" for uname -r. echo alpha-dec-osf${UNAME_RELEASE} exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; amiga:NetBSD:*:*) echo m68k-cbm-netbsd${UNAME_RELEASE} exit 0 ;; @@ -111,9 +118,15 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; + mips:*:4*:UMIPS) + echo mips-mips-riscos4sysv + exit 0 ;; mips:*:5*:RISCos) echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; @@ -124,12 +137,17 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88100 ] ; then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 @@ -181,10 +199,8 @@ EOF else IBM_ARCH=powerpc fi - if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then - IBM_REV=4.1 - elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then - IBM_REV=4.1.1 + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` else IBM_REV=4.${UNAME_RELEASE} fi @@ -215,7 +231,7 @@ EOF case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;; + 9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;; 9000/8?? ) HP_ARCH=hppa1.0 ;; esac HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` @@ -251,13 +267,13 @@ EOF rm -f dummy.c dummy echo unknown-hitachi-hiuxwe2 exit 0 ;; - 9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* ) + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; - hp7??:OSF1:*:* | hp8?7:OSF1:*:* ) + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) @@ -308,19 +324,38 @@ EOF *:NetBSD:*:*) echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` exit 0 ;; + i*:CYGWIN*:*) + echo i386-unknown-cygwin32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:Linux:*:*) - # Systems without a BFD linker - if test -d /usr/lib/ldscripts/. ; then - : + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then + echo "${UNAME_MACHINE}-unknown-linux" ; exit 0 + elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then + echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0 + elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then + echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0 + elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then + echo "${UNAME_MACHINE}-unknown-linux" ; exit 0 + elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then + echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0 + elif test "${UNAME_MACHINE}" = "alpha" ; then + echo alpha-unknown-linux ; exit 0 else - echo "${UNAME_MACHINE}-unknown-linuxoldld" - exit 0 - fi - # Determine whether the default compiler is a.out or elf - cat >dummy.c <dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 - rm -f dummy.c dummy;; + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions # are messed up and put the nodename in both sysname and nodename. i[34]86:DYNIX/ptx:4*:*) @@ -354,6 +390,8 @@ EOF elif /bin/uname -X 2>/dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL else echo ${UNAME_MACHINE}-unknown-sysv32 @@ -384,19 +422,19 @@ EOF 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; - m680[234]0:LynxOS:2.2*:*) + m680[234]0:LynxOS:2.[23]*:*) echo m68k-lynx-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; - i[34]86:LynxOS:2.2*:*) + i[34]86:LynxOS:2.[23]*:*) echo i386-lynx-lynxos${UNAME_RELEASE} exit 0 ;; - TSUNAMI:LynxOS:2.2*:*) + TSUNAMI:LynxOS:2.[23]*:*) echo sparc-lynx-lynxos${UNAME_RELEASE} exit 0 ;; - rs6000:LynxOS:2.2*:*) + rs6000:LynxOS:2.[23]*:*) echo rs6000-lynx-lynxos${UNAME_RELEASE} exit 0 ;; RM*:SINIX-*:*:*) @@ -410,12 +448,26 @@ EOF echo ns32k-sni-sysv fi exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + R3000:*System_V*:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 cat >dummy.c < +# include +#endif main () { #if defined (sony) @@ -479,7 +531,18 @@ main () #endif #if defined (_SEQUENT_) - printf ("i386-sequent-ptx\n"); exit (0); + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + #endif #if defined (vax) diff --git a/config.sub b/config.sub index 93371be..c462f8a 100644 --- a/config.sub +++ b/config.sub @@ -1,6 +1,6 @@ #! /bin/sh # Configuration validation subroutine script, version 1.1. -# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. @@ -17,7 +17,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -84,9 +85,27 @@ case $os in os= basic_machine=$1 ;; + -sim | -cisco | -oki | -wec | -winbond ) # CYGNUS LOCAL + os= + basic_machine=$1 + ;; + -apple*) # CYGNUS LOCAL + os= + basic_machine=$1 + ;; + -scout) # CYGNUS LOCAL + ;; + -wrs) # CYGNUS LOCAL + os=vxworks + basic_machine=$1 + ;; -hiux*) os=-hiuxwe2 ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` + ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'` @@ -122,19 +141,31 @@ case $os in -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; + -psos*) + os=-psos + ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. - tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm \ + tahoe | i[3456]86 | i860 | m68k | m68000 | m88k | ns32k | arm \ | arme[lb] | pyramid \ | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \ - | alpha | we32k | ns16k | clipper | sparclite | i370 | sh \ - | powerpc | powerpcle | sparc64 | 1750a | dsp16xx | mips64 | mipsel \ + | alpha | we32k | ns16k | clipper | i370 | sh \ + | powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \ | pdp11 | mips64el | mips64orion | mips64orionel \ - | sparc) + | sparc | sparclet | sparclite | sparc64) + basic_machine=$basic_machine-unknown + ;; + m88110 | m680[01234]0 | m683?2 | m68360 | z8k | v70 | h8500 | w65) # CYGNUS LOCAL + basic_machine=$basic_machine-unknown + ;; + mips64vr4300 | mips64vr4300el) # CYGNUS LOCAL jsmith/vr4300 + basic_machine=$basic_machine-unknown + ;; + mips64vr4100 | mips64vr4100el) # CYGNUS LOCAL jsmith/vr4100 basic_machine=$basic_machine-unknown ;; # Object if more than one company name word. @@ -143,8 +174,8 @@ case $basic_machine in exit 1 ;; # Recognize the basic CPU types with company name. - vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \ - | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \ + vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \ + | sparc-* | ns32k-* | fx80-* | arm-* | arme[lb]-* | c[123]* \ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \ | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \ | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \ @@ -152,14 +183,32 @@ case $basic_machine in | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \ | mips64el-* | mips64orion-* | mips64orionel-*) ;; + m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | h8500-*) # CYGNUS LOCAL + ;; + mips64vr4300-* | mips64vr4300el-*) # CYGNUS LOCAL jsmith/vr4300 + ;; + mips64vr4100-* | mips64vr4100el-*) # CYGNUS LOCAL jsmith/vr4100 + ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. + 386bsd) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-bsd + ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; + a29khif) # CYGNUS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) # CYGNUS LOCAL + basic_machine=m68010-adobe + os=-scout + ;; alliant | fx80) basic_machine=fx80-alliant ;; @@ -189,6 +238,18 @@ case $basic_machine in basic_machine=m68k-apollo os=-sysv ;; + apollo68bsd) # CYGNUS LOCAL + basic_machine=m68k-apollo + os=-bsd + ;; + arm | armel | armeb) + basic_machine=arm-arm + os=-aout + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; balance) basic_machine=ns32k-sequent os=-dynix @@ -257,6 +318,10 @@ case $basic_machine in encore | umax | mmax) basic_machine=ns32k-encore ;; + es1800 | OSE68k | ose68k | ose | OSE) # CYGNUS LOCAL + basic_machine=m68k-ericsson + os=-ose + ;; fx2800) basic_machine=i860-alliant ;; @@ -275,6 +340,14 @@ case $basic_machine in basic_machine=h8300-hitachi os=-hms ;; + h8300xray) # CYGNUS LOCAL + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) # CYGNUS LOCAL + basic_machine=h8500-hitachi + os=-hms + ;; harris) basic_machine=m88k-harris os=-sysv3 @@ -290,6 +363,22 @@ case $basic_machine in basic_machine=m68k-hp os=-hpux ;; + w89k-*) # CYGNUS LOCAL + basic_machine=hppa1.1-winbond + os=-proelf + ;; + op50n-*) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + op60c-*) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + hppro) # CYGNUS LOCAL + basic_machine=hppa1.1-hp + os=-proelf + ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; @@ -302,27 +391,43 @@ case $basic_machine in hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; + hppaosf) # CYGNUS LOCAL + basic_machine=hppa1.1-hp + os=-osf + ;; i370-ibm* | ibm*) basic_machine=i370-ibm os=-mvs ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? - i[345]86v32) + i[3456]86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` os=-sysv32 ;; - i[345]86v4*) + i[3456]86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` os=-sysv4 ;; - i[345]86v) + i[3456]86v) basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` os=-sysv ;; - i[345]86sol2) + i[3456]86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'` os=-solaris2 ;; + i386mach) # CYGNUS LOCAL + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-go32 + ;; iris | iris4d) basic_machine=mips-sgi case $os in @@ -357,10 +462,22 @@ case $basic_machine in mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; + monitor) # CYGNUS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) # CYGNUS LOCAL + basic_machine=i386-unknown + os=-msdos + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; + netbsd386) + basic_machine=i386-unknown # CYGNUS LOCAL + os=-netbsd + ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos @@ -373,6 +490,10 @@ case $basic_machine in basic_machine=mips-sony os=-newsos ;; + necv70) # CYGNUS LOCAL + basic_machine=v70-nec + os=-sysv + ;; next | m*-next ) basic_machine=m68k-next case $os in @@ -398,9 +519,21 @@ case $basic_machine in basic_machine=i960-intel os=-nindy ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; np1) basic_machine=np1-gould ;; + OSE68000 | ose68000) # CYGNUS LOCAL + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) # CYGNUS LOCAL + basic_machine=m68k-none + os=-os68k + ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 @@ -418,14 +551,18 @@ case $basic_machine in pc532 | pc532-*) basic_machine=ns32k-pc532 ;; - pentium | p5 | p6) - # We don't have specific support for the Intel Pentium (p6) followon yet, so just call it a Pentium + pentium | p5) basic_machine=i586-intel ;; - pentium-* | p5-* | p6-*) - # We don't have specific support for the Intel Pentium (p6) followon yet, so just call it a Pentium + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; k5) # We don't have specific support for AMD's K5 yet, so just call it a Pentium basic_machine=i586-amd @@ -452,12 +589,20 @@ case $basic_machine in ps2) basic_machine=i386-ibm ;; + rom68k) # CYGNUS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; + sa29200) # CYGNUS LOCAL + basic_machine=a29k-amd + os=-udi + ;; sequent) basic_machine=i386-sequent ;; @@ -465,6 +610,10 @@ case $basic_machine in basic_machine=sh-hitachi os=-hms ;; + sparclite-wrs) # CYGNUS LOCAL + basic_machine=sparclite-wrs + os=-vxworks + ;; sps7) basic_machine=m68k-bull os=-sysv2 @@ -472,6 +621,13 @@ case $basic_machine in spur) basic_machine=spur-unknown ;; + st2000) # CYGNUS LOCAL + basic_machine=m68k-tandem + ;; + stratus) # CYGNUS LOCAL + basic_machine=i860-stratus + os=-sysv4 + ;; sun2) basic_machine=m68000-sun ;; @@ -527,6 +683,10 @@ case $basic_machine in basic_machine=a29k-nyu os=-sym1 ;; + v810 | necv810) # CYGNUS LOCAL + basic_machine=v810-nec + os=-none + ;; vaxv) basic_machine=vax-dec os=-sysv @@ -547,6 +707,10 @@ case $basic_machine in basic_machine=a29k-wrs os=-vxworks ;; + w65*) # CYGNUS LOCAL + basic_machine=w65-wdc + os=-none + ;; xmp) basic_machine=xmp-cray os=-unicos @@ -554,6 +718,10 @@ case $basic_machine in xps | xps100) basic_machine=xps100-honeywell ;; + z8k-*-coff) # CYGNUS LOCAL + basic_machine=z8k-unknown + os=-sim + ;; none) basic_machine=none-none os=-none @@ -561,6 +729,15 @@ case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. + w89k) # CYGNUS LOCAL + basic_machine=hppa1.1-winbond + ;; + op50n) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + ;; + op60c) # CYGNUS LOCAL + basic_machine=hppa1.1-oki + ;; mips) basic_machine=mips-mips ;; @@ -591,6 +768,12 @@ case $basic_machine in orion105) basic_machine=clipper-highlevel ;; + mac | mpw | mac-mpw) # CYGNUS LOCAL + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) # CYGNUS LOCAL + basic_machine=powerpc-apple + ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 @@ -632,17 +815,27 @@ case $os in # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \ + | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[3456]* \ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \ - | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \ + | -amigados* | -msdos* | -moss* | -newsos* | -unicos* | -aos* | -aof* \ + | -nindy* | -mon960* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \ | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* ) + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos*) # Remember, each alternative MUST END IN *, to match a version number. ;; + # CYGNUS LOCAL + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -proelf | -os9* \ + | -macos* | -mpw* | -magic*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + # END CYGNUS LOCAL -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; @@ -664,9 +857,15 @@ case $os in -acis*) os=-aos ;; + -386bsd) # CYGNUS LOCAL + os=-bsd + ;; -ctix* | -uts*) os=-sysv ;; + -ns2 ) + os=-nextstep2 + ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` @@ -692,6 +891,12 @@ case $os in # This must come after -sysvr4. -sysv*) ;; + -ose*) # CYGNUS LOCAL + os=-ose + ;; + -es1800*) # CYGNUS LOCAL + os=-ose + ;; -xenix) os=-xenix ;; @@ -741,6 +946,12 @@ case $basic_machine in # default. # os=-sunos4 ;; + m68*-cisco) # CYGNUS LOCAL + os=-aout + ;; + mips*-cisco) # CYGNUS LOCAL + os=-elf + ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; @@ -750,6 +961,15 @@ case $basic_machine in *-ibm) os=-aix ;; + *-wec) # CYGNUS LOCAL + os=-proelf + ;; + *-winbond) # CYGNUS LOCAL + os=-proelf + ;; + *-oki) # CYGNUS LOCAL + os=-proelf + ;; *-hp) os=-hpux ;; @@ -774,6 +994,9 @@ case $basic_machine in m88k-omron*) os=-luna ;; + *-next ) + os=-nextstep + ;; *-sequent) os=-ptx ;; @@ -807,6 +1030,15 @@ case $basic_machine in *-masscomp) os=-rtu ;; + *-rom68k) # CYGNUS LOCAL + os=-coff + ;; + *-*bug) # CYGNUS LOCAL + os=-coff + ;; + *-apple) # CYGNUS LOCAL + os=-macos + ;; *) os=-none ;; @@ -825,6 +1057,9 @@ case $basic_machine in -sunos*) vendor=sun ;; + -bosx*) # CYGNUS LOCAL + vendor=bull + ;; -lynxos*) vendor=lynx ;; @@ -858,6 +1093,15 @@ case $basic_machine in -vxworks*) vendor=wrs ;; + -aux*) + vendor=apple + ;; + -hms*) # CYGNUS LOCAL + vendor=hitachi + ;; + -mpw* | -macos*) # CYGNUS LOCAL + vendor=apple + ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; diff --git a/configure.in b/configure.in index c3f058c..3a57a3c 100644 --- a/configure.in +++ b/configure.in @@ -17,7 +17,8 @@ AC_INIT(STARTUP.in) # # Prepare to generate the following header files # -AC_CONFIG_HEADER(ghc/includes/config.h literate/config.h) +AC_CONFIG_HEADER(ghc/includes/config.h) +# and literate/config.h ??? # ToDo !!!!!!!!!!!!!!!! # # No, we don't do `--srcdir'... @@ -27,15 +28,16 @@ if test x"$srcdir" != 'x.' ; then fi # ------------------------------------------------------------------------- -dnl ** choose what blobs to build (ghc,haggis,happy,nofib,????) +dnl ** choose what blobs to build (ghc,hslibs,haggis,happy,nofib,????) # set to the name for the dir if doing it, otherwise empty DoingGHC='ghc' +DoingHsLibs='' DoingNoFib='' DoingHappy='' DoingHaggis='' +DoingLiterate='' # the following are not normally changed -DoingLiterate='literate' DoingMkWorld='mkworld' DoingGlaFpUtils='glafp-utils' @@ -48,7 +50,7 @@ AC_ARG_ENABLE(ghc, ********************************************************************** First, select *which* of the tools you want to build, -with --{enable,disable}-{ghc,nofib,happy,haggis}. +with --{enable,disable}-{ghc,hslibs,nofib,happy,haggis}. (The default is: only GHC (Glasgow Haskell compiler).) Second, you may set one of a few applies-in-all-cases options. @@ -91,6 +93,26 @@ if test "xxx$DoingGHC" = 'xxx' ; then # ghc_includes_config_h='' fi +AC_ARG_ENABLE(hslibs, + [--enable-hslibs build suite of Haskell libraries], + [case "$enableval" in + yes) DoingHsLibs='hslibs' + ;; + no) DoingHsLibs='' + ;; + *) echo "I don't understand this option: --enable-hslibs=$enableval" + exit 1 + ;; + esac]) +if test "xxx$DoingHsLibs" = 'xxxhslibs' -a \( ! -d hslibs \) ; then + DoingHsLibs='' + echo 'Doing --disable-hslibs, as there is no hslibs directory' +fi +hslibs_mkworld_site_hslibs_jm='hslibs/mkworld/site-hslibs.jm' +if test "xxx$DoingHsLibs" = 'xxx' ; then + hslibs_mkworld_site_hslibs_jm='' +fi + AC_ARG_ENABLE(nofib, [--enable-nofib build NoFib suite as part of Glasgow FP tools], [case "$enableval" in @@ -128,7 +150,7 @@ if test "xxx$DoingHappy" = 'xxxhappy' -a \( ! -d happy \) ; then fi AC_ARG_ENABLE(haggis, - [--disable-haggis build Haggis GUI toolkit as part of Glasgow FP tools], + [--enable-haggis build Haggis GUI toolkit as part of Glasgow FP tools], [case "$enableval" in yes) DoingHaggis='haggis' ;; @@ -194,6 +216,7 @@ if test "xxx$DoingGlaFpUtils" = 'xxxglafp-utils' -a \( ! -d glafp-utils \) ; the fi AC_SUBST(DoingGHC) +AC_SUBST(DoingHsLibs) AC_SUBST(DoingNoFib) AC_SUBST(DoingHappy) AC_SUBST(DoingHaggis) @@ -207,7 +230,7 @@ dnl ** choose host(/target/build) platform # Partly stolen from GCC "configure". # if test "x$target" = xNONE ; then - if test "x$nonopt" != xNONE; then + if test "x$nonopt" != xNONE ; then target=$nonopt else # This way of testing the result of a command substitution is @@ -217,8 +240,7 @@ if test "x$target" = xNONE ; then else echo 'Config.guess failed to determine the host type. You need \ to specify one.' 1>&2 - if [ -r config.status ] - then + if test -r config.status ; then tail +2 config.status 1>&2 fi exit 1 @@ -254,7 +276,7 @@ fi # We also record the architecture, vendor, and operating system (OS) # separately. case $HostPlatform in -alpha-dec-osf1* | alpha-dec-osf2*) +alpha-dec-osf[[1234]]*) HostPlatform=alpha-dec-osf1 # canonicalise for our purposes TargetPlatform=alpha-dec-osf1 # this will work for now... (hack) BuildPlatform=alpha-dec-osf1 #hack @@ -272,7 +294,7 @@ hppa1.1-hp-hpux*) HostVendor_CPP='hp' HostOS_CPP='hpux' ;; -i386-*-linuxaout*) +i[[3456]]86-*-linuxaout*) HostPlatform=i386-unknown-linuxaout # hack again TargetPlatform=i386-unknown-linuxaout BuildPlatform=i386-unknown-linuxaout @@ -281,16 +303,7 @@ i386-*-linuxaout*) HostVendor_CPP='unknown' HostOS_CPP='linuxaout' ;; -i486-*-linuxaout*) - HostPlatform=i386-unknown-linuxaout # hack again: NB: name for arch is *i386*! - TargetPlatform=i386-unknown-linuxaout - BuildPlatform=i386-unknown-linuxaout - HostPlatform_CPP='i386_unknown_linuxaout' - HostArch_CPP='i386' - HostVendor_CPP='unknown' - HostOS_CPP='linuxaout' - ;; -i386-*-linux*) +i[[3456]]86-*-linux*) HostPlatform=i386-unknown-linux # hack again TargetPlatform=i386-unknown-linux BuildPlatform=i386-unknown-linux @@ -299,40 +312,25 @@ i386-*-linux*) HostVendor_CPP='unknown' HostOS_CPP='linux' ;; -i486-*-linux*) - HostPlatform=i386-unknown-linux # hack again: NB: name for arch is *i386*! - TargetPlatform=i386-unknown-linux - BuildPlatform=i386-unknown-linux - HostPlatform_CPP='i386_unknown_linux' - HostArch_CPP='i386' - HostVendor_CPP='unknown' - HostOS_CPP='linux' - ;; -i386-*-freebsd*) - HostPlatform_CPP='i386_unknown_freebsd' - HostArch_CPP='i386' - HostVendor_CPP='unknown' - HostOS_CPP='freebsd' - ;; -i486-*-freebsd*) +i[[3456]]86-*-freebsd*) + HostPlatform=i386-unknown-freebsd # hack again + TargetPlatform=i386-unknown-freebsd + BuildPlatform=i386-unknown-freebsd HostPlatform_CPP='i386_unknown_freebsd' HostArch_CPP='i386' HostVendor_CPP='unknown' HostOS_CPP='freebsd' ;; -i386-*-netbsd*) +i[[3456]]86-*-netbsd*) + HostPlatform=i386-unknown-netbsd # hack again + TargetPlatform=i386-unknown-netbsd + BuildPlatform=i386-unknown-netbsd HostPlatform_CPP='i386_unknown_netbsd' HostArch_CPP='i386' HostVendor_CPP='unknown' HostOS_CPP='netbsd' ;; -i486-*-netbsd*) - HostPlatform_CPP='i386_unknown_netbsd' - HostArch_CPP='i386' - HostVendor_CPP='unknown' - HostOS_CPP='netbsd' - ;; -i386-*-solaris2*) +i[[3456]]86-*-solaris2*) HostPlatform=i386-unknown-solaris2 # hack again TargetPlatform=i386-unknown-solaris2 BuildPlatform=i386-unknown-solaris2 @@ -353,7 +351,7 @@ m68k-next-nextstep3) HostVendor_CPP='next' HostOS_CPP='nextstep3' ;; -i386-next-nextstep3) +i[[3456]]86-next-nextstep3) HostPlatform=i386-next-nextstep3 # hack again TargetPlatform=i386-next-nextstep3 BuildPlatform=i386-next-nextstep3 @@ -617,6 +615,10 @@ if test -z "$YaccCmd"; then fi fi +dnl ** Find lex command (lex or flex) and library (-ll or -lfl) +# +AC_PROG_LEX + #-------------------------------------------------------------- WithHc='haskell-compiler-unspecified' WithHcType='HC_UNSPECIFIED' @@ -689,14 +691,37 @@ esac AC_SUBST(WithHc) AC_SUBST(WithHcType) +dnl ** Possibly use something else instead of 'gcc'. +WhatGccIsCalled=gcc +AC_ARG_WITH(gcc, + [--with-gcc= + Use a different command instead of 'gcc' for the GNU C compiler.], + [HaveGcc=YES; WhatGccIsCalled="$withval"]) +AC_SUBST(WhatGccIsCalled) + +dnl ** Choose which make to use (default 'make -r') +MakeCmd='make -r' +AC_ARG_WITH(make, + [ +--with-make= + Use an alternate command instead of 'make'. This is useful + when GNU make is required (for instance when the default make + supplied by the system won't work, as is the case on FreeBSD + and NetBSD). You probably want to include the '-r' flag with + make, to exclude implicit suffix rules.], + [MakeCmd="$withval"]) +AC_SUBST(MakeCmd) + dnl ** possibly choose a different tmpdir (default /tmp) # let the user decide where the best tmpdir is # /tmp is the default; /usr/tmp is sometimes a good choice. # Very site-specific. TmpDir='/tmp' AC_ARG_WITH(tmpdir, - [--with-tmpdir= Use an alternative directory for -temporary files (presumably because /tmp is too small).], + [ +--with-tmpdir= + Use an alternative directory for temporary files (presumably + because /tmp is too small).], [TmpDir="$withval"]) AC_SUBST(TmpDir) @@ -707,8 +732,9 @@ HcMaxHeapWasSet='NO' HcMaxHeap='0' AC_ARG_WITH(max-heap, [ ---with-max-heap= Do all Haskell compilations -with a heap of this size. (If you've got it, flaunt it.)], +--with-max-heap= + Do all Haskell compilations with a heap of this size. (If + you've got it, flaunt it.)], [HcMaxHeapWasSet='YES' HcMaxHeap="$withval"]) AC_SUBST(HcMaxHeapWasSet) @@ -769,6 +795,9 @@ elif $ArCmd clq conftest.a >/dev/null 2>/dev/null; then elif $ArCmd cq conftest.a >/dev/null 2>/dev/null; then ArCmd="$ArCmd cq" NeedRanLib='YES' +elif $ArCmd cq conftest.a 2>&1 | grep 'no archive members specified' >/dev/null 2>/dev/null; then + ArCmd="$ArCmd cq" + NeedRanLib='YES' else echo "I can't figure out how to use your $ArCmd" exit 1 @@ -815,21 +844,6 @@ dnl ** determine the type of signal() # AC_TYPE_SIGNAL # -dnl ** decide whether or not flex lexers need to be linked with -lfl -# -AC_CHECK_LIB(fl,yywrap, - FlexLibAvailable='YES', - FlexLibAvailable='NO') -AC_SUBST(FlexLibAvailable) -# -dnl ** Decide whether or not lex lexers need to be linked with -ll -# (Linux, for example, does not have "lex", only "flex") -# -AC_CHECK_LIB(l,yywrap, - LexLibAvailable='YES', - LexLibAvailable='NO') -AC_SUBST(LexLibAvailable) -# dnl ** check for specific library functions that we are interested in # AC_CHECK_FUNCS(access ftime getclock getpagesize getrusage gettimeofday mktime mprotect setitimer stat sysconf timelocal times vadvise vfork) @@ -1047,224 +1061,226 @@ AC_ARG_ENABLE(gc-du, ;; esac]) -dnl some seds only allow 99 commands, meaning no more -dnl than 99 AC_SUBSTs. AARRGGHH!! -dnl AC_ARG_ENABLE(user-way-a, -dnl [--enable-user-way-a build for \`user way a' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_a='YES' -dnl ;; -dnl no) GhcBuild_a='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-a=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-b, -dnl [--enable-user-way-b build for \`user way b' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_b='YES' -dnl ;; -dnl no) GhcBuild_b='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-b=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-c, -dnl [--enable-user-way-c build for \`user way c' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_c='YES' -dnl ;; -dnl no) GhcBuild_c='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-c=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-d, -dnl [--enable-user-way-d build for \`user way d' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_d='YES' -dnl ;; -dnl no) GhcBuild_d='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-d=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-e, -dnl [--enable-user-way-e build for \`user way e' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_e='YES' -dnl ;; -dnl no) GhcBuild_e='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-e=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-f, -dnl [--enable-user-way-f build for \`user way f' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_f='YES' -dnl ;; -dnl no) GhcBuild_f='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-f=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-g, -dnl [--enable-user-way-g build for \`user way g' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_g='YES' -dnl ;; -dnl no) GhcBuild_g='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-g=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-h, -dnl [--enable-user-way-h build for \`user way h' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_h='YES' -dnl ;; -dnl no) GhcBuild_h='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-h=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-i, -dnl [--enable-user-way-i build for \`user way i' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_i='YES' -dnl ;; -dnl no) GhcBuild_i='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-i=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-j, -dnl [--enable-user-way-j build for \`user way j' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_j='YES' -dnl ;; -dnl no) GhcBuild_j='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-j=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-k, -dnl [--enable-user-way-k build for \`user way k' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_k='YES' -dnl ;; -dnl no) GhcBuild_k='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-k=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-l, -dnl [--enable-user-way-l build for \`user way l' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_l='YES' -dnl ;; -dnl no) GhcBuild_l='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-l=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-m, -dnl [--enable-user-way-m build for \`user way m' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_m='YES' -dnl ;; -dnl no) GhcBuild_m='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-m=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-n, -dnl [--enable-user-way-n build for \`user way n' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_n='YES' -dnl ;; -dnl no) GhcBuild_n='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-n=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-o, -dnl [--enable-user-way-o build for \`user way o' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_o='YES' -dnl ;; -dnl no) GhcBuild_o='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-o=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-A, -dnl [--enable-user-way-A build for \`user way A' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_A='YES' -dnl ;; -dnl no) GhcBuild_A='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-A=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -dnl AC_ARG_ENABLE(user-way-B, -dnl [--enable-user-way-B build for \`user way B' (mostly for implementors)], -dnl [case "$enableval" in -dnl yes) GhcBuild_B='YES' -dnl ;; -dnl no) GhcBuild_B='NO' -dnl ;; -dnl *) echo "I don't understand this option: --enable-user-way-B=$enableval" -dnl exit 1 -dnl ;; -dnl esac]) -dnl -AC_SUBST(GhcBuild_normal) -AC_SUBST(GhcBuild_p) -AC_SUBST(GhcBuild_t) -AC_SUBST(GhcBuild_u) -AC_SUBST(GhcBuild_mc) -AC_SUBST(GhcBuild_mr) -AC_SUBST(GhcBuild_mt) -AC_SUBST(GhcBuild_mp) -AC_SUBST(GhcBuild_mg) -AC_SUBST(GhcBuild_2s) -AC_SUBST(GhcBuild_1s) -AC_SUBST(GhcBuild_du) +AC_ARG_ENABLE(user-way-a, + [--enable-user-way-a build for \`user way a' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_a='YES' + ;; + no) GhcBuild_a='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-a=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-b, + [--enable-user-way-b build for \`user way b' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_b='YES' + ;; + no) GhcBuild_b='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-b=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-c, + [--enable-user-way-c build for \`user way c' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_c='YES' + ;; + no) GhcBuild_c='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-c=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-d, + [--enable-user-way-d build for \`user way d' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_d='YES' + ;; + no) GhcBuild_d='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-d=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-e, + [--enable-user-way-e build for \`user way e' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_e='YES' + ;; + no) GhcBuild_e='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-e=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-f, + [--enable-user-way-f build for \`user way f' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_f='YES' + ;; + no) GhcBuild_f='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-f=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-g, + [--enable-user-way-g build for \`user way g' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_g='YES' + ;; + no) GhcBuild_g='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-g=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-h, + [--enable-user-way-h build for \`user way h' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_h='YES' + ;; + no) GhcBuild_h='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-h=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-i, + [--enable-user-way-i build for \`user way i' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_i='YES' + ;; + no) GhcBuild_i='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-i=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-j, + [--enable-user-way-j build for \`user way j' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_j='YES' + ;; + no) GhcBuild_j='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-j=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-k, + [--enable-user-way-k build for \`user way k' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_k='YES' + ;; + no) GhcBuild_k='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-k=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-l, + [--enable-user-way-l build for \`user way l' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_l='YES' + ;; + no) GhcBuild_l='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-l=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-m, + [--enable-user-way-m build for \`user way m' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_m='YES' + ;; + no) GhcBuild_m='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-m=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-n, + [--enable-user-way-n build for \`user way n' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_n='YES' + ;; + no) GhcBuild_n='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-n=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-o, + [--enable-user-way-o build for \`user way o' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_o='YES' + ;; + no) GhcBuild_o='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-o=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-A, + [--enable-user-way-A build for \`user way A' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_A='YES' + ;; + no) GhcBuild_A='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-A=$enableval" + exit 1 + ;; + esac]) + +AC_ARG_ENABLE(user-way-B, + [--enable-user-way-B build for \`user way B' (mostly for implementors)], + [case "$enableval" in + yes) GhcBuild_B='YES' + ;; + no) GhcBuild_B='NO' + ;; + *) echo "I don't understand this option: --enable-user-way-B=$enableval" + exit 1 + ;; + esac]) + +dnl We do not use AC_SUBST to communicate the GhcBuild_* info, +dnl as some seds (notably OSF) only allow 99 commands (!!!). +dnl We will do the equivalent by a HACK further down. + +dnl AC_SUBST(GhcBuild_normal) +dnl AC_SUBST(GhcBuild_p) +dnl AC_SUBST(GhcBuild_t) +dnl AC_SUBST(GhcBuild_u) +dnl AC_SUBST(GhcBuild_mc) +dnl AC_SUBST(GhcBuild_mr) +dnl AC_SUBST(GhcBuild_mt) +dnl AC_SUBST(GhcBuild_mp) +dnl AC_SUBST(GhcBuild_mg) +dnl AC_SUBST(GhcBuild_2s) +dnl AC_SUBST(GhcBuild_1s) +dnl AC_SUBST(GhcBuild_du) dnl AC_SUBST(GhcBuild_a) dnl AC_SUBST(GhcBuild_b) dnl AC_SUBST(GhcBuild_c) @@ -1291,7 +1307,7 @@ dnl ** which Haskell compiler to bootstrap GHC with? # first, the defaults... WithGhcHc='haskell-compiler-unspecified' WithGhcHcType='HC_UNSPECIFIED' -GhcBuilderVersion='26' +GhcBuilderVersion='28' AC_ARG_WITH(hc-for-ghc, [ @@ -1534,9 +1550,100 @@ AC_ARG_ENABLE(ghci, esac]) AC_SUBST(BuildGHCI) +# Here, by HACK means, we dump all the GhcBuild_ info +# into a file. See comment above. +rm -f ghc/mkworld/buildinfo.jm +echo creating ghc/mkworld/buildinfo.jm +cat > ghc/mkworld/buildinfo.jm <> ghc/mkworld/buildinfo.jm + echo "#define GhcBuild_$xx $yy" >> ghc/mkworld/buildinfo.jm + echo "#endif" >> ghc/mkworld/buildinfo.jm +done + # here ends a very big if DoingGHC = 'ghc' ... fi +# ------------------------------------------------------------------------- +dnl +dnl * `HsLibs' CONFIGURATION STUFF + +if test "xxx$DoingHsLibs" = 'xxxhslibs' ; then +# a very big "if"! + +dnl ** which Haskell compiler to use on hslibs? +WithHsLibsHc='haskell-compiler-unspecified' +WithHsLibsHcType='HC_UNSPECIFIED' + +AC_ARG_WITH(hc-for-hslibs, + [ +******************************************************************* +** \`HsLibs' HASKELL LIBRARIES OPTIONS: + +The Haskell compiler to compile the Haskell Libraries suite; this +option, if used, overrides --with-hc=<...>: + + --with-hc-for-hslibs= + ghc* => Glasgow Haskell invoked by the name given + and you want to use it un-installed ("in-place").], + [case "$withval" in + ghc* | glhc* ) + WithHsLibsHc=$withval + ;; + in-place ) + WithHsLibsHc='IN-PLACE' + ;; + *) echo "I don't understand this option: --with-hc-for-hslibs=$withval" + exit 1 + ;; + esac]) + +# make sure that what they said makes sense.... set WithHsLibsHcType +case $WithHsLibsHc in + haskell-compiler-unspecified ) # maybe they said something earlier... + if test $WithHc = 'haskell-compiler-unspecified' ; then + echo "Neither --with-hc nor --with-hc-for-hslibs was properly set" + exit 1 + fi + ;; + ghc* | glhc* ) + WithHsLibsHcType='HC_GLASGOW_GHC' + AC_CHECK_PROG(have_ghc_hslibs,$WithHsLibsHc,$ac_dir/$ac_word) + if test -z "$have_ghc_hslibs"; then + echo "Can't find Glasgow Haskell to compile HsLibs with: $WithHsLibsHc" + exit 1 + fi + ;; + IN-PLACE) WithHsLibsHcType='HC_GLASGOW_GHC' + ;; +esac +AC_SUBST(WithHsLibsHc) +AC_SUBST(WithHsLibsHcType) + +# Here, by HACK means, we dump all the GhcBuild_ info +# into a file. See comment above. +rm -f hslibs/mkworld/buildinfo.jm +echo creating hslibs/mkworld/buildinfo.jm +cat > hslibs/mkworld/buildinfo.jm <> ghc/mkworld/buildinfo.jm +dnl echo "#define GhcBuild_$xx $yy" >> ghc/mkworld/buildinfo.jm +dnl echo "#endif" >> ghc/mkworld/buildinfo.jm +dnl done + +# here ends a very big if DoingHsLibs = 'hslibs' ... +fi # # ------------------------------------------------------------------------- dnl @@ -1816,8 +1923,7 @@ fi IncludeRealNoFibTests='YES' # defaults IncludeSpectralNoFibTests='YES' IncludeImaginaryNoFibTests='YES' -IncludePENDINGNoFibTests='NO' -IncludeUNUSEDNoFibTests='NO' +IncludeSpecialiseNoFibTests='NO' IncludeGHC_ONLYNoFibTests='NO' IncludePRIVATENoFibTests='NO' IncludeParallelNoFibTests='NO' @@ -1830,15 +1936,13 @@ only if using GHC): --enable-all-tests do *all* tests], [case "$enableval" in - yes) IncludePENDINGNoFibTests='YES' - IncludeUNUSEDNoFibTests='YES' - IncludeGHC_ONLYNoFibTests='YES' + yes) IncludeGHC_ONLYNoFibTests='YES' + IncludeSpecialiseNoFibTests='YES' IncludePRIVATENoFibTests='YES' IncludeParallelNoFibTests='YES' ;; - no) IncludePENDINGNoFibTests='NO' - IncludeUNUSEDNoFibTests='NO' - IncludeGHC_ONLYNoFibTests='NO' + no) IncludeGHC_ONLYNoFibTests='NO' + IncludeSpecialiseNoFibTests='NO' IncludePRIVATENoFibTests='NO' IncludeParallelNoFibTests='NO' @@ -1892,38 +1996,26 @@ AC_ARG_ENABLE(real-tests, ;; esac]) -AC_ARG_ENABLE(PENDING-tests, - [--enable-PENDING-tests include PENDING tests], - [case "$enableval" in - yes) IncludePENDINGNoFibTests='YES' - ;; - no) IncludePENDINGNoFibTests='NO' - ;; - *) echo "I don't understand this option: --enable-PENDING-tests=$enableval" - exit 1 - ;; - esac]) - -AC_ARG_ENABLE(UNUSED-tests, - [--enable-UNUSED-tests include UNUSED tests], +AC_ARG_ENABLE(GHC-ONLY-tests, + [--enable-GHC-ONLY-tests include GHC_ONLY tests], [case "$enableval" in - yes) IncludeUNUSEDNoFibTests='YES' + yes) IncludeGHC_ONLYNoFibTests='YES' ;; - no) IncludeUNUSEDNoFibTests='NO' + no) IncludeGHC_ONLYNoFibTests='NO' ;; - *) echo "I don't understand this option: --enable-UNUSED-tests=$enableval" + *) echo "I don't understand this option: --enable-GHC-ONLY-tests=$enableval" exit 1 ;; esac]) -AC_ARG_ENABLE(GHC-ONLY-tests, - [--enable-GHC-ONLY-tests include GHC_ONLY tests], +AC_ARG_ENABLE(specialise-tests, + [--enable-specialise-tests include specialisation tests], [case "$enableval" in - yes) IncludeGHC_ONLYNoFibTests='YES' + yes) IncludeSpecialiseNoFibTests='YES' ;; - no) IncludeGHC_ONLYNoFibTests='NO' + no) IncludeSpecialiseNoFibTests='NO' ;; - *) echo "I don't understand this option: --enable-GHC-ONLY-tests=$enableval" + *) echo "I don't understand this option: --enable-specialise-tests=$enableval" exit 1 ;; esac]) @@ -1953,15 +2045,31 @@ AC_ARG_ENABLE(parallel-tests, ;; esac]) -AC_SUBST(IncludeRealNoFibTests) -AC_SUBST(IncludeSpectralNoFibTests) -AC_SUBST(IncludeImaginaryNoFibTests) -AC_SUBST(IncludePENDINGNoFibTests) -AC_SUBST(IncludeUNUSEDNoFibTests) -AC_SUBST(IncludeGHC_ONLYNoFibTests) -AC_SUBST(IncludeSpecialiseNoFibTests) -AC_SUBST(IncludePRIVATENoFibTests) -AC_SUBST(IncludeParallelNoFibTests) +dnl not AC_SUBSTd because of 99-command seds (sigh) +dnl (See what follows instead) +dnl AC_SUBST(IncludeRealNoFibTests) +dnl AC_SUBST(IncludeSpectralNoFibTests) +dnl AC_SUBST(IncludeImaginaryNoFibTests) +dnl AC_SUBST(IncludeGHC_ONLYNoFibTests) +dnl AC_SUBST(IncludeSpecialiseNoFibTests) +dnl AC_SUBST(IncludePRIVATENoFibTests) +dnl AC_SUBST(IncludeParallelNoFibTests) + +# Here, by HACK means, we dump all the Include*NoFibTests info +# into a file. See comment above. +rm -f nofib/mkworld/buildinfo.jm +echo creating nofib/mkworld/buildinfo.jm +cat > nofib/mkworld/buildinfo.jm <> nofib/mkworld/buildinfo.jm + echo "#define Include${xx}NoFibTests $yy" >> nofib/mkworld/buildinfo.jm + echo "#endif" >> nofib/mkworld/buildinfo.jm +done # here ends a very big if DoingNoFib = 'nofib' ... fi @@ -1972,7 +2080,7 @@ dnl * extract non-header files with substitution (end) # AC_SUBST(MkWorldSetup) -AC_OUTPUT(Makefile STARTUP mkworld/site.jm mkworld/platform.h mkworld/config.h $ghc_mkworld_site_ghc_jm $ghc_includes_platform_h $nofib_mkworld_site_nofib_jm) +AC_OUTPUT(Makefile STARTUP mkworld/site.jm mkworld/platform.h mkworld/config.h $ghc_mkworld_site_ghc_jm $ghc_includes_platform_h $hslibs_mkworld_site_hslibs_jm $nofib_mkworld_site_nofib_jm) echo '************************************************' echo '*** NOW DO: sh < STARTUP' diff --git a/ghc/Jmakefile b/ghc/Jmakefile index e2d68ee..f6bae9d 100644 --- a/ghc/Jmakefile +++ b/ghc/Jmakefile @@ -1,7 +1,5 @@ #define IHaveSubdirs -MsubNeededHere( ./glue_TAGS_files ) - /* order in SUBDIRS is not supposed to be important but ... "compiler" must be before "lib", because we use the compiler just built to compile pieces of "lib". @@ -38,10 +36,3 @@ SUBDIRS = includes \ whoami:: @echo using a \`$(BUILDPLATFORM)\' host to build a Haskell compiler to run on a @echo \`$(HOSTPLATFORM)\' host that will generate \`C\' target code - -fulltags : ./glue_TAGS_files - $(RM) ./TAGS - ./glue_TAGS_files `find . -type f -name TAGS -print` - -/* this line makes sure perl gets picked up from the right place */ -MsubProgramScriptTarget(PerlCmd,./glue_TAGS_files,./glue_TAGS_files.prl,,) diff --git a/ghc/Makefile.BOOT b/ghc/Makefile.BOOT index 8d0e797..72b7dbf 100644 --- a/ghc/Makefile.BOOT +++ b/ghc/Makefile.BOOT @@ -40,7 +40,7 @@ JMAKE_CMD = $(NEWTOP)$(JMAKE) -I$(NEWTOP)$(JMAKESRC) $(BOOTSTRAPCFLAGS) -DTopDir Makefile:: $(JMAKE) $(JMAKE): - @(cd $(JMAKESRC); if [ -f Makefile ]; then \ + @(cd $(JMAKESRC) && if [ -f Makefile ]; then \ echo "checking $@ in $(JMAKESRC) first..."; $(MAKE) all; else \ echo "bootstrapping $@ from Makefile.BOOT in $(JMAKESRC) first..."; \ $(MAKE) -f Makefile.BOOT BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS); fi; \ diff --git a/ghc/PATCHLEVEL b/ghc/PATCHLEVEL index 936caf5..916eaba 100644 --- a/ghc/PATCHLEVEL +++ b/ghc/PATCHLEVEL @@ -1 +1,2 @@ -The Glamorous Glasgow Haskell Compiler, version 0.27, patchlevel 0 +The Glamorous Glasgow Haskell Compiler, version 2.01, patchlevel 0 +(for Haskell 1.3) diff --git a/ghc/README b/ghc/README index ccc3edb..ea726df 100644 --- a/ghc/README +++ b/ghc/README @@ -1,6 +1,6 @@ -This is version 0.26 of the Glorious Glasgow Haskell compilation +This is version 2.01 of the Glorious Glasgow Haskell compilation system (GHC). This is a major public release. The top-level file -"ANNOUNCE-0.26" says more. +"ANNOUNCE-0.28" says more. Haskell is "the" standard lazy functional programming language [see SIGPLAN Notices, May 1992]. Some general merits of GHC are given at diff --git a/ghc/docs/Jmakefile b/ghc/docs/Jmakefile index 799f3e0..9e9510c 100644 --- a/ghc/docs/Jmakefile +++ b/ghc/docs/Jmakefile @@ -2,6 +2,7 @@ /* just documents here */ #define NoAllTargetForSubdirs +#define NoDependTargetForSubdirs #define NoRunTestsTargetForSubdirs #define NoInstallTargetForSubdirs #define NoTagTargetForSubdirs diff --git a/ghc/docs/install_guide/installing.lit b/ghc/docs/install_guide/installing.lit index 13df5b5..5cdd189 100644 --- a/ghc/docs/install_guide/installing.lit +++ b/ghc/docs/install_guide/installing.lit @@ -1,5 +1,5 @@ % -% $Header: /srv/cvs/cvs.haskell.org/fptools/ghc/docs/install_guide/Attic/installing.lit,v 1.1 1996/01/08 20:25:19 partain Exp $ +% $Header: /srv/cvs/cvs.haskell.org/fptools/ghc/docs/install_guide/Attic/installing.lit,v 1.2 1996/06/27 15:57:32 partain Exp $ % \begin{onlystandalone} \documentstyle[11pt,literate]{article} @@ -12,7 +12,7 @@ University of Glasgow\\ Glasgow, Scotland\\ G12 8QQ\\ \\ -Email: glasgow-haskell-\{request,bugs\}\@dcs.glasgow.ac.uk} +Email: glasgow-haskell-\{users,bugs\}-request\@dcs.glasgow.ac.uk} \maketitle \begin{rawlatex} \tableofcontents diff --git a/ghc/docs/release_notes/release.lit b/ghc/docs/release_notes/release.lit index 16e4d24..b98df34 100644 --- a/ghc/docs/release_notes/release.lit +++ b/ghc/docs/release_notes/release.lit @@ -8,7 +8,7 @@ University of Glasgow\\ Glasgow, Scotland\\ G12 8QQ\\ \\ -Email: glasgow-haskell-\{bugs,request\}\@dcs.glasgow.ac.uk} +Email: glasgow-haskell-\{users,bugs\}-request\@dcs.glasgow.ac.uk} \maketitle \begin{rawlatex} \tableofcontents diff --git a/ghc/docs/state_interface/state-interface.verb b/ghc/docs/state_interface/state-interface.verb index 3767205..c51193a 100644 --- a/ghc/docs/state_interface/state-interface.verb +++ b/ghc/docs/state_interface/state-interface.verb @@ -349,8 +349,8 @@ data StateAndFloat# s = StateAndFloat# (State# s) Float# data StateAndDouble# s = StateAndDouble# (State# s) Double# data StateAndAddr# s = StateAndAddr# (State# s) Addr# -data StateAndStablePtr# s a = StateAndStablePtr# (State# s) (StablePtr# a) -data StateAndMallocPtr# s = StateAndMallocPtr# (State# s) MallocPtr# +data StateAndStablePtr# s a = StateAndStablePtr# (State# s) (StablePtr# a) +data StateAndForeignObj# s = StateAndForeignObj# (State# s) ForeignObj# data StateAndSynchVar# s a = StateAndSynchVar# (State# s) (SynchVar# a) data StateAndArray# s elt = StateAndArray# (State# s) (Array# elt) @@ -461,47 +461,68 @@ deRefStablePointer# :: StablePtr# a -> State# _RealWorld -> StateAndPtr _RealWor @ There is also a C procedure @FreeStablePtr@ which frees a stable pointer. -\subsubsection{``Malloc'' pointers} +% +% Rewritten and updated for MallocPtr++ -- 4/96 SOF +% +\subsubsection{Foreign objects} -A ``malloc'' pointer is an ordinary pointer from outside the Haskell world -(i.e., from the C world) where the Haskell world has been told ``Let me +A \tr{ForeignObj} is a reference to an object outside the Haskell +world (i.e., from the C world, or a reference to an object on another +machine completely.), where the Haskell world has been told ``Let me know when you're finished with this ...''. -The ``malloc'' pointer type is just a special @Addr#@ ({\em not} parameterised). +The \tr{ForeignObj} type is just a special @Addr#@ ({\em not} parameterised). @ -type MallocPtr# +type ForeignObj# @ -{\em ToDo: say more about this and how it's used...} -The main point is that when Haskell discards a -value of type @MallocPtr#@, it calls the procedure @FreeMallocPtr@, which -must be provided by the C world. @FreeMallocPtr@ might in turn call -the GHC-provided procedure @FreeStablePtr@, to deallocate a stable pointer. -No other GHC runtime system procedures should be called by @FreeMallocPtr@. +A typical use of \tr{ForeignObj} is in constructing Haskell bindings +to external libraries. A good example is that of writing a binding to +an image-processing library (which was actually the main motivation +for implementing \tr{ForeignObj}'s precursor, \tr{MallocPtr}). The +images manipulated are not stored in the Haskell heap, either because +the library insist on allocating them internally or we (sensibly) +decide to spare the GC from having to heave heavy images around. -(Implementation: a linked list of all @MallocPtr#@s is maintained to allow the -garbage collector to detect when a @MallocPtr#@ becomes garbage.) +@ +data Image = Image ForeignObj# -Like @Array@, @MallocPtr#@s are represented by heap objects. +instance _CCallable Image +@ -{\bf ToDo --- Important:} Ian Poole reports a need for functions to return a list of -CHPs. Should we add a @CHeapPtrArray@ type too? or just -hack something up? +The \tr{ForeignObj#} type is then used to refer to the externally +allocated image, and to acheive some type safety, the Haskell binding +defines the @Image@ data type. So, a value of type \tr{ForeignObj#} is +used to ``box'' up an external reference into a Haskell heap object +that we can then indirectly reference: -The only Haskell operation we might want on @MallocPtr#@s is an -equality test. However, this is easily implemented if desired: @ -> eqCHP x y = (_runST (_ccall_ equal x y) == 1::Int) +createImage :: (Int,Int) -> PrimIO Image +@ + +So far, this looks just like an @Addr#@ type, but \tr{ForeignObj#} +offers a bit more, namely that we can specify a {\em finalisation +routine} to invoke when the \tr{ForeignObj#} is discarded by the +GC. The garbage collector invokes the finalisation routine associated +with the \tr{ForeignObj#}, saying `` Thanks, I'm through with this +now..'' For the image-processing library, the finalisation routine could for +the images free up memory allocated for them. The finalisation routine has +currently to be written in C (the finalisation routine can in turn call on +@FreeStablePtr@ to deallocate a stable pointer.). -C> equal (x, y) -C> { -C> return (x == y ? 1 : 0); -C> } +Associating a finalisation routine with an external object is done by +\tr{makeForeignObj#}: + +@ +makeForeignObj# :: Addr# -- foreign reference + -> Addr# -- pointer to finalisation routine + -> StateAndForeignObj# _RealWorld ForeignObj# @ -The C world must provide a function @FreeCHeapPointer@ which -will be called (with a C Heap pointer as argument) when the garbage -collector releases a CHP. +(Implementation: a linked list of all @ForeignObj#@s is maintained to allow the + garbage collector to detect when a @ForeignObj#@ becomes garbage.) + +Like @Array@, @ForeignObj#@s are represented by heap objects. {\bf ToDo:} Decide whether @FreeCHeapPointer@ is allowed to call on a stable pointer. (I sincerely hope not since we will still be in the @@ -803,14 +824,14 @@ writeCharArray :: Ix ix => _MutableByteArray s ix -> ix -> Char -> _ST s () @ freezeArray :: Ix ix => _MutableArray s ix elt -> _ST s (Array ix elt) -freezeCharArray :: Ix ix => _MutableByteArray s ix -> _ST s (_ByteArray ix Char) +freezeCharArray :: Ix ix => _MutableByteArray s ix -> _ST s (_ByteArray ix) ... @ We have no need on one-function-per-type for unsafe freezing: @ unsafeFreezeArray :: Ix ix => _MutableArray s ix elt -> _ST s (Array ix elt) -unsafeFreezeByteArray :: Ix ix => _MutableByteArray s ix -> _ST s (_ByteArray ix elt) +unsafeFreezeByteArray :: Ix ix => _MutableByteArray s ix -> _ST s (_ByteArray ix) @ Sometimes we want to snaffle the bounds of one of these beasts: @@ -854,11 +875,13 @@ makeStablePointer :: a -> _StablePtr a freeStablePointer :: _StablePtr a -> PrimIO () @ -\subsection{``Malloc'' pointers} +\subsection{Foreign objects} Again, just boxing up. @ -data _MallocPtr = _MallocPtr MallocPtr# +data _ForeignObj = _ForeignObj ForeignObj# + +makeForeignObj :: _Addr -> _Addr -> PrimIO _ForeignObj @ \subsection{C calls} @@ -899,22 +922,22 @@ table summarises (including the standard boxed-primitive types): Boxed Type of transferd Corresp. Which is Type Prim. component C type *probably*... ------ --------------- ------ ------------- -Char Char# StgChar unsigned char -Int Int# StgInt long int -_Word Word# StgWord unsigned long int -_Addr Addr# StgAddr char * -Float Float# StgFloat float -Double Double# StgDouble double - -Array Array# StgArray StgPtr -_ByteArray ByteArray# StgByteArray StgPtr -_MutableArray MutableArray# StgArray StgPtr -_MutableByteArray MutableByteArray# StgByteArray StgPtr +Char Char# StgChar unsigned char +Int Int# StgInt long int +_Word Word# StgWord unsigned long int +_Addr Addr# StgAddr char * +Float Float# StgFloat float +Double Double# StgDouble double + +Array Array# StgArray StgPtr +_ByteArray ByteArray# StgByteArray StgPtr +_MutableArray MutableArray# StgArray StgPtr +_MutableByteArray MutableByteArray# StgByteArray StgPtr _State State# nothing! -_StablePtr StablePtr# StgStablePtr StgPtr -_MallocPtr MallocPtr# StgMallocPtr StgPtr +_StablePtr StablePtr# StgStablePtr StgPtr +_ForeignObj ForeignObj# StgForeignObj StgPtr @ All of the above are {\em C-returnable} except: @@ -959,8 +982,10 @@ are stored on the heap. ... details omitted ... -More importantly, it must construct a C Heap Pointer heap-object after -a @_ccall_@ which returns a @MallocPtr#@. +% +%More importantly, it must construct a C Heap Pointer heap-object after +%a @_ccall_@ which returns a @MallocPtr#@. +% %-------------------------------------------------------- \section{Non-primitive stuff that must be wired into GHC} @@ -977,7 +1002,7 @@ data Integer = J# Int# Int# ByteArray# -- and the other boxed-primitive types: Array, _ByteArray, _MutableArray, _MutableByteArray, - _StablePtr, _MallocPtr + _StablePtr, _ForeignObj data Bool = False | True data CMP_TAG# = LT# | EQ# | GT# -- used in derived comparisons diff --git a/ghc/docs/users_guide/gone_wrong.lit b/ghc/docs/users_guide/gone_wrong.lit index 4403d20..960d3b7 100644 --- a/ghc/docs/users_guide/gone_wrong.lit +++ b/ghc/docs/users_guide/gone_wrong.lit @@ -52,7 +52,7 @@ This is a bug just as surely as a ``panic.'' Please report it. \item[``Some confusion about a value specialised to a type...'' Huh???] (A deeply obscure and unfriendly error message.) -This message crops up when the typechecker is sees a reference in an +This message crops up when the typechecker sees a reference in an interface pragma to a specialisation of an overloaded value (function); for example, \tr{elem} specialised for type \tr{[Char]} (\tr{String}). The problem is: it doesn't {\em know} that such a diff --git a/ghc/docs/users_guide/prof-compiler-options.lit b/ghc/docs/users_guide/prof-compiler-options.lit index 21d8ca6..0f870b4 100644 --- a/ghc/docs/users_guide/prof-compiler-options.lit +++ b/ghc/docs/users_guide/prof-compiler-options.lit @@ -53,6 +53,12 @@ declared in the module. If no group is specified it defaults to the module name. \end{description} +In addition to the \tr{-prof} option your system might be setup to +enable you to compile and link with the \tr{-prof-details} +\index{\tr{-prof-details option}} option instead. This enables +additional detailed counts to be reported with the \tr{-P} RTS option. +%-prof-details should also enable age profiling if we get it going again ... + %Alternative profiling semantics have also been implemented. To use %these the runtime system and prelude libraries must have been built %for the alternative profiling setup. This is done using a particular diff --git a/ghc/docs/users_guide/prof-output.lit b/ghc/docs/users_guide/prof-output.lit index a246b38..868c98c 100644 --- a/ghc/docs/users_guide/prof-output.lit +++ b/ghc/docs/users_guide/prof-output.lit @@ -3,7 +3,7 @@ % When you run your profiled program with the \tr{-p} RTS option -\index{\tr{-p RTS option (profiling)}, you get the following +\index{\tr{-p RTS option (profiling)}}, you get the following information about your ``cost centres'': \begin{description} @@ -19,12 +19,6 @@ different modules. How many times this cost-centre was entered; think of it as ``I got to the \tr{_scc_} construct this many times...'' %------------------------------------------------------------- -\item[\tr{subcc}:] -How many times this cost-centre ``passed control'' to another -cost-centre; for example, \tr{scc=4} plus \tr{subscc=8} means -``This \tr{_scc_} was entered four times, but went out to -other \tr{_scc_s} eight times.'' -%------------------------------------------------------------- \item[\tr{%time}:] What part of the time was spent in this cost-centre (see also ``ticks,'' below). @@ -32,18 +26,43 @@ below). \item[\tr{%alloc}:] What part of the memory allocation was done in this cost-centre (see also ``bytes,'' below). +%------------------------------------------------------------- +\item[\tr{inner}:] +How many times this cost-centre ``passed control'' to an inner +cost-centre; for example, \tr{scc=4} plus \tr{subscc=8} means +``This \tr{_scc_} was entered four times, but went out to +other \tr{_scc_s} eight times.'' +%------------------------------------------------------------- +\item[\tr{cafs}:] +How many CAFs this cost centre evaluated. +%------------------------------------------------------------- +\item[\tr{dicts}:] +How many dictionaries this cost centre evaluated. +\end{description} + +In addition you can use the \tr{-P} RTS option \index{\tr{-P RTS + option (profiling)}} to get the following additional information: +\begin{description} +%------------------------------------------------------------- +\item[\tr{ticks}:] The raw number of time ``ticks'' which were +attributed to this cost-centre; from this, we get the \tr{%time} +figure mentioned above. +%------------------------------------------------------------- +\item[\tr{bytes}:] Number of bytes allocated in the heap while in +this cost-centre; again, this is the raw number from which we +get the \tr{%alloc} figure mentioned above. \end{description} -If you use the \tr{-P} RTS option -\index{\tr{-P RTS option (profiling)}, you will also get the -following information: +Finally if you built your program with \tr{-prof-details} +\index{\tr{-prof-details option}} the \tr{-P} RTS option will also +produce the following information: \begin{description} %------------------------------------------------------------- -\item[\tr{cafcc}:] Two columns, analogous to the \tr{scc} and \tr{subcc} -columns, except these are for CAF cost-centres: the first column -is how many times this top-level CAF cost-centre was entered; -the second column is how many times this cost-centre (CAF or otherwise) -entered another CAF cost-centre. +\item[\tr{closures}:] +How many heap objects were allocated; these objects may be of varying +size. If you divide the number of bytes (mentioned below) by this +number of ``closures'', then you will get the average object size. +(Not too interesting, but still...) %------------------------------------------------------------- \item[\tr{thunks}:] How many times we entered (evaluated) a thunk---an unevaluated @@ -60,18 +79,4 @@ How many times we entered (evaluated) a partial application (PAP), i.e., a function applied to fewer arguments than it needs. For example, \tr{Int} addition applied to one argument would be a PAP. A PAP is really just a particular form for a function. -%------------------------------------------------------------- -\item[\tr{closures}:] -How many heap objects were allocated; these objects may be of varying -size. If you divide the number of bytes (mentioned below) by this -number of ``closures'', then you will get the average object size. -(Not too interesting, but still...) -%------------------------------------------------------------- -\item[\tr{ticks}:] The raw number of time ``ticks'' which were -attributed to this cost-centre; from this, we get the \tr{%time} -figure mentioned above. -%------------------------------------------------------------- -\item[\tr{bytes}:] Number of bytes allocated in the heap while in -this cost-centre; again, this is the raw number from which we -get the \tr{%alloc} figure mentioned above. \end{description} diff --git a/ghc/docs/users_guide/prof-rts-options.lit b/ghc/docs/users_guide/prof-rts-options.lit index 022d4e3..12325d5 100644 --- a/ghc/docs/users_guide/prof-rts-options.lit +++ b/ghc/docs/users_guide/prof-rts-options.lit @@ -64,10 +64,10 @@ The heap space profile may be broken down by different criteria: \item[\tr{-hG}:] cost centre group which produced the closure. \item[\tr{-hD}:] closure description --- a string describing the closure. \item[\tr{-hY}:] closure type --- a string describing the closure's type. -\item[\tr{-hT,}:] the time interval the closure was -created. \tr{} specifies the no. of interval bands plotted -(default 18) and \tr{} the number of seconds after which the -reported intervals start (default 0.0). +%\item[\tr{-hT,}:] the time interval the closure was +%created. \tr{} specifies the no. of interval bands plotted +%(default 18) and \tr{} the number of seconds after which the +%reported intervals start (default 0.0). \end{description} By default all live closures in the heap are profiled, but particular closures of interest can be selected (see below). @@ -107,14 +107,14 @@ Selects closures which are of one of the specified closure kinds. Valid closure kinds are \tr{CON} (constructor), \tr{FN} (manifest function), \tr{PAP} (partial application), \tr{BH} (black hole) and \tr{THK} (thunk). -\item[\tr{-a}:] -\index{-a RTS option (profiling)} -Selects closures which have survived \pl{} complete intervals. +%\item[\tr{-a}:] +%\index{-a RTS option (profiling)} +%Selects closures which have survived \pl{} complete intervals. \end{description} The space occupied by a closure will be reported in the heap profile if the closure satisfies the following logical expression: \begin{display} -([-c] or [-m] or [-g]) and ([-d] or [-y] or [-k]) and [-a] +([-c] or [-m] or [-g]) and ([-d] or [-y] or [-k]) %and [-a] \end{display} where a particular option is true if the closure (or its attached cost centre) is selected by the option (or the option is not specified). diff --git a/ghc/docs/users_guide/profiling.lit b/ghc/docs/users_guide/profiling.lit index 68d4a7e..9f55739 100644 --- a/ghc/docs/users_guide/profiling.lit +++ b/ghc/docs/users_guide/profiling.lit @@ -8,7 +8,7 @@ University of Glasgow\\ Glasgow, Scotland\\ G12 8QQ\\ \\ -Email: glasgow-haskell-\{bugs,request\}\@dcs.glasgow.ac.uk} +Email: glasgow-haskell-\{users,bugs\}-request\@dcs.glasgow.ac.uk} \maketitle \begin{rawlatex} \tableofcontents diff --git a/ghc/docs/users_guide/user.lit b/ghc/docs/users_guide/user.lit index 51f63e2..858a12b 100644 --- a/ghc/docs/users_guide/user.lit +++ b/ghc/docs/users_guide/user.lit @@ -8,7 +8,7 @@ University of Glasgow\\ Glasgow, Scotland\\ G12 8QQ\\ \\ -Email: glasgow-haskell-\{bugs,request\}\@dcs.glasgow.ac.uk} +Email: glasgow-haskell-\{bugs,users\}-request\@dcs.glasgow.ac.uk} \maketitle \begin{rawlatex} \tableofcontents diff --git a/ghc/docs/users_guide/utils.lit b/ghc/docs/users_guide/utils.lit index d007621..6ec326e 100644 --- a/ghc/docs/users_guide/utils.lit +++ b/ghc/docs/users_guide/utils.lit @@ -27,7 +27,9 @@ HCFLAGS = -fhaskell-1.3 -cpp -hi-diffs $(EXTRA_HC_OPTS) SRCS = Main.lhs Foo.lhs Bar.lhs OBJS = Main.o Foo.o Bar.o -.SUFFIXES : .o .lhs +.SUFFIXES : .o .hi .lhs +.o.hi: + @: .lhs.o: $(RM) $@ $(HC) -c $< $(HCFLAGS) @@ -37,6 +39,14 @@ cool_pgm : $(OBJS) $(HC) -o $@ $(HCFLAGS) $(OBJS) \end{verbatim} +Note the cheesy \tr{.o.hi} rule: It records the dependency of the +interface (\tr{.hi}) file on the source. The rule says a \tr{.hi} +file can be made from a \tr{.o} file by doing... nothing. Which is +true. + +(Sophisticated \tr{make} variants may achieve some of the above more +elegantly. What we've shown should work with any \tr{make}.) + The only thing lacking in the above \tr{Makefile} is interface-file dependencies. If \tr{Foo.lhs} imports module \tr{Bar} and the \tr{Bar} interface changes, then \tr{Foo.lhs} needs to be recompiled. @@ -64,6 +74,9 @@ effect. However, a \tr{make} run that does nothing {\em does} mean mutually-recursive modules but, again, it may take multiple iterations to ``settle.'' +To see \tr{mkdependHS}'s command-line flags, give it a duff flag, +e.g., \tr{mkdependHS -help}. + %************************************************************************ %* * \subsection[hstags]{Emacs `TAGS' for Haskell: \tr{hstags}} diff --git a/ghc/docs/users_guide/vs_haskell.lit b/ghc/docs/users_guide/vs_haskell.lit index c4fc5e5..912e2df 100644 --- a/ghc/docs/users_guide/vs_haskell.lit +++ b/ghc/docs/users_guide/vs_haskell.lit @@ -362,13 +362,13 @@ Here is our ``crib sheet'' for converting 1.2 I/O to 1.3. In most cases, it's really easy. \begin{enumerate} \item -Change \tr{readChan stdin} to \tr{hGetContents stdin}. +Change \tr{readChan stdin} to \tr{getContents}. \item Change \tr{appendChan stdout} to \tr{putStr}, which is equivalent to \tr{hPutStr stdout}. Change \tr{appendChan stderr} to \tr{hPutStr stderr}. \item -You need to \tr{import LibSystem} if you used @getArgs@, @getEnv@, +You need to \tr{import System} if you used @getArgs@, @getEnv@, or @getProgName@. \item Assuming continuation-style @Dialogue@ code, change \tr{... exit done $} @@ -378,6 +378,36 @@ If you had any functions named \tr{(>>)}, \tr{(>>=)}, or \tr{return}, change them to something else. \end{enumerate} +Also: +1.3 I/O all the way. +\tr{Dialogue} usually turns into \tr{IO ()}. +Use of \tr{StatusFile} request: rewrite (no equivalent exists). +Add \tr{import Ratio} if you use \tr{Rationals} at all. +Ditto: \tr{import Complex} if you use complex numbers. +Ditto: \tr{import Array} if you use arrays. Also: note that +Arrays now use ordinary pairs, rather than a separate \tr{Assoc} type. +May be easier to do: +infix 1 =: +(=:) a b = (a,b) +and switch := to =: +This can happen: \tr{LiteralInt.leStringToInt}; add spaces. +For \tr{minInt}/\tr{maxInt}, \tr{minChar}/\tr{maxChar} (???) +use the \tr{Bounded} class methods, \tr{minBound} and \tr{maxBound}. +Replace class \tr{Text} with \tr{Show}; on rare occasions, +you may need to do something for \tr{Read}, too. +The functions \tr{ord} and \tr{chr} have been replaced by +the class methods \tr{fromEnum} and \tr{toEnum}, respectively. +The changes, however, can lead to ambiguous overloading. +Need \tr{import IO} for anything interesting. +What was called \tr{handle} is now called \tr{catch}. +New keyword: \tr{do}. +Other clashes: e.g., \tr{seq}, \tr{fail}. +\tr{readDec} no longer exists; use ???. +Type of \tr{fail} changed? +\tr{(a `op` b) c = ...} is bogus. +`failWith x' now `fail x' +`fail x' now `fail (userError x)' + %************************************************************************ %* * \subsection[nonio-1-3]{Non-I/O things from the 1.3-DRAFT proposal} @@ -444,10 +474,10 @@ The error type is called \tr{IOError13}, rather than \tr{IOError} so...) You probably shouldn't be messing with \tr{IOError} much, anyway. -Some of the 1.3 I/O code, notably the Extremely Cool \tr{LibPosix} +Some of the 1.3 I/O code, notably the Extremely Cool \tr{Posix} stuff, is relatively untested. Go for it, but be wary... -\index{LibPosix bugs} -\index{bugs, LibPosix} +\index{Posix library bugs} +\index{bugs, Posix library} %************************************************************************ %* * @@ -470,7 +500,7 @@ required) and put into \tr{Lib*} interfaces (import required). GHC~0.26 still provides the I/O functions via \tr{Prelude.hi} (no import required). Ignore the ``June draft'' pleadings for -\tr{import LibIO}, and you'll be fine. +\tr{import IO}, and you'll be fine. {\em There is no guarantee that the final 1.3 proposal will look anything like the current DRAFT.} It ain't a standard until the fat @@ -557,11 +587,11 @@ with \tr{-fhaskell-1.3}...) To subvert the above process, you need only provide a @mainPrimIO :: PrimIO ()@ of your own -(in a module named \tr{Main}). Do {\em not} use a \tr{-fhaskell-1.3} flag! +(in a module named \tr{GHCmain}). Do {\em not} use a \tr{-fhaskell-1.3} flag! Here's a little example, stolen from Alastair Reid: \begin{verbatim} -module Main ( mainPrimIO ) where +module GHCmain ( mainPrimIO ) where import PreludeGlaST diff --git a/ghc/driver/Jmakefile b/ghc/driver/Jmakefile index 97e9100..5070553 100644 --- a/ghc/driver/Jmakefile +++ b/ghc/driver/Jmakefile @@ -1,29 +1,19 @@ /* stuff to have before we get going */ MsubNeededHere(ghc) -#if BuildDataParallelHaskell == YES -MsubNeededHere(dphc) -#endif -LitStuffNeededHere(depend) +UnlitNeededHere(depend) InfoStuffNeededHere(docs) DYN_LOADABLE_BITS = \ - ghc-asm-sparc.prl \ - ghc-asm-solaris.prl \ - ghc-asm-m68k.prl \ ghc-asm.prl \ - ghc-asm-alpha.prl \ - ghc-asm-hppa.prl \ - ghc-asm-mips.prl \ + ghc-recomp.prl \ + ghc-iface.prl \ ghc-consist.prl \ ghc-split.prl /* Literate-pgmming suffix rules used herein */ -LitSuffixRule(.lprl,.prl) +UnlitSuffixRule(.lprl,.prl) MsubMakefileDependentProgramScriptTarget(PerlCmd,ghc,ghc.prl,/*no flags*/,/*Makefile*/) -#if BuildDataParallelHaskell == YES -MsubMakefileDependentProgramScriptTarget(PerlCmd,dphc,dphc.prl,,/*Makefile*/) -#endif AllTarget( $(DYN_LOADABLE_BITS) ) /* installation is hackish: because we may want to install w/ a diff name */ @@ -36,13 +26,6 @@ install:: $(MV) $(INSTBINDIR_GHC)/ghc-v-temp-name $(INSTBINDIR_GHC)/$(GHC_DRIVER_INST_NAME) $(RM) $(INSTBINDIR_GHC)/ghc-v-temp-name -#if BuildDataParallelHaskell == YES -InstallMsubbedScriptTarget(PerlCmd,dphc-v-temp-name,dphc.prl,$(INSTBINDIR_GHC)) -install:: - $(MV) $(INSTBINDIR_GHC)/dphc-v-temp-name $(INSTBINDIR_GHC)/dphc - $(RM) $(INSTBINDIR_GHC)/dphc-v-temp-name -#endif /* DPH */ - dyn_loadable_bits : $(DYN_LOADABLE_BITS) InstallMultNonExecTargets(dyn_loadable_bits, $(DYN_LOADABLE_BITS), $(INSTLIBDIR_GHC)) @@ -60,5 +43,3 @@ ClearTagsFile() DYN_LOADABLE_LPRLS = $(DYN_LOADABLE_BITS:.prl=.lprl) PerlTagsTarget( ghc.lprl $(DYN_LOADABLE_LPRLS) ) - -LitDocRootTargetWithNamedOutput(driver,lit,driver-standalone) diff --git a/ghc/driver/driver.lit b/ghc/driver/driver.lit deleted file mode 100644 index ca4a876..0000000 --- a/ghc/driver/driver.lit +++ /dev/null @@ -1,33 +0,0 @@ -\begin{onlystandalone} -\documentstyle[11pt,literate,a4wide]{article} -\begin{document} -\title{Driver: @ghc@} -\author{The GRASP team} -\date{January 1993} -\maketitle -\begin{rawlatex} -\tableofcontents -\end{rawlatex} -\end{onlystandalone} - -\begin{onlypartofdoc} -\section[Driver-for-compilation-system]{@ghc@: Driver for the compilation system} -\downsection -\end{onlypartofdoc} - -\input{ghc.lprl} - -\section[Driver-support]{Support code for the @ghc@ driver} -\downsection -\input{ghc-asm.lprl} -\input{ghc-consist.lprl} -\input{ghc-split.lprl} -\upsection - -\begin{onlypartofdoc} -\upsection -\end{onlypartofdoc} -\begin{onlystandalone} -\printindex -\end{document} -\end{onlystandalone} diff --git a/ghc/driver/ghc-asm-alpha.lprl b/ghc/driver/ghc-asm-alpha.lprl deleted file mode 100644 index 23ee45a..0000000 --- a/ghc/driver/ghc-asm-alpha.lprl +++ /dev/null @@ -1,521 +0,0 @@ -%************************************************************************ -%* * -\section[Driver-asm-fiddling]{Fiddling with assembler files (alpha)} -%* * -%************************************************************************ - -Tasks: -\begin{itemize} -\item -Utterly stomp out C functions' prologues and epilogues; i.e., the -stuff to do with the C stack. -\item -Any other required tidying up. -\end{itemize} - -\begin{code} -sub mangle_asm { - local($in_asmf, $out_asmf) = @_; - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # read whole file, divide into "chunks": - # record some info about what we've found... - - @chk = (); # contents of the chunk - $numchks = 0; # number of them - @chkcat = (); # what category of thing in each chunk - @chksymb = (); # what symbol(base) is defined in this chunk - %slowchk = (); # ditto, its regular "slow" entry code - %fastchk = (); # ditto, fast entry code - %closurechk = (); # ditto, the (static) closure - %infochk = (); # given a symbol base, say what chunk its info tbl is in - %vectorchk = (); # ditto, return vector table - %directchk = (); # ditto, direct return code - - $i = 0; - $chkcat[0] = 'misc'; - - while () { -#??? next if /^\.stab.*___stg_split_marker/; -#??? next if /^\.stab.*ghc.*c_ID/; - - next if /^\s*$/; - - if ( /^\s+/ ) { # most common case first -- a simple line! - # duplicated from the bottom - $chk[$i] .= $_; - - } elsif ( /\.\.ng:$/ ) { # Local labels not to be confused with new chunks - $chk[$i] .= $_; - - } elsif ( /^\$C(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'string'; - $chksymb[$i] = $1; - - } elsif ( /^__stg_split_marker(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; - $chksymb[$i] = $1; - - } elsif ( /^([A-Za-z0-9_]+)_info:$/ ) { - $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; - $chksymb[$i] = $symb; - - die "Info table already? $symb; $i\n" if defined($infochk{$symb}); - - $infochk{$symb} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_entry:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; - $chksymb[$i] = $1; - - $slowchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_fast\d+:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; - $chksymb[$i] = $1; - - $fastchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_closure:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; - $chksymb[$i] = $1; - - $closurechk{$1} = $i; - - } elsif ( /^ghc.*c_ID:/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'consist'; - - } elsif ( /^(__gnu_compiled_c|gcc2_compiled\.):/ ) { - ; # toss it - - } elsif ( /^ErrorIO_call_count:/ # HACK!!!! - || /^[A-Za-z0-9_]+\.\d+:$/ - || /^.*_CAT:/ # PROF: _entryname_CAT - || /^CC_.*_struct:/ # PROF: _CC_ccident_struct - || /^.*_done:/ # PROF: _module_done - || /^_module_registered:/ # PROF: _module_registered - ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; - $chksymb[$i] = ''; - - } elsif ( /^(ret_|djn_)/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^vtbl_([A-Za-z0-9_]+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; - $chksymb[$i] = $1; - - $vectorchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)DirectReturn:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; - $chksymb[$i] = $1; - - $directchk{$1} = $i; - - } elsif ( /^[A-Za-z0-9_]+_upd:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^[A-Za-z0-9_]/ ) { - local($thing); - chop($thing = $_); - print STDERR "Funny global thing?: $_" - unless $KNOWN_FUNNY_THING{$thing} - || /^_(PRIn|PRStart).*:/ # pointer reversal GC routines - || /^CC_.*:/ # PROF: _CC_ccident - || /^_reg.*:/; # PROF: _reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } else { # simple line (duplicated at the top) - $chk[$i] .= $_; - } - } - $numchks = $#chk + 1; - -# print STDERR "\nCLOSURES:\n"; -# foreach $s (sort (keys %closurechk)) { -# print STDERR "$s:\t\t",$closurechk{$s},"\n"; -# } -# print STDERR "\nINFOS:\n"; -# foreach $s (sort (keys %infochk)) { -# print STDERR "$s:\t\t",$infochk{$s},"\n"; -# } -# print STDERR "SLOWS:\n"; -# foreach $s (sort (keys %slowchk)) { -# print STDERR "$s:\t\t",$slowchk{$s},"\n"; -# } -# print STDERR "\nFASTS:\n"; -# foreach $s (sort (keys %fastchk)) { -# print STDERR "$s:\t\t",$fastchk{$s},"\n"; -# } - - # the division into chunks is imperfect; - # we throw some things over the fence into the next - # chunk. - # - # also, there are things we would like to know - # about the whole module before we start spitting - # output. - - # NB: we start meddling at chunk 1, not chunk 0 - - # the first ".rdata" is quite magical; as of GCC 2.7.x, it - # spits a ".quad 0" in after the v first ".rdata"; we - # detect this special case (tossing the ".quad 0")! - $magic_rdata_seen = 0; - - for ($i = 1; $i < $numchks; $i++) { - $c = $chk[$i]; # convenience copy - -# print STDERR "\nCHK $i (BEFORE):\n", $c; - - # pin a funny end-thing on (for easier matching): - $c .= 'FUNNY#END#THING'; - - if ( ! $magic_rdata_seen && $c =~ /^\s*\.rdata\n\t\.quad 0\n\t\.align \d\n/ ) { - $c =~ s/^\s*\.rdata\n\t\.quad 0\n\t\.align (\d)\n/\.rdata\n\t\.align $1\n/; - $magic_rdata_seen = 1; - } - - # pick some end-things and move them to the next chunk - - while ( $c =~ /^(\s*\.align\s+\d+\n)FUNNY#END#THING/ - || $c =~ /^(\s*\.(globl|ent)\s+\S+\n)FUNNY#END#THING/ - || $c =~ /^(\s*\#.*\n)FUNNY#END#THING/ - || $c =~ /^(\s*\.(file|loc)\s+\S+\s+\S+\n)FUNNY#END#THING/ - || $c =~ /^(\s*\.text\n|\s*\.r?data\n)FUNNY#END#THING/ ) { - $to_move = $1; - - if ( $to_move =~ /^\s*(\#|\.(file|globl|ent|loc))/ && $i < ($numchks - 1) ) { - $chk[$i + 1] = $to_move . $chk[$i + 1]; - # otherwise they're tossed - } - - $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/; - } - - if ($c =~ /^\t\.ent\s+(\S+)/) { - $ent = $1; - # toss all prologue stuff, except for loading gp, and the ..ng address - if (($p, $r) = split(/^\t\.prologue/, $c)) { -# print STDERR "$ent: prologue:\n$p\nrest:\n$r\n"; - if (($keep, $junk) = split(/\.\.ng:/, $p)) { - $c = $keep . "..ng:\n"; - } else { - print STDERR "malformed code block ($ent)?\n" - } - } - $c .= "\t.frame \$30,0,\$26,0\n\t.prologue" . $r; - } - - $c =~ s/FUNNY#END#THING//; - $chk[$i] = $c; # update w/ convenience copy - -# print STDERR "\nCHK $i (AFTER):\n", $c; - } - - # print out the header stuff first - - $chk[0] =~ s/^(\t\.file.*)"(ghc\d+\.c)"/\1"$ifile_root.hc"/; - print OUTASM $chk[0]; - - # print out all the literal strings second - for ($i = 1; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'string' ) { - print OUTASM "\.rdata\n\t\.align 3\n"; - print OUTASM $chk[$i]; - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - for ($i = 1; $i < $numchks; $i++) { -# print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; - - next if $chkcat[$i] eq 'DONE ALREADY'; - - if ( $chkcat[$i] eq 'misc' ) { - print OUTASM "\.text\n\t\.align 3\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM "\.data\n\t\.align 3\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'consist' ) { - if ( $chk[$i] =~ /\.ascii.*\)(hsc|cc) (.*)\\11"\n\t\.ascii\s+"(.*)\\0"/ ) { - local($consist) = "$1.$2.$3"; - $consist =~ s/,/./g; - $consist =~ s/\//./g; - $consist =~ s/-/_/g; - $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - print OUTASM "\.text\n$consist:\n"; - } else { - print STDERR "Couldn't grok consistency: ", $chk[$i]; - } - - } elsif ( $chkcat[$i] eq 'splitmarker' ) { - # we can just re-constitute this one... - # ignore the final split marker, to save an empty object module - # Use _three_ underscores so that ghc-split doesn't get overly complicated - print OUTASM "___stg_split_marker",$chksymb[$i],":\n"; - - } elsif ( $chkcat[$i] eq 'closure' - || $chkcat[$i] eq 'infotbl' - || $chkcat[$i] eq 'slow' - || $chkcat[$i] eq 'fast' ) { # do them in that order - $symb = $chksymb[$i]; - - # CLOSURE - if ( defined($closurechk{$symb}) ) { - print OUTASM "\.data\n\t\.align 3\n"; - print OUTASM $chk[$closurechk{$symb}]; - $chkcat[$closurechk{$symb}] = 'DONE ALREADY'; - } - - # INFO TABLE - if ( defined($infochk{$symb}) ) { - - print OUTASM "\.text\n\t\.align 3\n"; - print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1); - # entry code will be put here! - - # paranoia - if ( $chk[$infochk{$symb}] =~ /\.quad\s+([A-Za-z0-9_]+_entry)$/ - && $1 ne "${symb}_entry" ) { - print STDERR "!!! entry point???\n",$chk[$infochk{$symb}]; - } - - $chkcat[$infochk{$symb}] = 'DONE ALREADY'; - } - - # STD ENTRY POINT - if ( defined($slowchk{$symb}) ) { - - # teach it to drop through to the fast entry point: - $c = $chk[$slowchk{$symb}]; - if ( defined($fastchk{$symb}) ) { - $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/; - } - - # NB: no very good way to look for "dangling" references - # to fast-entry pt - - print OUTASM "\.text\n\t\.align 3\n"; - print OUTASM $c; - $chkcat[$slowchk{$symb}] = 'DONE ALREADY'; - } - - # FAST ENTRY POINT - if ( defined($fastchk{$symb}) ) { - $c = $chk[$fastchk{$symb}]; - if ( ! defined($slowchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 3\n"; - } - print OUTASM $c; - $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; - } - - } elsif ( $chkcat[$i] eq 'vector' - || $chkcat[$i] eq 'direct' ) { # do them in that order - $symb = $chksymb[$i]; - - # VECTOR TABLE - if ( defined($vectorchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 3\n"; - print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0); - # direct return code will be put here! - $chkcat[$vectorchk{$symb}] = 'DONE ALREADY'; - } - - # DIRECT RETURN - if ( defined($directchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 3\n"; - print OUTASM $chk[$directchk{$symb}]; - $chkcat[$directchk{$symb}] = 'DONE ALREADY'; - } else { - # The commented nop is for the splitter, to ensure - # that no module ends with a label as the very last - # thing. (The linker will adjust the label to point - # to the first code word of the next module linked in, - # even if alignment constraints cause the label to move!) - - print OUTASM "\t# nop\n"; - } - } else { - &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm alpha)\n$chkcat[$i]\n$chk[$i]\n"); - } - } - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -\end{code} - -\begin{code} -sub init_FUNNY_THINGS { - %KNOWN_FUNNY_THING = ( - 'CheckHeapCode:', 1, - 'CommonUnderflow:', 1, - 'Continue:', 1, - 'EnterNodeCode:', 1, - 'ErrorIO_call_count:', 1, - 'ErrorIO_innards:', 1, - 'IndUpdRetDir:', 1, - 'IndUpdRetV0:', 1, - 'IndUpdRetV1:', 1, - 'IndUpdRetV2:', 1, - 'IndUpdRetV3:', 1, - 'IndUpdRetV4:', 1, - 'IndUpdRetV5:', 1, - 'IndUpdRetV6:', 1, - 'IndUpdRetV7:', 1, - 'PrimUnderflow:', 1, - 'StackUnderflowEnterNode:', 1, - 'StdErrorCode:', 1, - 'UnderflowVect0:', 1, - 'UnderflowVect1:', 1, - 'UnderflowVect2:', 1, - 'UnderflowVect3:', 1, - 'UnderflowVect4:', 1, - 'UnderflowVect5:', 1, - 'UnderflowVect6:', 1, - 'UnderflowVect7:', 1, - 'UpdErr:', 1, - 'UpdatePAP:', 1, - 'WorldStateToken:', 1, - '_Enter_Internal:', 1, - '_PRMarking_MarkNextAStack:', 1, - '_PRMarking_MarkNextBStack:', 1, - '_PRMarking_MarkNextCAF:', 1, - '_PRMarking_MarkNextGA:', 1, - '_PRMarking_MarkNextRoot:', 1, - '_PRMarking_MarkNextSpark:', 1, - '_Scavenge_Forward_Ref:', 1, - '__std_entry_error__:', 1, - '_startMarkWorld:', 1, - 'resumeThread:', 1, - 'startCcRegisteringWorld:', 1, - 'startEnterFloat:', 1, - 'startEnterInt:', 1, - 'startPerformIO:', 1, - 'startStgWorld:', 1, - 'stopPerformIO:', 1 - ); -} -\end{code} - -The following table reversal is used for both info tables and return -vectors. In both cases, we remove the first entry from the table, -reverse the table, put the label at the end, and paste some code -(that which is normally referred to by the first entry in the table) -right after the table itself. (The code pasting is done elsewhere.) - -\begin{code} -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.quad\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+:$/ - || $lines[$i] =~ /^\t\.globl/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.quad\s+/; $i++) { - push(@words, $lines[$i]); - } - # now throw away the first word (entry code): - shift(@words) if $discard1; - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - # If we have anonymous text (not part of a procedure), the linker - # may complain about missing exception information. Bleh. - if ($label =~ /^([A-Za-z0-9_]+):$/) { - $before = "\t.ent $1\n" . $before; - $after .= "\t.end $1\n"; - } - - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} -\end{code} - -%************************************************************************ -%* * -\subsection[Driver-asm-info]{Collect interesting (static) info from an assembler file} -%* * -%************************************************************************ - -How many times is each asm instruction used? - -\begin{code} -%AsmInsn = (); # init - -sub dump_asm_insn_counts { - local($asmf) = @_; - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\t([a-z][a-z0-9]+)\b/ ) { - $AsmInsn{$1} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %AsmInsn)) { - print STDERR "INSN:: $i\t",$AsmInsn{$i},"\n"; - } -} - -sub dump_asm_globals_info { -} - -# make "require"r happy... -1; -\end{code} diff --git a/ghc/driver/ghc-asm-hppa.lprl b/ghc/driver/ghc-asm-hppa.lprl deleted file mode 100644 index 1032a36..0000000 --- a/ghc/driver/ghc-asm-hppa.lprl +++ /dev/null @@ -1,582 +0,0 @@ -%************************************************************************ -%* * -\section[Driver-asm-fiddling]{Fiddling with assembler files (HP-PA)} -%* * -%************************************************************************ - -Tasks: -\begin{itemize} -\item -Utterly stomp out C functions' prologues and epilogues; i.e., the -stuff to do with the C stack. -\item -Any other required tidying up. -\end{itemize} - -HP specific notes: -\begin{itemize} -\item -The HP linker is very picky about symbols being in the appropriate -space (code vs. data). When we mangle the threaded code to put the -info tables just prior to the code, they wind up in code space -rather than data space. This means that references to *_info from -un-mangled parts of the RTS (e.g. unthreaded GC code) get -unresolved symbols. Solution: mini-mangler for .c files on HP. I -think this should really be triggered in the driver by a new -rts -option, so that user code doesn't get mangled inappropriately. -\item -With reversed tables, jumps are to the _info label rather than to -the _entry label. The _info label is just an address in code -space, rather than an entry point with the descriptive blob we -talked about yesterday. As a result, you can't use the call-style -JMP_ macro. However, some JMP_ macros take _info labels as targets -and some take code entry points within the RTS. The latter won't -work with the goto-style JMP_ macro. Sigh. Solution: Use the goto -style JMP_ macro, and mangle some more assembly, changing all -"RP'literal" and "LP'literal" references to "R'literal" and -"L'literal," so that you get the real address of the code, rather -than the descriptive blob. Also change all ".word P%literal" -entries in info tables and vector tables to just ".word literal," -for the same reason. Advantage: No more ridiculous call sequences. -\end{itemize} - -\begin{code} -sub mangle_asm { - local($in_asmf, $out_asmf) = @_; - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # read whole file, divide into "chunks": - # record some info about what we've found... - - @chk = (); # contents of the chunk - $numchks = 0; # number of them - @chkcat = (); # what category of thing in each chunk - @chksymb = (); # what symbol(base) is defined in this chunk - %slowchk = (); # ditto, its regular "slow" entry code - %fastchk = (); # ditto, fast entry code - %closurechk = (); # ditto, the (static) closure - %infochk = (); # ditto, normal info tbl - %vectorchk = (); # ditto, return vector table - %directchk = (); # ditto, direct return code - - $i = 0; - $chkcat[0] = 'misc'; - - while () { -#??? next if /^\.stab.*___stg_split_marker/; -#??? next if /^\.stab.*ghc.*c_ID/; - - next if /^;/; - - if ( /^\s+/ ) { # most common case first -- a simple line! - # duplicated from the bottom - $chk[$i] .= $_; - - } elsif ( /^L\$C(\d+)$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'literal'; - $chksymb[$i] = $1; - - } elsif ( /^__stg_split_marker(\d+)$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; - $chksymb[$i] = $1; - - } elsif ( /^([A-Za-z0-9_]+)_info$/ ) { - $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; - $chksymb[$i] = $symb; - - die "Info table already? $symb; $i\n" if defined($infochk{$symb}); - - $infochk{$symb} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_entry$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; - $chksymb[$i] = $1; - - $slowchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_fast\d+$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; - $chksymb[$i] = $1; - - $fastchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_closure$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; - $chksymb[$i] = $1; - - $closurechk{$1} = $i; - - } elsif ( /^ghc.*c_ID/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'consist'; - - } elsif ( /^(__gnu_compiled_c|gcc2_compiled\.)/ ) { - ; # toss it - - } elsif ( /^ErrorIO_call_count/ # HACK!!!! - || /^[A-Za-z0-9_]+\.\d+$/ - || /^.*_CAT/ # PROF: _entryname_CAT - || /^CC_.*_struct/ # PROF: _CC_ccident_struct - || /^.*_done/ # PROF: _module_done - || /^_module_registered/ # PROF: _module_registered - ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; - $chksymb[$i] = ''; - - } elsif ( /^([A-Za-z0-9_]+)\s+\.comm/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'bss'; - $chksymb[$i] = $1; - - } elsif ( /^(ret_|djn_)/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^vtbl_([A-Za-z0-9_]+)$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; - $chksymb[$i] = $1; - - $vectorchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)DirectReturn$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; - $chksymb[$i] = $1; - - $directchk{$1} = $i; - - } elsif ( /^[A-Za-z0-9_]+_upd$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^[A-Za-z0-9_]/ && ! /^L\$\d+$/) { - local($thing); - chop($thing = $_); - print STDERR "Funny global thing?: $_" - unless $KNOWN_FUNNY_THING{$thing} - || /^_(PRIn|PRStart)/ # pointer reversal GC routines - || /^CC_.*/ # PROF: _CC_ccident - || /^_reg.*/; # PROF: _reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } else { # simple line (duplicated at the top) - $chk[$i] .= $_; - } - } - $numchks = $#chk + 1; - -# print STDERR "\nCLOSURES:\n"; -# foreach $s (sort (keys %closurechk)) { -# print STDERR "$s:\t\t",$closurechk{$s},"\n"; -# } -# print STDERR "\nNORMAL INFOS:\n"; -# foreach $s (sort (keys %infochk)) { -# print STDERR "$s:\t\t",$infochk{$s},"\n"; -# } -# print STDERR "SLOWS:\n"; -# foreach $s (sort (keys %slowchk)) { -# print STDERR "$s:\t\t",$slowchk{$s},"\n"; -# } -# print STDERR "\nFASTS:\n"; -# foreach $s (sort (keys %fastchk)) { -# print STDERR "$s:\t\t",$fastchk{$s},"\n"; -# } - - # the division into chunks is imperfect; - # we throw some things over the fence into the next - # chunk. - # - # also, there are things we would like to know - # about the whole module before we start spitting - # output. - - # NB: we start meddling at chunk 1, not chunk 0 - - for ($i = 1; $i < $numchks; $i++) { - $c = $chk[$i]; # convenience copy - -# print STDERR "\nCHK $i (BEFORE):\n", $c; - - # toss all prologue stuff - $c =~ s/^\s+\.ENTRY[^\0]*--- BEGIN ---/\t.ENTRY/; - - # Lie about our .CALLINFO - $c =~ s/^\s+\.CALLINFO.*$/\t.CALLINFO NO_CALLS,NO_UNWIND/; - - # Get rid of P' - - $c =~ s/LP'/L'/g; - $c =~ s/RP'/R'/g; - -# print STDERR "\nCHK $i (STEP 1):\n", $c; - - # toss all epilogue stuff - $c =~ s/^\s+--- END ---[^\0]*\.EXIT/\t.EXIT/; - -# print STDERR "\nCHK $i (STEP 2):\n", $c; - - # Sorry; we moved the _info stuff to the code segment. - $c =~ s/_info,DATA/_info,CODE/g; - - # pin a funny end-thing on (for easier matching): - $c .= 'FUNNY#END#THING'; - - # pick some end-things and move them to the next chunk - -# print STDERR "\nCHK $i (STEP 3):\n", $c; - while ($c =~ /^(\s+\.(IMPORT|EXPORT|PARAM).*\n)FUNNY#END#THING/ - || $c =~ /^(\s+\.align\s+\d+\n)FUNNY#END#THING/ - || $c =~ /^(\s+\.(SPACE|SUBSPA)\s+\S+\n)FUNNY#END#THING/ - || $c =~ /^(\s*\n)FUNNY#END#THING/ ) { - $to_move = $1; - - if ( $i < ($numchks - 1) && ($to_move =~ /^\s+\.(IMPORT|EXPORT)/ - || ($to_move =~ /align/ && $chkcat[$i+1] eq 'literal')) ) { - $chk[$i + 1] = $to_move . $chk[$i + 1]; - # otherwise they're tossed - } - $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/; - } -# print STDERR "\nCHK $i (STEP 4):\n", $c; - - $c =~ s/FUNNY#END#THING//; - $chk[$i] = $c; # update w/ convenience copy - } - - # print out the header stuff first - - print OUTASM $chk[0]; - - # print out all the literals second - - for ($i = 1; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'literal' ) { - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n"; - print OUTASM $chk[$i]; - print OUTASM "; end literal\n"; # for the splitter - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - # print out all the bss third - - for ($i = 1; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'bss' ) { - print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$BSS\$\n\t.align 4\n"; - print OUTASM $chk[$i]; - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - for ($i = 1; $i < $numchks; $i++) { -# print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; - - next if $chkcat[$i] eq 'DONE ALREADY'; - - if ( $chkcat[$i] eq 'misc' ) { - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'consist' ) { - if ( $chk[$i] =~ /\.STRING.*\)(hsc|cc) (.*)\\x09(.*)\\x00/ ) { - local($consist) = "$1.$2.$3"; - $consist =~ s/,/./g; - $consist =~ s/\//./g; - $consist =~ s/-/_/g; - $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n$consist\n"; - } else { - print STDERR "Couldn't grok consistency: ", $chk[$i]; - } - - } elsif ( $chkcat[$i] eq 'splitmarker' ) { - # we can just re-constitute this one... - # ignore the final split marker, to save an empty object module - # Use _three_ underscores so that ghc-split doesn't get overly complicated - print OUTASM "___stg_split_marker$chksymb[$i]\n"; - - } elsif ( $chkcat[$i] eq 'closure' - || $chkcat[$i] eq 'infotbl' - || $chkcat[$i] eq 'slow' - || $chkcat[$i] eq 'fast' ) { # do them in that order - $symb = $chksymb[$i]; - - # CLOSURE - if ( defined($closurechk{$symb}) ) { - print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n"; - print OUTASM $chk[$closurechk{$symb}]; - $chkcat[$closurechk{$symb}] = 'DONE ALREADY'; - } - - # INFO TABLE - if ( defined($infochk{$symb}) ) { - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; - print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1); - # entry code will be put here! - - # paranoia - if ( $chk[$infochk{$symb}] =~ /\.word\s+([A-Za-z0-9_]+_entry)$/ - && $1 ne "${symb}_entry" ) { - print STDERR "!!! entry point???\n",$chk[$infochk{$symb}]; - } - - $chkcat[$infochk{$symb}] = 'DONE ALREADY'; - } - - # STD ENTRY POINT - if ( defined($slowchk{$symb}) ) { - - # teach it to drop through to the fast entry point: - $c = $chk[$slowchk{$symb}]; - if ( defined($fastchk{$symb}) ) { - $c =~ s/^\s+ldil.*\n\s+ldo.*\n\s+bv.*\n(.*\n)?\s+\.EXIT/$1\t.EXIT/; - } - - # ToDo: ???? any good way to look for "dangling" references - # to fast-entry pt ??? - - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; - print OUTASM $c; - $chkcat[$slowchk{$symb}] = 'DONE ALREADY'; - } - - # FAST ENTRY POINT - if ( defined($fastchk{$symb}) ) { - $c = $chk[$fastchk{$symb}]; - if ( ! defined($slowchk{$symb}) ) { - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; - } - print OUTASM $c; - $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; - } - - } elsif ( $chkcat[$i] eq 'vector' - || $chkcat[$i] eq 'direct' ) { # do them in that order - $symb = $chksymb[$i]; - - # VECTOR TABLE - if ( defined($vectorchk{$symb}) ) { - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; - print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0); - # direct return code will be put here! - $chkcat[$vectorchk{$symb}] = 'DONE ALREADY'; - } - - # DIRECT RETURN - if ( defined($directchk{$symb}) ) { - print OUTASM "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; - print OUTASM $chk[$directchk{$symb}]; - $chkcat[$directchk{$symb}] = 'DONE ALREADY'; - } - } else { - &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm hppa)\n$chkcat[$i]\n$chk[$i]\n"); - } - } - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -\end{code} - -The HP is a major nuisance. The threaded code mangler moved info tables -from data space to code space, but unthreaded code in the RTS still has -references to info tables in data space. Since the HP linker is very precise -about where symbols live, we need to patch the references in the unthreaded -RTS as well. - -\begin{code} - -sub mini_mangle_asm { - local($in_asmf, $out_asmf) = @_; - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - while () { - s/_info,DATA/_info,CODE/; # Move _info references to code space - s/P%_PR/_PR/; - print OUTASM; - } - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} - -\end{code} - -\begin{code} -sub init_FUNNY_THINGS { - %KNOWN_FUNNY_THING = ( - 'CheckHeapCode', 1, - 'CommonUnderflow', 1, - 'Continue', 1, - 'EnterNodeCode', 1, - 'ErrorIO_call_count', 1, - 'ErrorIO_innards', 1, - 'IndUpdRetDir', 1, - 'IndUpdRetV0', 1, - 'IndUpdRetV1', 1, - 'IndUpdRetV2', 1, - 'IndUpdRetV3', 1, - 'IndUpdRetV4', 1, - 'IndUpdRetV5', 1, - 'IndUpdRetV6', 1, - 'IndUpdRetV7', 1, - 'PrimUnderflow', 1, - 'StackUnderflowEnterNode', 1, - 'StdErrorCode', 1, - 'UnderflowVect0', 1, - 'UnderflowVect1', 1, - 'UnderflowVect2', 1, - 'UnderflowVect3', 1, - 'UnderflowVect4', 1, - 'UnderflowVect5', 1, - 'UnderflowVect6', 1, - 'UnderflowVect7', 1, - 'UpdErr', 1, - 'UpdatePAP', 1, - 'WorldStateToken', 1, - '_Enter_Internal', 1, - '_PRMarking_MarkNextAStack', 1, - '_PRMarking_MarkNextBStack', 1, - '_PRMarking_MarkNextCAF', 1, - '_PRMarking_MarkNextGA', 1, - '_PRMarking_MarkNextRoot', 1, - '_PRMarking_MarkNextSpark', 1, - '_Scavenge_Forward_Ref', 1, - '__std_entry_error__', 1, - '_startMarkWorld', 1, - 'resumeThread', 1, - 'startCcRegisteringWorld', 1, - 'startEnterFloat', 1, - 'startEnterInt', 1, - 'startPerformIO', 1, - 'startStgWorld', 1, - 'stopPerformIO', 1 - ); -} -\end{code} - -The following table reversal is used for both info tables and return -vectors. In both cases, we remove the first entry from the table, -reverse the table, put the label at the end, and paste some code -(that which is normally referred to by the first entry in the table) -right after the table itself. (The code pasting is done elsewhere.) - -\begin{code} -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@imports) = (); - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\s+\.word\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+$/ - || $lines[$i] =~ /^\s+\.EXPORT/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\s+\.(word|IMPORT)/; $i++) { - if ($lines[$i] =~ /^\s+\.IMPORT/) { - push(@imports, $lines[$i]); - } else { - # We don't use HP's ``function pointers'' - # We just use labels in code space, like normal people - $lines[$i] =~ s/P%//; - push(@words, $lines[$i]); - } - } - # now throw away the first word (entry code): - if ($discard1) { - shift(@words); - } - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - $tbl = $before . join("\n", @imports) . "\n" . - join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} -\end{code} - -%************************************************************************ -%* * -\subsection[Driver-asm-info]{Collect interesting (static) info from an assembler file} -%* * -%************************************************************************ - -How many times is each asm instruction used? - -\begin{code} -%AsmInsn = (); # init - -sub dump_asm_insn_counts { - local($asmf) = @_; - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\t([a-z][a-z0-9]+)\b/ ) { - $AsmInsn{$1} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %AsmInsn)) { - print STDERR "INSN:: $i\t",$AsmInsn{$i},"\n"; - } -} - -sub dump_asm_globals_info { -} - -# make "require"r happy... -1; -\end{code} diff --git a/ghc/driver/ghc-asm-m68k.lprl b/ghc/driver/ghc-asm-m68k.lprl deleted file mode 100644 index e3a1431..0000000 --- a/ghc/driver/ghc-asm-m68k.lprl +++ /dev/null @@ -1,486 +0,0 @@ -%************************************************************************ -%* * -\section[Driver-asm-fiddling]{Fiddling with assembler files (m68k)} -%* * -%************************************************************************ - -Tasks: -\begin{itemize} -\item -Utterly stomp out C functions' prologues and epilogues; i.e., the -stuff to do with the C stack. -\item -Any other required tidying up. -\end{itemize} - -\begin{code} -sub mangle_asm { - local($in_asmf, $out_asmf) = @_; - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # read whole file, divide into "chunks": - # record some info about what we've found... - - @chk = (); # contents of the chunk - $numchks = 0; # number of them - @chkcat = (); # what category of thing in each chunk - @chksymb = (); # what symbol(base) is defined in this chunk - %slowchk = (); # ditto, its regular "slow" entry code - %fastchk = (); # ditto, fast entry code - %closurechk = (); # ditto, the (static) closure - %infochk = (); # given a symbol base, say what chunk its info tbl is in - %vectorchk = (); # ditto, return vector table - %directchk = (); # ditto, direct return code - - $i = 0; - $chkcat[0] = 'misc'; - - while () { - next if /^\.stab.*___stg_split_marker/; - next if /^\.stab.*ghc.*c_ID/; - next if /^#(NO_)?APP/; - - if ( /^\s+/ ) { # most common case first -- a simple line! - # duplicated from the bottom - - $chk[$i] .= $_; - - } elsif ( /^LC(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'string'; - $chksymb[$i] = $1; - - } elsif ( /^___stg_split_marker(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; - $chksymb[$i] = $1; - - } elsif ( /^_([A-Za-z0-9_]+)_info:$/ ) { - $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; - $chksymb[$i] = $symb; - - die "Info table already? $symb; $i\n" if defined($infochk{$symb}); - - $infochk{$symb} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)_entry:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; - $chksymb[$i] = $1; - - $slowchk{$1} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)_fast\d+:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; - $chksymb[$i] = $1; - - $fastchk{$1} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)_closure:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; - $chksymb[$i] = $1; - - $closurechk{$1} = $i; - - } elsif ( /^_ghc.*c_ID:/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'consist'; - - } elsif ( /^(___gnu_compiled_c|gcc2_compiled\.):/ ) { - ; # toss it - - } elsif ( /^_ErrorIO_call_count:/ # HACK!!!! - || /^_[A-Za-z0-9_]+\.\d+:$/ - || /^_.*_CAT:/ # PROF: _entryname_CAT - || /^_CC_.*_struct:/ # PROF: _CC_ccident_struct - || /^_.*_done:/ # PROF: _module_done - || /^__module_registered:/ # PROF: _module_registered - ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; - $chksymb[$i] = ''; - - } elsif ( /^_(ret_|djn_)/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^_vtbl_([A-Za-z0-9_]+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; - $chksymb[$i] = $1; - - $vectorchk{$1} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)DirectReturn:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; - $chksymb[$i] = $1; - - $directchk{$1} = $i; - - } elsif ( /^_[A-Za-z0-9_]+_upd:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^_[A-Za-z0-9_]/ ) { - local($thing); - chop($thing = $_); - print STDERR "Funny global thing?: $_" - unless $KNOWN_FUNNY_THING{$thing} - || /^__(PRIn|PRStart).*:/ # pointer reversal GC routines - || /^_CC_.*:/ # PROF: _CC_ccident - || /^__reg.*:/; # PROF: __reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } else { # simple line (duplicated at the top) - - $chk[$i] .= $_; - } - } - $numchks = $#chk + 1; - - # the division into chunks is imperfect; - # we throw some things over the fence into the next - # chunk. - # - # also, there are things we would like to know - # about the whole module before we start spitting - # output. - - # NB: we start meddling at chunk 1, not chunk 0 - - for ($i = 1; $i < $numchks; $i++) { - $c = $chk[$i]; # convenience copy - -# print STDERR "\nCHK $i (BEFORE) (",$chkcat[$i],"):\n", $c; - - # toss all prologue stuff; - # be slightly paranoid to make sure there's - # nothing surprising in there - if ( $c =~ /--- BEGIN ---/ ) { - if (($p, $r) = split(/--- BEGIN ---/, $c)) { - $p =~ s/^\tlink a6,#-?\d.*\n//; - $p =~ s/^\tmovel d2,sp\@-\n//; - $p =~ s/^\tmovel d5,sp\@-\n//; # SMmark.* only? - $p =~ s/^\tmoveml \#0x[0-9a-f]+,sp\@-\n//; # SMmark.* only? - die "Prologue junk?: $p\n" if $p =~ /^\t[^\.]/; - - # glue together what's left - $c = $p . $r; - } - } - - # toss all epilogue stuff; again, paranoidly - if ( $c =~ /--- END ---/ ) { - if (($r, $e) = split(/--- END ---/, $c)) { - $e =~ s/^\tunlk a6\n//; - $e =~ s/^\trts\n//; - die "Epilogue junk?: $e\n" if $e =~ /^\t[^\.]/; - - # glue together what's left - $c = $r . $e; - } - } - - # toss all calls to __DISCARD__ - $c =~ s/^\tjbsr ___DISCARD__\n//g; - - # toss stack adjustment after DoSparks - $c =~ s/^(\tjbsr _DoSparks\n)\taddqw #8,sp/$1/g; - - # pin a funny end-thing on (for easier matching): - $c .= 'FUNNY#END#THING'; - - # pick some end-things and move them to the next chunk - - while ( $c =~ /^\s*(\.align\s+\d+\n|\.proc\s+\d+\n|\.const\n|\.cstring\n|\.globl\s+\S+\n|\.text\n|\.data\n|\.even\n|\.stab[^n].*\n)FUNNY#END#THING/ ) { - $to_move = $1; - - if ( $to_move =~ /\.(globl|proc|stab)/ && $i < ($numchks - 1) ) { - $chk[$i + 1] = $to_move . $chk[$i + 1]; - # otherwise they're tossed - } - - $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/; - } - - $c =~ s/FUNNY#END#THING//; - $chk[$i] = $c; # update w/ convenience copy - } - - # print out all the literal strings first - for ($i = 0; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'string' ) { - print OUTASM "\.text\n\t\.even\n"; - print OUTASM $chk[$i]; - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - for ($i = 0; $i < $numchks; $i++) { -# print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; - - next if $chkcat[$i] eq 'DONE ALREADY'; - - if ( $chkcat[$i] eq 'misc' ) { - print OUTASM "\.text\n\t\.even\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM "\.data\n\t\.even\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'consist' ) { - if ( $chk[$i] =~ /\.ascii.*\)(hsc|cc) (.*)\\11"\n\t\.ascii\s+"(.*)\\0"/ ) { - local($consist) = "$1.$2.$3"; - $consist =~ s/,/./g; - $consist =~ s/\//./g; - $consist =~ s/-/_/g; - $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - print OUTASM "\.text\n$consist:\n"; - } else { - print STDERR "Couldn't grok consistency: ", $chk[$i]; - } - - } elsif ( $chkcat[$i] eq 'splitmarker' ) { - # we can just re-constitute this one... - print OUTASM "___stg_split_marker",$chksymb[$i],":\n"; - - } elsif ( $chkcat[$i] eq 'closure' - || $chkcat[$i] eq 'infotbl' - || $chkcat[$i] eq 'slow' - || $chkcat[$i] eq 'fast' ) { # do them in that order - $symb = $chksymb[$i]; - - # CLOSURE - if ( defined($closurechk{$symb}) ) { - print OUTASM "\.data\n\t\.even\n"; - print OUTASM $chk[$closurechk{$symb}]; - $chkcat[$closurechk{$symb}] = 'DONE ALREADY'; - } - - # INFO TABLE - if ( defined($infochk{$symb}) ) { - - print OUTASM "\.text\n\t\.even\n"; - print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1); - # entry code will be put here! - - # paranoia - if ( $chk[$infochk{$symb}] =~ /\.long\s+([A-Za-z0-9_]+_entry)$/ - && $1 ne "_${symb}_entry" ) { - print STDERR "!!! entry point???\n",$chk[$infochk{$symb}]; - } - - $chkcat[$infochk{$symb}] = 'DONE ALREADY'; - } - - # STD ENTRY POINT - if ( defined($slowchk{$symb}) ) { - - # teach it to drop through to the fast entry point: - $c = $chk[$slowchk{$symb}]; - - if ( defined($fastchk{$symb}) ) { - $c =~ s/^\tjmp _${symb}_fast\d+.*\n\tnop\n//; - $c =~ s/^\tjmp _${symb}_fast\d+.*\n//; - } - - print STDERR "still has jump to fast entry point:\n$c" - if $c =~ /_${symb}_fast/; # NB: paranoia - - print OUTASM "\.text\n\t\.even\n"; - print OUTASM $c; - $chkcat[$slowchk{$symb}] = 'DONE ALREADY'; - } - - # FAST ENTRY POINT - if ( defined($fastchk{$symb}) ) { - print OUTASM "\.text\n\t\.even\n"; - print OUTASM $chk[$fastchk{$symb}]; - $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; - } - - } elsif ( $chkcat[$i] eq 'vector' - || $chkcat[$i] eq 'direct' ) { # do them in that order - $symb = $chksymb[$i]; - - # VECTOR TABLE - if ( defined($vectorchk{$symb}) ) { - print OUTASM "\.text\n\t\.even\n"; - print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0); - # direct return code will be put here! - $chkcat[$vectorchk{$symb}] = 'DONE ALREADY'; - } - - # DIRECT RETURN - if ( defined($directchk{$symb}) ) { - print OUTASM "\.text\n\t\.even\n"; - print OUTASM $chk[$directchk{$symb}]; - $chkcat[$directchk{$symb}] = 'DONE ALREADY'; - } - - } else { - &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm m68k)\n$chkcat[$i]\n$chk[$i]\n"); - } - } - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -\end{code} - -\begin{code} -sub init_FUNNY_THINGS { - %KNOWN_FUNNY_THING = ( - '_CheckHeapCode:', 1, - '_CommonUnderflow:', 1, - '_Continue:', 1, - '_EnterNodeCode:', 1, - '_ErrorIO_call_count:', 1, - '_ErrorIO_innards:', 1, - '_IndUpdRetDir:', 1, - '_IndUpdRetV0:', 1, - '_IndUpdRetV1:', 1, - '_IndUpdRetV2:', 1, - '_IndUpdRetV3:', 1, - '_IndUpdRetV4:', 1, - '_IndUpdRetV5:', 1, - '_IndUpdRetV6:', 1, - '_IndUpdRetV7:', 1, - '_PrimUnderflow:', 1, - '_StackUnderflowEnterNode:', 1, - '_StdErrorCode:', 1, - '_UnderflowVect0:', 1, - '_UnderflowVect1:', 1, - '_UnderflowVect2:', 1, - '_UnderflowVect3:', 1, - '_UnderflowVect4:', 1, - '_UnderflowVect5:', 1, - '_UnderflowVect6:', 1, - '_UnderflowVect7:', 1, - '_UpdErr:', 1, - '_UpdatePAP:', 1, - '_WorldStateToken:', 1, - '__Enter_Internal:', 1, - '__PRMarking_MarkNextAStack:', 1, - '__PRMarking_MarkNextBStack:', 1, - '__PRMarking_MarkNextCAF:', 1, - '__PRMarking_MarkNextGA:', 1, - '__PRMarking_MarkNextRoot:', 1, - '__PRMarking_MarkNextSpark:', 1, - '__Scavenge_Forward_Ref:', 1, - '___std_entry_error__:', 1, - '__startMarkWorld:', 1, - '_resumeThread:', 1, - '_startCcRegisteringWorld:', 1, - '_startEnterFloat:', 1, - '_startEnterInt:', 1, - '_startPerformIO:', 1, - '_startStgWorld:', 1, - '_stopPerformIO:', 1 - ); -} -\end{code} - -The following table reversal is used for both info tables and return -vectors. In both cases, we remove the first entry from the table, -reverse the table, put the label at the end, and paste some code -(that which is normally referred to by the first entry in the table) -right after the table itself. (The code pasting is done elsewhere.) - -\begin{code} -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.long\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+_info:$/ - || $lines[$i] =~ /^\.globl/ - || $lines[$i] =~ /^_vtbl_\S+:$/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.long\s+/; $i++) { - push(@words, $lines[$i]); - } - # now throw away the first word (entry code): - shift(@words) if $discard1; - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} -\end{code} - -%************************************************************************ -%* * -\subsection[Driver-asm-info]{Collect interesting (static) info from an assembler file} -%* * -%************************************************************************ - -How many times is each asm instruction used? - -\begin{code} -%AsmInsn = (); # init - -sub dump_asm_insn_counts { - local($asmf) = @_; - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\t([a-z][a-z0-9]+)\b/ ) { - $AsmInsn{$1} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %AsmInsn)) { - print STDERR "INSN:: $i\t",$AsmInsn{$i},"\n"; - } -} - -sub dump_asm_globals_info { -} - -# make "require"r happy... -1; - -\end{code} diff --git a/ghc/driver/ghc-asm-mips.lprl b/ghc/driver/ghc-asm-mips.lprl deleted file mode 100644 index 3c210cb..0000000 --- a/ghc/driver/ghc-asm-mips.lprl +++ /dev/null @@ -1,529 +0,0 @@ -%************************************************************************ -%* * -\section[Driver-asm-fiddling]{Fiddling with assembler files (SGI MIPS box)} -%* * -%************************************************************************ - -\begin{code} -sub mangle_asm { - local($in_asmf, $out_asmf) = @_; - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # read whole file, divide into "chunks": - # record some info about what we've found... - - @chk = (); # contents of the chunk - $numchks = 0; # number of them - @chkcat = (); # what category of thing in each chunk - @chksymb = (); # what symbol(base) is defined in this chunk - %slowchk = (); # ditto, its regular "slow" entry code - %fastchk = (); # ditto, fast entry code - %closurechk = (); # ditto, the (static) closure - %infochk = (); # given a symbol base, say what chunk its info tbl is in - %vectorchk = (); # ditto, return vector table - %directchk = (); # ditto, direct return code - $EXTERN_DECLS = ''; # .globl .text - - $i = 0; - $chkcat[0] = 'misc'; - - while () { - - next if /^$/; # blank line - next if /^\s*#(NO_)?APP/; - next if /^\t\.file\t/; - next if /^ # /; - - if ( /^\t\.(globl \S+ \.text|comm\t)/ ) { - $EXTERN_DECLS .= $_ unless /(__DISCARD__|\b(PK_|ASSIGN_)(FLT|DBL)\b)/; - - } elsif ( /^\s+/ ) { # most common case first -- a simple line! - # duplicated from the bottom - $chk[$i] .= $_; - - # NB: all the rest start with a non-space - - } elsif ( /^\d+:/ ) { # a funny-looking very-local label - $chk[$i] .= $_; - - } elsif ( /^\$LC(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'string'; - $chksymb[$i] = $1; - - } elsif ( /^__stg_split_marker(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; - $chksymb[$i] = $1; - - } elsif ( /^([A-Za-z0-9_]+)_info:$/ ) { - $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; - $chksymb[$i] = $symb; - - die "Info table already? $symb; $i\n" if defined($infochk{$symb}); - - $infochk{$symb} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_entry:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; - $chksymb[$i] = $1; - - $slowchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_fast\d+:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; - $chksymb[$i] = $1; - - $fastchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_closure:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; - $chksymb[$i] = $1; - - $closurechk{$1} = $i; - - } elsif ( /^ghc.*c_ID:/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'consist'; - - } elsif ( /^(__gnu_compiled_c|gcc2_compiled\.):/ ) { - ; # toss it - - } elsif ( /^ErrorIO_call_count:/ # HACK!!!! - || /^[A-Za-z0-9_]+\.\d+:$/ - || /^.*_CAT:/ # PROF: _entryname_CAT - || /^CC_.*_struct:/ # PROF: _CC_ccident_struct - || /^.*_done:/ # PROF: _module_done - || /^_module_registered:/ # PROF: _module_registered - ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; - $chksymb[$i] = ''; - - } elsif ( /^(ret_|djn_)/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^vtbl_([A-Za-z0-9_]+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; - $chksymb[$i] = $1; - - $vectorchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)DirectReturn:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; - $chksymb[$i] = $1; - - $directchk{$1} = $i; - - } elsif ( /^[A-Za-z0-9_]+_upd:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^[A-Za-z0-9_]/ ) { - local($thing); - chop($thing = $_); - print STDERR "Funny global thing? ($.): $_" - unless $KNOWN_FUNNY_THING{$thing} - || /^_(PRIn|PRStart).*:/ # pointer reversal GC routines - || /^CC_.*:/ # PROF: _CC_ccident - || /^_reg.*:/; # PROF: _reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } else { # simple line (duplicated at the top) - $chk[$i] .= $_; - } - } - $numchks = $#chk + 1; - -# print STDERR "\nCLOSURES:\n"; -# foreach $s (sort (keys %closurechk)) { -# print STDERR "$s:\t\t",$closurechk{$s},"\n"; -# } -# print STDERR "\nINFOS:\n"; -# foreach $s (sort (keys %infochk)) { -# print STDERR "$s:\t\t",$infochk{$s},"\n"; -# } -# print STDERR "SLOWS:\n"; -# foreach $s (sort (keys %slowchk)) { -# print STDERR "$s:\t\t",$slowchk{$s},"\n"; -# } -# print STDERR "\nFASTS:\n"; -# foreach $s (sort (keys %fastchk)) { -# print STDERR "$s:\t\t",$fastchk{$s},"\n"; -# } - - # the division into chunks is imperfect; - # we throw some things over the fence into the next - # chunk. - # - # also, there are things we would like to know - # about the whole module before we start spitting - # output. - - # NB: we start meddling at chunk 1, not chunk 0 - - for ($i = 1; $i < $numchks; $i++) { - $c = $chk[$i]; # convenience copy - -# print STDERR "\nCHK $i (BEFORE):\n", $c; - - # pin a funny end-thing on (for easier matching): - $c .= 'FUNNY#END#THING'; - - # pick some end-things and move them to the next chunk - - while ( $c =~ /^(\s*\.align\s+\d+\n)FUNNY#END#THING/ - || $c =~ /^(\s*\.(globl|ent)\s+\S+\n)FUNNY#END#THING/ - || $c =~ /^(\s*\.text\n|\s*\.r?data\n)FUNNY#END#THING/ ) { - $to_move = $1; - - if ( $to_move =~ /\.(globl|ent)/ && $i < ($numchks - 1) ) { - $chk[$i + 1] = $to_move . $chk[$i + 1]; - # otherwise they're tossed - } - - $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/; - } - - # toss all prologue stuff; - # be slightly paranoid to make sure there's - # nothing surprising in there - if ( $c =~ /--- BEGIN ---/ ) { - if (($p, $r) = split(/--- BEGIN ---/, $c)) { - # the .frame/.mask/.fmask that we use is the same - # as that produced by GCC for miniInterpret; this - # gives GDB some chance of figuring out what happened - $FRAME = "\t.frame\t\$sp,2168,\$31\n\t.mask\t0x90000000,-4\n\t.fmask\t0x00000000,0\n"; - $p =~ s/^\t\.(frame).*\n/__FRAME__/g; - $p =~ s/^\t\.(mask|fmask).*\n//g; - $p =~ s/^\t\.cprestore.*\n/\t\.cprestore 416\n/; # 16 + 100 4-byte args - $p =~ s/^\tsubu\t\$sp,\$sp,\d+\n//; - $p =~ s/^\tsw\t\$31,\d+\(\$sp\)\n//; - $p =~ s/^\tsw\t\$fp,\d+\(\$sp\)\n//; - $p =~ s/^\tsw\t\$28,\d+\(\$sp\)\n//; - $p =~ s/__FRAME__/$FRAME/; - die "Prologue junk?: $p\n" if $p =~ /^\t[^\.]/; - - # glue together what's left - $c = $p . $r; - $c =~ s/\n\t\n/\n/; # junk blank line - } - } - - # toss all epilogue stuff; again, paranoidly; - # first, this basic sequence may occur "--- END ---" or not - $c =~ s/^\tlw\t\$31,\d+\(\$sp\)\n\taddu\t\$sp,\$sp,\d+\n\tj\t\$31\n\t\.end/\t\.end/; - - if ( $c =~ /--- END ---/ ) { - if (($r, $e) = split(/--- END ---/, $c)) { - $e =~ s/^\tlw\t\$31,\d+\(\$sp\)\n//; - $e =~ s/^\tlw\t\$fp,\d+\(\$sp\)\n//; - $e =~ s/^\taddu\t\$sp,\$sp,\d+\n//; - $e =~ s/^\tj\t\$31\n//; - die "Epilogue junk?: $e\n" if $e =~ /^\t[^\.]/; - - # glue together what's left - $c = $r . $e; - $c =~ s/\n\t\n/\n/; # junk blank line - } - } - - # toss all calls to __DISCARD__ - $c =~ s/^\tjal\t__DISCARD__\n//g; - # that may leave some gratuitous asm macros around - # (no harm done; but we get rid of them to be tidier) - $c =~ s/^\t\.set\tnoreorder\n\t\.set\tnomacro\n\taddu\t(\S+)\n\t\.set\tmacro\n\t\.set\treorder\n/\taddu\t$1\n/; - - $c =~ s/FUNNY#END#THING//; - $chk[$i] = $c; # update w/ convenience copy - - print STDERR "NB: Contains magic stuff!\n$c\n" if $c =~ /^\t[^\.].*(\$28)\b/; - -# print STDERR "\nCHK $i (AFTER):\n", $c; - - } - - # print out the header stuff first - $chk[0] = "\t\.file\t1 \"$ifile_root.hc\"\n" . $chk[0]; - - # get rid of horrible "Revision: .*$" strings - local(@lines0) = split(/\n/, $chk[0]); - local($z) = 0; - while ( $z <= $#lines0 ) { - if ( $lines0[$z] =~ /^\t\.byte\t0x24,0x52,0x65,0x76,0x69,0x73,0x69,0x6f$/ ) { - undef($lines0[$z]); - $z++; - while ( $z <= $#lines0 ) { - undef($lines0[$z]); - last if $lines0[$z] =~ /[,\t]0x0$/; - $z++; - } - } - $z++; - } - $chk[0] = join("\n", @lines0); - $chk[0] =~ s/\n\n+/\n/; - print OUTASM $chk[0]; - - # print out all the literal strings second - for ($i = 1; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'string' ) { - print OUTASM "\t\.rdata\n\t\.align 2\n"; - print OUTASM $chk[$i]; - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - for ($i = 1; $i < $numchks; $i++) { -# print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; - - next if $chkcat[$i] eq 'DONE ALREADY'; - - if ( $chkcat[$i] eq 'misc' ) { - print OUTASM "\t\.text\n\t\.align 2\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM "\t\.data\n\t\.align 2\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'consist' ) { -#? consistency string is just a v -#? horrible bunch of .bytes, -#? which I am too lazy to sort out (WDP 95/05) -#? if ( $chk[$i] =~ /\.ascii.*\)(hsc|cc) (.*)\\11"\n\t\.ascii\s+"(.*)\\0"/ ) { -#? local($consist) = "$1.$2.$3"; -#? $consist =~ s/,/./g; -#? $consist =~ s/\//./g; -#? $consist =~ s/-/_/g; -#? $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? -#? print OUTASM "\t\.text\n$consist:\n"; -#? } else { -#? print STDERR "Couldn't grok consistency: ", $chk[$i]; -#? } - - } elsif ( $chkcat[$i] eq 'splitmarker' ) { - # we can just re-constitute this one... - # ignore the final split marker, to save an empty object module - # Use _three_ underscores so that ghc-split doesn't get overly complicated - print OUTASM "___stg_split_marker",$chksymb[$i],":\n"; - - } elsif ( $chkcat[$i] eq 'closure' - || $chkcat[$i] eq 'infotbl' - || $chkcat[$i] eq 'slow' - || $chkcat[$i] eq 'fast' ) { # do them in that order - $symb = $chksymb[$i]; - - # CLOSURE - if ( defined($closurechk{$symb}) ) { - print OUTASM "\t\.data\n\t\.align 2\n"; - print OUTASM $chk[$closurechk{$symb}]; - $chkcat[$closurechk{$symb}] = 'DONE ALREADY'; - } - - # INFO TABLE - if ( defined($infochk{$symb}) ) { - - print OUTASM "\t\.text\n\t\.align 2\n"; - print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1); - # entry code will be put here! - - # paranoia - if ( $chk[$infochk{$symb}] =~ /\.word\s+([A-Za-z0-9_]+_entry)$/ - && $1 ne "${symb}_entry" ) { - print STDERR "!!! entry point???\n",$chk[$infochk{$symb}]; - } - - $chkcat[$infochk{$symb}] = 'DONE ALREADY'; - } - - # STD ENTRY POINT - if ( defined($slowchk{$symb}) ) { - - # teach it to drop through to the fast entry point: - $c = $chk[$slowchk{$symb}]; - - if ( defined($fastchk{$symb}) ) { - $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/; - } - - # ToDo??? any good way to look for "dangling" references - # to fast-entry pt ??? - - print OUTASM "\t\.text\n\t\.align 2\n"; - print OUTASM $c; - $chkcat[$slowchk{$symb}] = 'DONE ALREADY'; - } - - # FAST ENTRY POINT - if ( defined($fastchk{$symb}) ) { - $c = $chk[$fastchk{$symb}]; - if ( ! defined($slowchk{$symb}) ) { - print OUTASM "\t\.text\n\t\.align 2\n"; - } - print OUTASM $c; - $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; - } - - } elsif ( $chkcat[$i] eq 'vector' - || $chkcat[$i] eq 'direct' ) { # do them in that order - $symb = $chksymb[$i]; - - # VECTOR TABLE - if ( defined($vectorchk{$symb}) ) { - print OUTASM "\t\.text\n\t\.align 2\n"; - print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0); - # direct return code will be put here! - $chkcat[$vectorchk{$symb}] = 'DONE ALREADY'; - } - - # DIRECT RETURN - if ( defined($directchk{$symb}) ) { - print OUTASM "\t\.text\n\t\.align 2\n"; - print OUTASM $chk[$directchk{$symb}]; - $chkcat[$directchk{$symb}] = 'DONE ALREADY'; - } else { - # The commented nop is for the splitter, to ensure - # that no module ends with a label as the very last - # thing. (The linker will adjust the label to point - # to the first code word of the next module linked in, - # even if alignment constraints cause the label to move!) - - print OUTASM "\t# nop\n"; - } - } else { - &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm alpha)\n$chkcat[$i]\n$chk[$i]\n"); - } - } - - print OUTASM $EXTERN_DECLS; - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -\end{code} - -\begin{code} -sub init_FUNNY_THINGS { - %KNOWN_FUNNY_THING = ( - 'CheckHeapCode:', 1, - 'CommonUnderflow:', 1, - 'Continue:', 1, - 'EnterNodeCode:', 1, - 'ErrorIO_call_count:', 1, - 'ErrorIO_innards:', 1, - 'IndUpdRetDir:', 1, - 'IndUpdRetV0:', 1, - 'IndUpdRetV1:', 1, - 'IndUpdRetV2:', 1, - 'IndUpdRetV3:', 1, - 'IndUpdRetV4:', 1, - 'IndUpdRetV5:', 1, - 'IndUpdRetV6:', 1, - 'IndUpdRetV7:', 1, - 'PrimUnderflow:', 1, - 'StackUnderflowEnterNode:', 1, - 'StdErrorCode:', 1, - 'UnderflowVect0:', 1, - 'UnderflowVect1:', 1, - 'UnderflowVect2:', 1, - 'UnderflowVect3:', 1, - 'UnderflowVect4:', 1, - 'UnderflowVect5:', 1, - 'UnderflowVect6:', 1, - 'UnderflowVect7:', 1, - 'UpdErr:', 1, - 'UpdatePAP:', 1, - 'WorldStateToken:', 1, - '_Enter_Internal:', 1, - '_PRMarking_MarkNextAStack:', 1, - '_PRMarking_MarkNextBStack:', 1, - '_PRMarking_MarkNextCAF:', 1, - '_PRMarking_MarkNextGA:', 1, - '_PRMarking_MarkNextRoot:', 1, - '_PRMarking_MarkNextSpark:', 1, - '_Scavenge_Forward_Ref:', 1, - '__std_entry_error__:', 1, - '_startMarkWorld:', 1, - 'resumeThread:', 1, - 'startCcRegisteringWorld:', 1, - 'startEnterFloat:', 1, - 'startEnterInt:', 1, - 'startPerformIO:', 1, - 'startStgWorld:', 1, - 'stopPerformIO:', 1 - ); -} -\end{code} - -The following table reversal is used for both info tables and return -vectors. In both cases, we remove the first entry from the table, -reverse the table, put the label at the end, and paste some code -(that which is normally referred to by the first entry in the table) -right after the table itself. (The code pasting is done elsewhere.) - -\begin{code} -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.word\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+:$/ - || $lines[$i] =~ /^\t\.globl/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.word\s+/; $i++) { - push(@words, $lines[$i]); - } - # now throw away the first word (entry code): - shift(@words) if $discard1; - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} - -# make "require"r happy... -1; -\end{code} diff --git a/ghc/driver/ghc-asm-sgi.prl b/ghc/driver/ghc-asm-sgi.prl deleted file mode 100644 index 2bb357b..0000000 --- a/ghc/driver/ghc-asm-sgi.prl +++ /dev/null @@ -1,69 +0,0 @@ -# line 10 "ghc-asm-sgi.lprl" -sub mangle_asm { - - local($in_asmf, $out_asmf) = @_; - local($fun_code); - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # just copy through now... - while () { - print OUTASM $_; - } - - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -# line 36 "ghc-asm-sgi.lprl" -sub init_FUNNY_THINGS { - print STDERR "SGI: init_FUNNY_THINGS\n"; -} -# line 48 "ghc-asm-sgi.lprl" -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.word\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+:$/ - || $lines[$i] =~ /^\t\.global/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.word\s+/; $i++) { - push(@words, $lines[$i]); - } - # now throw away the first word (entry code): - shift(@words) if $discard1; - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} -# line 88 "ghc-asm-sgi.lprl" -# make "require"r happy... -1; diff --git a/ghc/driver/ghc-asm-solaris.lprl b/ghc/driver/ghc-asm-solaris.lprl deleted file mode 100644 index 6359c66..0000000 --- a/ghc/driver/ghc-asm-solaris.lprl +++ /dev/null @@ -1,498 +0,0 @@ -%************************************************************************ -%* * -\section[Driver-asm-fiddling]{Fiddling with assembler files (SPARC)} -%* * -%************************************************************************ - -Tasks: -\begin{itemize} -\item -Utterly stomp out C functions' prologues and epilogues; i.e., the -stuff to do with the C stack. -\item -(SPARC) [Related] Utterly stomp out the changing of register windows. -\item -Any other required tidying up. -\end{itemize} - -\begin{code} -sub mangle_asm { - local($in_asmf, $out_asmf) = @_; - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # read whole file, divide into "chunks": - # record some info about what we've found... - - @chk = (); # contents of the chunk - $numchks = 0; # number of them - @chkcat = (); # what category of thing in each chunk - @chksymb = (); # what symbol(base) is defined in this chunk - %slowchk = (); # ditto, its regular "slow" entry code - %fastchk = (); # ditto, fast entry code - %closurechk = (); # ditto, the (static) closure - %infochk = (); # given a symbol base, say what chunk its info tbl is in - %vectorchk = (); # ditto, return vector table - %directchk = (); # ditto, direct return code - - $i = 0; - $chkcat[0] = 'misc'; - - while () { - - if ( /^\s+/ ) { # most common case first -- a simple line! - # duplicated from the bottom - - $chk[$i] .= $_; - - } elsif ( /^\.LLC(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'string'; - $chksymb[$i] = $1; - - } elsif ( /^__stg_split_marker(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; - $chksymb[$i] = $1; - - } elsif ( /^([A-Za-z0-9_]+)_info:$/ ) { - $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; - $chksymb[$i] = $symb; - - die "Info table already? $symb; $i\n" if defined($infochk{$symb}); - - $infochk{$symb} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_entry:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; - $chksymb[$i] = $1; - - $slowchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_fast\d+:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; - $chksymb[$i] = $1; - - $fastchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)_closure:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; - $chksymb[$i] = $1; - - $closurechk{$1} = $i; - - } elsif ( /^ghc.*c_ID:/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'consist'; - - } elsif ( /^(__gnu_compiled_c|gcc2_compiled\.):/ ) { - ; # toss it - - } elsif ( /^ErrorIO_call_count:/ # HACK!!!! - || /^[A-Za-z0-9_]+\.\d+:$/ - || /_CAT:/ # PROF: _entryname_CAT - || /^CC_.*_struct:/ # PROF: _CC_ccident_struct - || /_done:/ # PROF: _module_done - || /^_module_registered:/ # PROF: _module_registered - ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; - $chksymb[$i] = ''; - - } elsif ( /^(ret_|djn_)/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^vtbl_([A-Za-z0-9_]+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; - $chksymb[$i] = $1; - - $vectorchk{$1} = $i; - - } elsif ( /^([A-Za-z0-9_]+)DirectReturn:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; - $chksymb[$i] = $1; - - $directchk{$1} = $i; - - } elsif ( /^[A-Za-z0-9_]+_upd:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^[A-Za-z0-9_]/ ) { - local($thing); - chop($thing = $_); - print STDERR "Funny global thing?: $_" - unless $KNOWN_FUNNY_THING{$thing} - || /^_(PRIn|PRStart).*:/ # pointer reversal GC routines - || /^CC_.*:/ # PROF: _CC_ccident - || /^_reg.*:/; # PROF: __reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } else { # simple line (duplicated at the top) - - $chk[$i] .= $_; - } - } - $numchks = $#chk + 1; - -# print STDERR "\nCLOSURES:\n"; -# foreach $s (sort (keys %closurechk)) { -# print STDERR "$s:\t\t",$closurechk{$s},"\n"; -# } -# print STDERR "\nINFOS:\n"; -# foreach $s (sort (keys %infochk)) { -# print STDERR "$s:\t\t",$infochk{$s},"\n"; -# } -# print STDERR "SLOWS:\n"; -# foreach $s (sort (keys %slowchk)) { -# print STDERR "$s:\t\t",$slowchk{$s},"\n"; -# } -# print STDERR "\nFASTS:\n"; -# foreach $s (sort (keys %fastchk)) { -# print STDERR "$s:\t\t",$fastchk{$s},"\n"; -# } - - # the division into chunks is imperfect; - # we throw some things over the fence into the next - # chunk. - # - # also, there are things we would like to know - # about the whole module before we start spitting - # output. - - # NB: we start meddling at chunk 1, not chunk 0 - - for ($i = 1; $i < $numchks; $i++) { - $c = $chk[$i]; # convenience copy - -# print STDERR "\nCHK $i (BEFORE):\n", $c; - - # toss all reg-window stuff (save/restore/ret[l] s): - $c =~ s/^\t(save .*|restore|ret|retl)\n//g; - # throw away PROLOGUE comments - $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//; - - # pin a funny end-thing on (for easier matching): - $c .= 'FUNNY#END#THING'; - - # pick some end-things and move them to the next chunk - - while ( $c =~ /^(\s+\.align\s+\d+\n|\s+\.proc\s+\d+\n|\s+\.global\s+\S+\n|\.text\n|\.data\n|\.stab.*\n|\.section.*\n|\s+\.type.*\n|\s+\.size.*\n)FUNNY#END#THING/ ) { - $to_move = $1; - - if ( $to_move =~ /\.(global|proc|stab)/ && $i < ($numchks - 1) ) { - $chk[$i + 1] = $to_move . $chk[$i + 1]; - # otherwise they're tossed - } - - $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/; - } - - $c =~ s/FUNNY#END#THING//; - $chk[$i] = $c; # update w/ convenience copy - } - - # print out all the literal strings first - for ($i = 0; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'string' ) { - print OUTASM "\.text\n\t\.align 8\n"; - print OUTASM $chk[$i]; - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - for ($i = 1; $i < $numchks; $i++) { -# print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; - - next if $chkcat[$i] eq 'DONE ALREADY'; - - if ( $chkcat[$i] eq 'misc' ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM "\.data\n\t\.align 8\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'consist' ) { - if ( $chk[$i] =~ /\.asciz.*\)(hsc|cc) (.*)\\t(.*)"/ ) { - local($consist) = "$1.$2.$3"; - $consist =~ s/,/./g; - $consist =~ s/\//./g; - $consist =~ s/-/_/g; - $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - print OUTASM "\.text\n$consist:\n"; - } else { - print STDERR "Couldn't grok consistency: ", $chk[$i]; - } - - } elsif ( $chkcat[$i] eq 'splitmarker' ) { - # we can just re-constitute this one... - print OUTASM "___stg_split_marker",$chksymb[$i],":\n"; - - } elsif ( $chkcat[$i] eq 'closure' - || $chkcat[$i] eq 'infotbl' - || $chkcat[$i] eq 'slow' - || $chkcat[$i] eq 'fast' ) { # do them in that order - $symb = $chksymb[$i]; - - # CLOSURE - if ( defined($closurechk{$symb}) ) { - print OUTASM "\.data\n\t\.align 4\n"; - print OUTASM $chk[$closurechk{$symb}]; - $chkcat[$closurechk{$symb}] = 'DONE ALREADY'; - } - - # INFO TABLE - if ( defined($infochk{$symb}) ) { - - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1); - # entry code will be put here! - - # paranoia - if ( $chk[$infochk{$symb}] =~ /\.word\s+([A-Za-z0-9_]+_entry)$/ - && $1 ne "${symb}_entry" ) { - print STDERR "!!! entry point???\n",$chk[$infochk{$symb}]; - } - - $chkcat[$infochk{$symb}] = 'DONE ALREADY'; - } - - # STD ENTRY POINT - if ( defined($slowchk{$symb}) ) { - - # teach it to drop through to the fast entry point: - $c = $chk[$slowchk{$symb}]; - - if ( defined($fastchk{$symb}) ) { - $c =~ s/^\tcall ${symb}_fast\d+,.*\n\tnop\n//; - $c =~ s/^\tcall ${symb}_fast\d+,.*\n(\t[a-z].*\n)/\1/; - } - - print STDERR "still has jump to fast entry point:\n$c" - if $c =~ /${symb}_fast/; # NB: paranoia - - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $c; - $chkcat[$slowchk{$symb}] = 'DONE ALREADY'; - } - - # FAST ENTRY POINT - if ( defined($fastchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $chk[$fastchk{$symb}]; - $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; - } - - } elsif ( $chkcat[$i] eq 'vector' - || $chkcat[$i] eq 'direct' ) { # do them in that order - $symb = $chksymb[$i]; - - # VECTOR TABLE - if ( defined($vectorchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0); - # direct return code will be put here! - $chkcat[$vectorchk{$symb}] = 'DONE ALREADY'; - } - - # DIRECT RETURN - if ( defined($directchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $chk[$directchk{$symb}]; - $chkcat[$directchk{$symb}] = 'DONE ALREADY'; - } - - } else { - &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm SPARC)\n$chkcat[$i]\n$chk[$i]\n"); - } - } - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -\end{code} - -\begin{code} -sub init_FUNNY_THINGS { - %KNOWN_FUNNY_THING = ( - 'CheckHeapCode:', 1, - 'CommonUnderflow:', 1, - 'Continue:', 1, - 'EnterNodeCode:', 1, - 'ErrorIO_call_count:', 1, - 'ErrorIO_innards:', 1, - 'IndUpdRetDir:', 1, - 'IndUpdRetV0:', 1, - 'IndUpdRetV1:', 1, - 'IndUpdRetV2:', 1, - 'IndUpdRetV3:', 1, - 'IndUpdRetV4:', 1, - 'IndUpdRetV5:', 1, - 'IndUpdRetV6:', 1, - 'IndUpdRetV7:', 1, - 'PrimUnderflow:', 1, - 'StackUnderflowEnterNode:', 1, - 'StdErrorCode:', 1, - 'UnderflowVect0:', 1, - 'UnderflowVect1:', 1, - 'UnderflowVect2:', 1, - 'UnderflowVect3:', 1, - 'UnderflowVect4:', 1, - 'UnderflowVect5:', 1, - 'UnderflowVect6:', 1, - 'UnderflowVect7:', 1, - 'UpdErr:', 1, - 'UpdatePAP:', 1, - 'WorldStateToken:', 1, - '_Enter_Internal:', 1, - '_PRMarking_MarkNextAStack:', 1, - '_PRMarking_MarkNextBStack:', 1, - '_PRMarking_MarkNextCAF:', 1, - '_PRMarking_MarkNextGA:', 1, - '_PRMarking_MarkNextRoot:', 1, - '_PRMarking_MarkNextSpark:', 1, - '_Scavenge_Forward_Ref:', 1, - '__std_entry_error__:', 1, - '_startMarkWorld:', 1, - 'resumeThread:', 1, - 'startCcRegisteringWorld:', 1, - 'startEnterFloat:', 1, - 'startEnterInt:', 1, - 'startPerformIO:', 1, - 'startStgWorld:', 1, - 'stopPerformIO:', 1 - ); -} -\end{code} - -The following table reversal is used for both info tables and return -vectors. In both cases, we remove the first entry from the table, -reverse the table, put the label at the end, and paste some code -(that which is normally referred to by the first entry in the table) -right after the table itself. (The code pasting is done elsewhere.) - -\begin{code} -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.word\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+:$/ - || $lines[$i] =~ /^\t\.global/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.word\s+/; $i++) { - push(@words, $lines[$i]); - } - # now throw away the first word (entry code): - shift(@words) if $discard1; - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} -\end{code} - -%************************************************************************ -%* * -\subsection[Driver-asm-info]{Collect interesting (static) info from an assembler file} -%* * -%************************************************************************ - -How many times is each asm instruction used? - -\begin{code} -%AsmInsn = (); # init - -sub dump_asm_insn_counts { - local($asmf) = @_; - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\t([a-z][a-z0-9]+)\b/ ) { - $AsmInsn{$1} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %AsmInsn)) { - print STDERR "INSN:: $i\t",$AsmInsn{$i},"\n"; - } -} -\end{code} - -How many times is each ``global variable'' used in a \tr{sethi} -instruction (SPARC)? This can give some guidance about what should be -put in machine registers... - -\begin{code} -%SethiGlobal = (); # init - -sub dump_asm_globals_info { - local($asmf) = @_; - - local($globl); - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\tsethi \%hi\(_([_A-Za-z0-9]+)/ ) { - $globl = $1; - next if $globl =~ /(ds|fail|stg|tpl|vtbl)_[0-9]+/; - - $SethiGlobal{$globl} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %SethiGlobal)) { - print STDERR "GLOBAL:: $i\t",$SethiGlobal{$i},"\n"; - } -} - -# make "require"r happy... -1; -\end{code} diff --git a/ghc/driver/ghc-asm-sparc.lprl b/ghc/driver/ghc-asm-sparc.lprl deleted file mode 100644 index ffe91ae..0000000 --- a/ghc/driver/ghc-asm-sparc.lprl +++ /dev/null @@ -1,487 +0,0 @@ -%************************************************************************ -%* * -\section[Driver-asm-fiddling]{Fiddling with assembler files (SPARC)} -%* * -%************************************************************************ - -Tasks: -\begin{itemize} -\item -Utterly stomp out C functions' prologues and epilogues; i.e., the -stuff to do with the C stack. -\item -(SPARC) [Related] Utterly stomp out the changing of register windows. -\item -Any other required tidying up. -\end{itemize} - -\begin{code} -sub mangle_asm { - local($in_asmf, $out_asmf) = @_; - - # multi-line regexp matching: - local($*) = 1; - local($i, $c); - &init_FUNNY_THINGS(); - - open(INASM, "< $in_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); - open(OUTASM,"> $out_asmf") - || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); - - # read whole file, divide into "chunks": - # record some info about what we've found... - - @chk = (); # contents of the chunk - $numchks = 0; # number of them - @chkcat = (); # what category of thing in each chunk - @chksymb = (); # what symbol(base) is defined in this chunk - %slowchk = (); # ditto, its regular "slow" entry code - %fastchk = (); # ditto, fast entry code - %closurechk = (); # ditto, the (static) closure - %infochk = (); # given a symbol base, say what chunk its info tbl is in - %vectorchk = (); # ditto, return vector table - %directchk = (); # ditto, direct return code - - $i = 0; - $chkcat[0] = 'misc'; - - while () { - next if /^\.stab.*___stg_split_marker/; - next if /^\.stab.*ghc.*c_ID/; - - if ( /^\s+/ ) { # most common case first -- a simple line! - # duplicated from the bottom - - $chk[$i] .= $_; - - } elsif ( /^LC(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'string'; - $chksymb[$i] = $1; - - } elsif ( /^___stg_split_marker(\d+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; - $chksymb[$i] = $1; - - } elsif ( /^_([A-Za-z0-9_]+)_info:$/ ) { - $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; - $chksymb[$i] = $symb; - - die "Info table already? $symb; $i\n" if defined($infochk{$symb}); - - $infochk{$symb} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)_entry:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; - $chksymb[$i] = $1; - - $slowchk{$1} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)_fast\d+:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; - $chksymb[$i] = $1; - - $fastchk{$1} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)_closure:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; - $chksymb[$i] = $1; - - $closurechk{$1} = $i; - - } elsif ( /^_ghc.*c_ID:/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'consist'; - - } elsif ( /^(___gnu_compiled_c|gcc2_compiled\.):/ ) { - ; # toss it - - } elsif ( /^_ErrorIO_call_count:/ # HACK!!!! - || /^_[A-Za-z0-9_]+\.\d+:$/ - || /^_.*_CAT:/ # PROF: _entryname_CAT - || /^_CC_.*_struct:/ # PROF: _CC_ccident_struct - || /^_.*_done:/ # PROF: _module_done - || /^__module_registered:/ # PROF: _module_registered - ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; - $chksymb[$i] = ''; - - } elsif ( /^_(ret_|djn_)/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^_vtbl_([A-Za-z0-9_]+):$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; - $chksymb[$i] = $1; - - $vectorchk{$1} = $i; - - } elsif ( /^_([A-Za-z0-9_]+)DirectReturn:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; - $chksymb[$i] = $1; - - $directchk{$1} = $i; - - } elsif ( /^_[A-Za-z0-9_]+_upd:$/ ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } elsif ( /^_[A-Za-z0-9_]/ ) { - local($thing); - chop($thing = $_); - print STDERR "Funny global thing?: $_" - unless $KNOWN_FUNNY_THING{$thing} - || /^__(PRIn|PRStart).*:/ # pointer reversal GC routines - || /^_CC_.*:/ # PROF: _CC_ccident - || /^__reg.*:/; # PROF: __reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; - $chksymb[$i] = ''; - - } else { # simple line (duplicated at the top) - - $chk[$i] .= $_; - } - } - $numchks = $#chk + 1; - - # the division into chunks is imperfect; - # we throw some things over the fence into the next - # chunk. - # - # also, there are things we would like to know - # about the whole module before we start spitting - # output. - - # NB: we start meddling at chunk 1, not chunk 0 - - for ($i = 1; $i < $numchks; $i++) { - $c = $chk[$i]; # convenience copy - -# print STDERR "\nCHK $i (BEFORE):\n", $c; - - # toss all reg-window stuff (save/restore/ret[l] s): - $c =~ s/^\t(save .*|restore|ret|retl)\n//g; - # throw away PROLOGUE comments - $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//; - - # pin a funny end-thing on (for easier matching): - $c .= 'FUNNY#END#THING'; - - # pick some end-things and move them to the next chunk - - while ( $c =~ /^(\s+\.align\s+\d+\n|\s+\.proc\s+\d+\n|\s+\.global\s+\S+\n|\.text\n|\.data\n|\.stab.*\n)FUNNY#END#THING/ ) { - $to_move = $1; - - if ( $to_move =~ /\.(global|proc|stab)/ && $i < ($numchks - 1) ) { - $chk[$i + 1] = $to_move . $chk[$i + 1]; - # otherwise they're tossed - } - - $c =~ s/^.*\nFUNNY#END#THING/FUNNY#END#THING/; - } - - $c =~ s/FUNNY#END#THING//; - $chk[$i] = $c; # update w/ convenience copy - -# print STDERR "\nCHK $i (AFTER):\n", $c; - } - - # print out all the literal strings first - for ($i = 0; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'string' ) { - print OUTASM "\.text\n\t\.align 8\n"; - print OUTASM $chk[$i]; - - $chkcat[$i] = 'DONE ALREADY'; - } - } - - for ($i = 0; $i < $numchks; $i++) { -# print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; - - next if $chkcat[$i] eq 'DONE ALREADY'; - - if ( $chkcat[$i] eq 'misc' ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM "\.data\n\t\.align 8\n"; - print OUTASM $chk[$i]; - - } elsif ( $chkcat[$i] eq 'consist' ) { - if ( $chk[$i] =~ /\.ascii.*\)(hsc|cc) (.*)\\11"\n\t\.ascii\s+"(.*)\\0"/ ) { - local($consist) = "$1.$2.$3"; - $consist =~ s/,/./g; - $consist =~ s/\//./g; - $consist =~ s/-/_/g; - $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - print OUTASM "\.text\n$consist:\n"; - } else { - print STDERR "Couldn't grok consistency: ", $chk[$i]; - } - - } elsif ( $chkcat[$i] eq 'splitmarker' ) { - # we can just re-constitute this one... - print OUTASM "___stg_split_marker",$chksymb[$i],":\n"; - - } elsif ( $chkcat[$i] eq 'closure' - || $chkcat[$i] eq 'infotbl' - || $chkcat[$i] eq 'slow' - || $chkcat[$i] eq 'fast' ) { # do them in that order - $symb = $chksymb[$i]; - -# print STDERR "$i: cat $chkcat[$i], symb $symb ",defined($closurechk{$symb}),":",defined($infochk{$symb}),":",defined($slowchk{$symb}),":",defined($fastchk{$symb}),"\n"; - - # CLOSURE - if ( defined($closurechk{$symb}) ) { - print OUTASM "\.data\n\t\.align 4\n"; - print OUTASM $chk[$closurechk{$symb}]; - $chkcat[$closurechk{$symb}] = 'DONE ALREADY'; - } - - # INFO TABLE - if ( defined($infochk{$symb}) ) { - - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM &rev_tbl($symb, $chk[$infochk{$symb}], 1); - # entry code will follow, here! - - # paranoia - if ( $chk[$infochk{$symb}] =~ /\.word\s+([A-Za-z0-9_]+_entry)$/ - && $1 ne "_${symb}_entry" ) { - print STDERR "!!! entry point???\n",$chk[$infochk{$symb}]; - } - - $chkcat[$infochk{$symb}] = 'DONE ALREADY'; - } - - # STD ENTRY POINT - if ( defined($slowchk{$symb}) ) { - - # teach it to drop through to the fast entry point: - $c = $chk[$slowchk{$symb}]; - - if ( defined($fastchk{$symb}) ) { - $c =~ s/^\tcall _${symb}_fast\d+,.*\n\tnop\n//; - $c =~ s/^\tcall _${symb}_fast\d+,.*\n(\t[a-z].*\n)/\1/; - } - - print STDERR "still has jump to fast entry point:\n$c" - if $c =~ /_${symb}_fast/; # NB: paranoia - - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $c; - $chkcat[$slowchk{$symb}] = 'DONE ALREADY'; - } - - # FAST ENTRY POINT - if ( defined($fastchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $chk[$fastchk{$symb}]; - $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; - } - - } elsif ( $chkcat[$i] eq 'vector' - || $chkcat[$i] eq 'direct' ) { # do them in that order - $symb = $chksymb[$i]; - - # VECTOR TABLE - if ( defined($vectorchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM &rev_tbl($symb, $chk[$vectorchk{$symb}], 0); - # direct return code will be put here! - $chkcat[$vectorchk{$symb}] = 'DONE ALREADY'; - } - - # DIRECT RETURN - if ( defined($directchk{$symb}) ) { - print OUTASM "\.text\n\t\.align 4\n"; - print OUTASM $chk[$directchk{$symb}]; - $chkcat[$directchk{$symb}] = 'DONE ALREADY'; - } - - } else { - &tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm SPARC)\n$chkcat[$i]\n$chk[$i]\n"); - } - } - - # finished: - close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); - close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); -} -\end{code} - -\begin{code} -sub init_FUNNY_THINGS { - %KNOWN_FUNNY_THING = ( - '_CheckHeapCode:', 1, - '_CommonUnderflow:', 1, - '_Continue:', 1, - '_EnterNodeCode:', 1, - '_ErrorIO_call_count:', 1, - '_ErrorIO_innards:', 1, - '_IndUpdRetDir:', 1, - '_IndUpdRetV0:', 1, - '_IndUpdRetV1:', 1, - '_IndUpdRetV2:', 1, - '_IndUpdRetV3:', 1, - '_IndUpdRetV4:', 1, - '_IndUpdRetV5:', 1, - '_IndUpdRetV6:', 1, - '_IndUpdRetV7:', 1, - '_PrimUnderflow:', 1, - '_StackUnderflowEnterNode:', 1, - '_StdErrorCode:', 1, - '_UnderflowVect0:', 1, - '_UnderflowVect1:', 1, - '_UnderflowVect2:', 1, - '_UnderflowVect3:', 1, - '_UnderflowVect4:', 1, - '_UnderflowVect5:', 1, - '_UnderflowVect6:', 1, - '_UnderflowVect7:', 1, - '_UpdErr:', 1, - '_UpdatePAP:', 1, - '_WorldStateToken:', 1, - '__Enter_Internal:', 1, - '__PRMarking_MarkNextAStack:', 1, - '__PRMarking_MarkNextBStack:', 1, - '__PRMarking_MarkNextCAF:', 1, - '__PRMarking_MarkNextGA:', 1, - '__PRMarking_MarkNextRoot:', 1, - '__PRMarking_MarkNextSpark:', 1, - '__Scavenge_Forward_Ref:', 1, - '___std_entry_error__:', 1, - '__startMarkWorld:', 1, - '_resumeThread:', 1, - '_startCcRegisteringWorld:', 1, - '_startEnterFloat:', 1, - '_startEnterInt:', 1, - '_startPerformIO:', 1, - '_startStgWorld:', 1, - '_stopPerformIO:', 1 - ); -} -\end{code} - -The following table reversal is used for both info tables and return -vectors. In both cases, we remove the first entry from the table, -reverse the table, put the label at the end, and paste some code -(that which is normally referred to by the first entry in the table) -right after the table itself. (The code pasting is done elsewhere.) - -\begin{code} -sub rev_tbl { - local($symb, $tbl, $discard1) = @_; - - local($before) = ''; - local($label) = ''; - local(@words) = (); - local($after) = ''; - local(@lines) = split(/\n/, $tbl); - local($i); - - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.word\s+/; $i++) { - $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+:$/ - || $lines[$i] =~ /^\t\.global/; - - $before .= $lines[$i] . "\n"; # otherwise... - } - - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.word\s+/; $i++) { - push(@words, $lines[$i]); - } - # now throw away the first word (entry code): - shift(@words) if $discard1; - - for (; $i <= $#lines; $i++) { - $after .= $lines[$i] . "\n"; - } - - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; - -# print STDERR "before=$before\n"; -# print STDERR "label=$label\n"; -# print STDERR "words=",(reverse @words),"\n"; -# print STDERR "after=$after\n"; - - $tbl; -} -\end{code} - -%************************************************************************ -%* * -\subsection[Driver-asm-info]{Collect interesting (static) info from an assembler file} -%* * -%************************************************************************ - -How many times is each asm instruction used? - -\begin{code} -%AsmInsn = (); # init - -sub dump_asm_insn_counts { - local($asmf) = @_; - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\t([a-z][a-z0-9]+)\b/ ) { - $AsmInsn{$1} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %AsmInsn)) { - print STDERR "INSN:: $i\t",$AsmInsn{$i},"\n"; - } -} -\end{code} - -How many times is each ``global variable'' used in a \tr{sethi} -instruction (SPARC)? This can give some guidance about what should be -put in machine registers... - -\begin{code} -%SethiGlobal = (); # init - -sub dump_asm_globals_info { - local($asmf) = @_; - - local($globl); - - open(INASM, "< $asmf") || &tidy_up_and_die(1,"$Pgm: failed to open `$asmf' (to read)\n"); - while () { - if ( /^\tsethi \%hi\(_([_A-Za-z0-9]+)/ ) { - $globl = $1; - next if $globl =~ /(ds|fail|stg|tpl|vtbl)_[0-9]+/; - - $SethiGlobal{$globl} ++; - } - } - close(INASM) || &tidy_up_and_die(1,"Failed reading from $asmf\n"); - - # OK, now print what we collected (to stderr) - foreach $i (sort (keys %SethiGlobal)) { - print STDERR "GLOBAL:: $i\t",$SethiGlobal{$i},"\n"; - } -} - -# make "require"r happy... -1; -\end{code} diff --git a/ghc/driver/ghc-asm.lprl b/ghc/driver/ghc-asm.lprl index 4a4834c..0907b09 100644 --- a/ghc/driver/ghc-asm.lprl +++ b/ghc/driver/ghc-asm.lprl @@ -13,6 +13,33 @@ stuff to do with the C stack. Any other required tidying up. \end{itemize} +HPPA specific notes: +\begin{itemize} +\item +The HP linker is very picky about symbols being in the appropriate +space (code vs. data). When we mangle the threaded code to put the +info tables just prior to the code, they wind up in code space +rather than data space. This means that references to *_info from +un-mangled parts of the RTS (e.g. unthreaded GC code) get +unresolved symbols. Solution: mini-mangler for .c files on HP. I +think this should really be triggered in the driver by a new -rts +option, so that user code doesn't get mangled inappropriately. +\item +With reversed tables, jumps are to the _info label rather than to +the _entry label. The _info label is just an address in code +space, rather than an entry point with the descriptive blob we +talked about yesterday. As a result, you can't use the call-style +JMP_ macro. However, some JMP_ macros take _info labels as targets +and some take code entry points within the RTS. The latter won't +work with the goto-style JMP_ macro. Sigh. Solution: Use the goto +style JMP_ macro, and mangle some more assembly, changing all +"RP'literal" and "LP'literal" references to "R'literal" and +"L'literal," so that you get the real address of the code, rather +than the descriptive blob. Also change all ".word P%literal" +entries in info tables and vector tables to just ".word literal," +for the same reason. Advantage: No more ridiculous call sequences. +\end{itemize} + %************************************************************************ %* * \subsection{Constants for various architectures} @@ -22,7 +49,62 @@ Any other required tidying up. \begin{code} sub init_TARGET_STUFF { - if ( $TargetPlatform =~ /^i386-.*-linuxaout/ ) { + #--------------------------------------------------------# + if ( $TargetPlatform =~ /^alpha-.*-.*/ ) { + + $T_STABBY = 0; # 1 iff .stab things (usually if a.out format) + $T_US = ''; # _ if symbols have an underscore on the front + $T_DO_GC = 'PerformGC_wrapper'; + $T_PRE_APP = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP + $T_CONST_LBL = '^\$C(\d+):$'; # regexp for what such a lbl looks like + $T_POST_LBL = ':'; + + $T_MOVE_DIRVS = '^(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\#.*|\.(file|loc)\s+\S+\s+\S+|\.text|\.r?data)\n)'; + $T_COPY_DIRVS = '^\s*(\#|\.(file|globl|ent|loc))'; + + $T_hsc_cc_PAT = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"'; + $T_DOT_WORD = '\.quad'; + $T_DOT_GLOBAL = "\t\.globl"; + $T_HDR_literal = "\.rdata\n\t\.align 3\n"; + $T_HDR_misc = "\.text\n\t\.align 3\n"; + $T_HDR_data = "\.data\n\t\.align 3\n"; + $T_HDR_consist = "\.text\n"; + $T_HDR_closure = "\.data\n\t\.align 3\n"; + $T_HDR_info = "\.text\n\t\.align 3\n"; + $T_HDR_entry = "\.text\n\t\.align 3\n"; + $T_HDR_fast = "\.text\n\t\.align 3\n"; + $T_HDR_vector = "\.text\n\t\.align 3\n"; + $T_HDR_direct = "\.text\n\t\.align 3\n"; + + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^hppa/ ) { + + $T_STABBY = 0; # 1 iff .stab things (usually if a.out format) + $T_US = ''; # _ if symbols have an underscore on the front + $T_DO_GC = 'PerformGC_wrapper'; + $T_PRE_APP = 'DONT THINK THIS APPLIES'; # regexp that says what comes before APP/NO_APP + $T_CONST_LBL = '^L\$C(\d+)$'; # regexp for what such a lbl looks like + $T_POST_LBL = ''; + + $T_MOVE_DIRVS = '^((\s+\.(IMPORT|EXPORT|PARAM).*|\s+\.align\s+\d+|\s+\.(SPACE|SUBSPA)\s+\S+|\s*)\n)'; + $T_COPY_DIRVS = '^\s+\.(IMPORT|EXPORT)'; + + $T_hsc_cc_PAT = '\.STRING.*\)(hsc|cc) (.*)\\\\x09(.*)\\\\x00'; + $T_DOT_WORD = '\.word'; + $T_DOT_GLOBAL = '\s+\.EXPORT'; + $T_HDR_literal = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n"; + $T_HDR_misc = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; + $T_HDR_data = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n"; + $T_HDR_consist = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$LIT\$\n"; + $T_HDR_closure = "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$DATA\$\n\t\.align 4\n"; + $T_HDR_info = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; + $T_HDR_entry = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; + $T_HDR_fast = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; + $T_HDR_vector = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; + $T_HDR_direct = "\t.SPACE \$TEXT\$\n\t.SUBSPA \$CODE\$\n\t\.align 4\n"; + + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^i386-.*-(linuxaout|freebsd)/ ) { $T_STABBY = 1; # 1 iff .stab things (usually if a.out format) $T_US = '_'; # _ if symbols have an underscore on the front @@ -30,26 +112,28 @@ sub init_TARGET_STUFF { $T_PRE_APP = '^#'; # regexp that says what comes before APP/NO_APP $T_CONST_LBL = '^LC(\d+):$'; $T_POST_LBL = ':'; - $T_PRE_LLBL_PAT = 'L'; - $T_PRE_LLBL = 'L'; + $T_X86_PRE_LLBL_PAT = 'L'; + $T_X86_PRE_LLBL = 'L'; $T_X86_BADJMP = '^\tjmp [^L\*]'; - $T_MOVE_DIRVS = '^\s*(\.align\s+\d+(,0x90)?\n|\.globl\s+\S+\n|\.text\n|\.data\n|\.stab[^n].*\n)'; + $T_MOVE_DIRVS = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.stab[^n].*|\.type\s+.*|\.size\s+.*)\n)'; $T_COPY_DIRVS = '\.(globl|stab)'; $T_hsc_cc_PAT = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"'; $T_DOT_WORD = '\.long'; - $T_HDR_string = "\.text\n\t\.align 4\n"; # .align 4 is 486-cache friendly - $T_HDR_misc = "\.text\n\t\.align 4\n"; + $T_DOT_GLOBAL = '\.globl'; + $T_HDR_literal = "\.text\n\t\.align 2\n"; # .align 4 is 486-cache friendly + $T_HDR_misc = "\.text\n\t\.align 2,0x90\n"; $T_HDR_data = "\.data\n\t\.align 2\n"; # ToDo: change align?? $T_HDR_consist = "\.text\n"; $T_HDR_closure = "\.data\n\t\.align 2\n"; # ToDo: change align? - $T_HDR_info = "\.text\n\t\.align 4\n"; # NB: requires padding + $T_HDR_info = "\.text\n\t\.align 2\n"; # NB: requires padding $T_HDR_entry = "\.text\n"; # no .align so we're right next to _info (arguably wrong...?) - $T_HDR_fast = "\.text\n\t\.align 4\n"; - $T_HDR_vector = "\.text\n\t\.align 4\n"; # NB: requires padding - $T_HDR_direct = "\.text\n\t\.align 4\n"; + $T_HDR_fast = "\.text\n\t\.align 2,0x90\n"; + $T_HDR_vector = "\.text\n\t\.align 2\n"; # NB: requires padding + $T_HDR_direct = "\.text\n\t\.align 2,0x90\n"; - } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/ ) { + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^i386-.*-(solaris2|linux)$/ ) { $T_STABBY = 0; # 1 iff .stab things (usually if a.out format) $T_US = ''; # _ if symbols have an underscore on the front @@ -57,16 +141,17 @@ sub init_TARGET_STUFF { $T_PRE_APP = '/'; # regexp that says what comes before APP/NO_APP $T_CONST_LBL = '^\.LC(\d+):$'; # regexp for what such a lbl looks like $T_POST_LBL = ':'; - $T_PRE_LLBL_PAT = '\.L'; - $T_PRE_LLBL = '.L'; + $T_X86_PRE_LLBL_PAT = '\.L'; + $T_X86_PRE_LLBL = '.L'; $T_X86_BADJMP = '^\tjmp [^\.\*]'; - $T_MOVE_DIRVS = '^\s*(\.align\s+\d+(,0x90)?\n|\.globl\s+\S+\n|\.text\n|\.data\n|\.section\s+.*\n|\.type\s+.*\n|\.Lfe.*\n\t\.size\s+.*\n|\.size\s+.*\n|\.ident.*\n)'; + $T_MOVE_DIRVS = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.Lfe.*\n\t\.size\s+.*|\.size\s+.*|\.ident.*)\n)'; $T_COPY_DIRVS = '\.(globl)'; $T_hsc_cc_PAT = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"'; $T_DOT_WORD = '\.long'; - $T_HDR_string = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11) + $T_DOT_GLOBAL = '\.globl'; + $T_HDR_literal = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11) $T_HDR_misc = "\.text\n\t\.align 16\n"; $T_HDR_data = "\.data\n\t\.align 4\n"; # ToDo: change align?? $T_HDR_consist = "\.text\n"; @@ -77,6 +162,61 @@ sub init_TARGET_STUFF { $T_HDR_vector = "\.text\n\t\.align 16\n"; # NB: requires padding $T_HDR_direct = "\.text\n\t\.align 16\n"; + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^m68k-.*-sunos4/ ) { + + $T_STABBY = 1; # 1 iff .stab things (usually if a.out format) + $T_US = '_'; # _ if symbols have an underscore on the front + $T_DO_GC = '_PerformGC_wrapper'; + $T_PRE_APP = '^# MAY NOT APPLY'; # regexp that says what comes before APP/NO_APP + $T_CONST_LBL = '^LC(\d+):$'; + $T_POST_LBL = ':'; + + $T_MOVE_DIRVS = '(\s*(\.align\s+\d+|\.proc\s+\d+|\.const|\.cstring|\.globl\s+\S+|\.text|\.data|\.even|\.stab[^n].*)\n)'; + $T_COPY_DIRVS = '\.(globl|proc|stab)'; + $T_hsc_cc_PAT = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"'; + + $T_DOT_WORD = '\.long'; + $T_DOT_GLOBAL = '\.globl'; + $T_HDR_literal = "\.text\n\t\.even\n"; + $T_HDR_misc = "\.text\n\t\.even\n"; + $T_HDR_data = "\.data\n\t\.even\n"; + $T_HDR_consist = "\.text\n"; + $T_HDR_closure = "\.data\n\t\.even\n"; + $T_HDR_info = "\.text\n\t\.even\n"; + $T_HDR_entry = "\.text\n\t\.even\n"; + $T_HDR_fast = "\.text\n\t\.even\n"; + $T_HDR_vector = "\.text\n\t\.even\n"; + $T_HDR_direct = "\.text\n\t\.even\n"; + + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^mips-.*/ ) { + + $T_STABBY = 0; # 1 iff .stab things (usually if a.out format) + $T_US = ''; # _ if symbols have an underscore on the front + $T_DO_GC = 'PerformGC_wrapper'; + $T_PRE_APP = '^\s*#'; # regexp that says what comes before APP/NO_APP + $T_CONST_LBL = '^\$LC(\d+):$'; # regexp for what such a lbl looks like + $T_POST_LBL = ':'; + + $T_MOVE_DIRVS = '(\s*(\.align\s+\d+|\.(globl|ent)\s+\S+|\.text|\.r?data)\n)'; + $T_COPY_DIRVS = '\.(globl|ent)'; + + $T_hsc_cc_PAT = 'I WAS TOO LAZY TO DO THIS BIT (WDP 95/05)'; + $T_DOT_WORD = '\.word'; + $T_DOT_GLOBAL = '\t\.globl'; + $T_HDR_literal = "\t\.rdata\n\t\.align 2\n"; + $T_HDR_misc = "\t\.text\n\t\.align 2\n"; + $T_HDR_data = "\t\.data\n\t\.align 2\n"; + $T_HDR_consist = 'TOO LAZY TO DO THIS TOO'; + $T_HDR_closure = "\t\.data\n\t\.align 2\n"; + $T_HDR_info = "\t\.text\n\t\.align 2\n"; + $T_HDR_entry = "\t\.text\n\t\.align 2\n"; + $T_HDR_fast = "\t\.text\n\t\.align 2\n"; + $T_HDR_vector = "\t\.text\n\t\.align 2\n"; + $T_HDR_direct = "\t\.text\n\t\.align 2\n"; + + #--------------------------------------------------------# } elsif ( $TargetPlatform =~ /^powerpc-.*/ ) { $T_STABBY = 0; # 1 iff .stab things (usually if a.out format) @@ -85,16 +225,14 @@ sub init_TARGET_STUFF { $T_PRE_APP = 'NOT APPLICABLE'; # regexp that says what comes before APP/NO_APP $T_CONST_LBL = '^LC\.\.(\d+):$'; # regexp for what such a lbl looks like $T_POST_LBL = ':'; - $T_PRE_LLBL_PAT = '\.L'; - $T_PRE_LLBL = '.L'; - $T_X86_BADJMP = 'NOT APPLICABLE'; - $T_MOVE_DIRVS = '^\s*(\.align\s+\d+(,0x90)?\n|\.globl\s+\S+\n|\.text\n|\.data\n|\.section\s+.*\n|\.type\s+.*\n|\.Lfe.*\n\t\.size\s+.*\n|\.size\s+.*\n|\.ident.*\n)'; + $T_MOVE_DIRVS = '^(\s*(\.align\s+\d+(,0x90)?|\.globl\s+\S+|\.text|\.data|\.section\s+.*|\.type\s+.*|\.Lfe.*\n\t\.size\s+.*|\.size\s+.*|\.ident.*)\n)'; $T_COPY_DIRVS = '\.(globl)'; $T_hsc_cc_PAT = '\.string.*\)(hsc|cc) (.*)\\\\t(.*)"'; $T_DOT_WORD = '\.long'; - $T_HDR_string = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11) + $T_DOT_GLOBAL = '\.globl'; + $T_HDR_literal = "\.section\t\.rodata\n"; # or just use .text??? (WDP 95/11) $T_HDR_misc = "\.text\n\t\.align 16\n"; $T_HDR_data = "\.data\n\t\.align 4\n"; # ToDo: change align?? $T_HDR_consist = "\.text\n"; @@ -104,6 +242,65 @@ sub init_TARGET_STUFF { $T_HDR_fast = "\.text\n\t\.align 16\n"; $T_HDR_vector = "\.text\n\t\.align 16\n"; # NB: requires padding $T_HDR_direct = "\.text\n\t\.align 16\n"; + + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^sparc-.*-solaris2/ ) { + + $T_STABBY = 0; # 1 iff .stab things (usually if a.out format) + $T_US = ''; # _ if symbols have an underscore on the front + $T_DO_GC = 'PerformGC_wrapper'; + $T_PRE_APP = 'DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP + $T_CONST_LBL = '^\.LLC(\d+):$'; # regexp for what such a lbl looks like + $T_POST_LBL = ':'; + + $T_MOVE_DIRVS = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*|\.section.*|\s+\.type.*|\s+\.size.*)\n)'; + $T_COPY_DIRVS = '\.(global|proc|stab)'; + + $T_hsc_cc_PAT = '\.asciz.*\)(hsc|cc) (.*)\\\\t(.*)"'; + $T_DOT_WORD = '\.word'; + $T_DOT_GLOBAL = '\.global'; + $T_HDR_literal = "\.text\n\t\.align 8\n"; + $T_HDR_misc = "\.text\n\t\.align 4\n"; + $T_HDR_data = "\.data\n\t\.align 8\n"; + $T_HDR_consist = "\.text\n"; + $T_HDR_closure = "\.data\n\t\.align 4\n"; + $T_HDR_info = "\.text\n\t\.align 4\n"; + $T_HDR_entry = "\.text\n\t\.align 4\n"; + $T_HDR_fast = "\.text\n\t\.align 4\n"; + $T_HDR_vector = "\.text\n\t\.align 4\n"; + $T_HDR_direct = "\.text\n\t\.align 4\n"; + + #--------------------------------------------------------# + } elsif ( $TargetPlatform =~ /^sparc-.*-sunos4/ ) { + + $T_STABBY = 1; # 1 iff .stab things (usually if a.out format) + $T_US = '_'; # _ if symbols have an underscore on the front + $T_DO_GC = '_PerformGC_wrapper'; + $T_PRE_APP = '^# DOES NOT SEEM TO APPLY'; # regexp that says what comes before APP/NO_APP + $T_CONST_LBL = '^LC(\d+):$'; + $T_POST_LBL = ':'; + + $T_MOVE_DIRVS = '^((\s+\.align\s+\d+|\s+\.proc\s+\d+|\s+\.global\s+\S+|\.text|\.data|\.stab.*)\n)'; + $T_COPY_DIRVS = '\.(global|proc|stab)'; + $T_hsc_cc_PAT = '\.ascii.*\)(hsc|cc) (.*)\\\\11"\n\t\.ascii\s+"(.*)\\\\0"'; + + $T_DOT_WORD = '\.word'; + $T_DOT_GLOBAL = '^\t\.global'; + $T_HDR_literal = "\.text\n\t\.align 8\n"; + $T_HDR_misc = "\.text\n\t\.align 4\n"; + $T_HDR_data = "\.data\n\t\.align 8\n"; + $T_HDR_consist = "\.text\n"; + $T_HDR_closure = "\.data\n\t\.align 4\n"; + $T_HDR_info = "\.text\n\t\.align 4\n"; + $T_HDR_entry = "\.text\n\t\.align 4\n"; + $T_HDR_fast = "\.text\n\t\.align 4\n"; + $T_HDR_vector = "\.text\n\t\.align 4\n"; + $T_HDR_direct = "\.text\n\t\.align 4\n"; + + #--------------------------------------------------------# + } else { + print STDERR "$Pgm: don't know how to mangle assembly language for: $TargetPlatform\n"; + exit 1; } if ( 0 ) { @@ -113,15 +310,16 @@ print STDERR "T_DO_GC: $T_DO_GC\n"; print STDERR "T_PRE_APP: $T_PRE_APP\n"; print STDERR "T_CONST_LBL: $T_CONST_LBL\n"; print STDERR "T_POST_LBL: $T_POST_LBL\n"; -print STDERR "T_PRE_LLBL_PAT: $T_PRE_LLBL_PAT\n"; -print STDERR "T_PRE_LLBL: $T_PRE_LLBL\n"; -print STDERR "T_X86_BADJMP: $T_X86_BADJMP\n"; - +if ( $TargetPlatform =~ /^i386-/ ) { + print STDERR "T_X86_PRE_LLBL_PAT: $T_X86_PRE_LLBL_PAT\n"; + print STDERR "T_X86_PRE_LLBL: $T_X86_PRE_LLBL\n"; + print STDERR "T_X86_BADJMP: $T_X86_BADJMP\n"; +} print STDERR "T_MOVE_DIRVS: $T_MOVE_DIRVS\n"; print STDERR "T_COPY_DIRVS: $T_COPY_DIRVS\n"; print STDERR "T_hsc_cc_PAT: $T_hsc_cc_PAT\n"; print STDERR "T_DOT_WORD: $T_DOT_WORD\n"; -print STDERR "T_HDR_string: $T_HDR_string\n"; +print STDERR "T_HDR_literal: $T_HDR_literal\n"; print STDERR "T_HDR_misc: $T_HDR_misc\n"; print STDERR "T_HDR_data: $T_HDR_data\n"; print STDERR "T_HDR_consist: $T_HDR_consist\n"; @@ -170,34 +368,52 @@ sub mangle_asm { %infochk = (); # given a symbol base, say what chunk its info tbl is in %vectorchk = (); # ditto, return vector table %directchk = (); # ditto, direct return code + $EXTERN_DECLS = ''; # .globl .text (MIPS only) - $i = 0; - $chkcat[0] = 'misc'; + $i = 0; $chkcat[0] = 'misc'; $chk[0] = ''; while () { next if $T_STABBY && /^\.stab.*${T_US}__stg_split_marker/o; next if $T_STABBY && /^\.stab.*ghc.*c_ID/; next if /${T_PRE_APP}(NO_)?APP/o; - if ( /^\s+/ ) { # most common case first -- a simple line! + next if /^;/ && $TargetPlatform =~ /^hppa/; + + next if /(^$|^\t\.file\t|^ # )/ && $TargetPlatform =~ /^mips-/; + + if ( $TargetPlatform =~ /^mips-/ + && /^\t\.(globl \S+ \.text|comm\t)/ ) { + $EXTERN_DECLS .= $_ unless /(__DISCARD__|\b(PK_|ASSIGN_)(FLT|DBL)\b)/; + + } elsif ( /^\s+/ ) { # most common case first -- a simple line! # duplicated from the bottom $chk[$i] .= $_; + } elsif ( /\.\.ng:$/ && $TargetPlatform =~ /^alpha-/ ) { + # Alphas: Local labels not to be confused with new chunks + $chk[$i] .= $_; + + # NB: all the rest start with a non-space + + } elsif ( $TargetPlatform =~ /^mips-/ + && /^\d+:/ ) { # a funny-looking very-local label + $chk[$i] .= $_; + } elsif ( /$T_CONST_LBL/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'string'; + $chk[++$i] = $_; + $chkcat[$i] = 'literal'; $chksymb[$i] = $1; } elsif ( /^${T_US}__stg_split_marker(\d+)${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'splitmarker'; + $chk[++$i] = $_; + $chkcat[$i] = 'splitmarker'; $chksymb[$i] = $1; } elsif ( /^${T_US}([A-Za-z0-9_]+)_info${T_POST_LBL}$/o ) { $symb = $1; - $chk[++$i] .= $_; - $chkcat[$i] = 'infotbl'; + $chk[++$i] = $_; + $chkcat[$i] = 'infotbl'; $chksymb[$i] = $symb; die "Info table already? $symb; $i\n" if defined($infochk{$symb}); @@ -205,31 +421,31 @@ sub mangle_asm { $infochk{$symb} = $i; } elsif ( /^${T_US}([A-Za-z0-9_]+)_entry${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'slow'; + $chk[++$i] = $_; + $chkcat[$i] = 'slow'; $chksymb[$i] = $1; $slowchk{$1} = $i; } elsif ( /^${T_US}([A-Za-z0-9_]+)_fast\d+${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'fast'; + $chk[++$i] = $_; + $chkcat[$i] = 'fast'; $chksymb[$i] = $1; $fastchk{$1} = $i; } elsif ( /^${T_US}([A-Za-z0-9_]+)_closure${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'closure'; + $chk[++$i] = $_; + $chkcat[$i] = 'closure'; $chksymb[$i] = $1; $closurechk{$1} = $i; } elsif ( /^${T_US}ghc.*c_ID${T_POST_LBL}/o ) { - $chk[++$i] .= $_; + $chk[++$i] = $_; $chkcat[$i] = 'consist'; - } elsif ( /^(___gnu_compiled_c|gcc2_compiled\.)${T_POST_LBL}/o ) { + } elsif ( /^(${T_US}__gnu_compiled_c|gcc2_compiled\.)${T_POST_LBL}/o ) { ; # toss it } elsif ( /^${T_US}ErrorIO_call_count${T_POST_LBL}$/o # HACK!!!! @@ -239,32 +455,37 @@ sub mangle_asm { || /^${T_US}.*_done${T_POST_LBL}$/o # PROF: _module_done || /^${T_US}_module_registered${T_POST_LBL}$/o # PROF: _module_registered ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'data'; + $chk[++$i] = $_; + $chkcat[$i] = 'data'; $chksymb[$i] = ''; + } elsif ( /^([A-Za-z0-9_]+)\s+\.comm/ && $TargetPlatform =~ /^hppa/ ) { + $chk[++$i] = $_; + $chkcat[$i] = 'bss'; + $chksymb[$i] = $1; + } elsif ( /^${T_US}(ret_|djn_)/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; + $chk[++$i] = $_; + $chkcat[$i] = 'misc'; $chksymb[$i] = ''; } elsif ( /^${T_US}vtbl_([A-Za-z0-9_]+)${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'vector'; + $chk[++$i] = $_; + $chkcat[$i] = 'vector'; $chksymb[$i] = $1; $vectorchk{$1} = $i; } elsif ( /^${T_US}([A-Za-z0-9_]+)DirectReturn${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'direct'; + $chk[++$i] = $_; + $chkcat[$i] = 'direct'; $chksymb[$i] = $1; $directchk{$1} = $i; } elsif ( /^${T_US}[A-Za-z0-9_]+_upd${T_POST_LBL}$/o ) { - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; + $chk[++$i] = $_; + $chkcat[$i] = 'misc'; $chksymb[$i] = ''; } elsif ( $TargetPlatform =~ /^i386-.*-solaris2/ @@ -278,20 +499,22 @@ sub mangle_asm { # Haskell, make a call to your own C wrapper, then # put that C wrapper (which calls one of these) in a # plain .c file. WDP 95/12 - $chk[++$i] .= $_; - $chkcat[$i] = 'toss'; + $chk[++$i] = $_; + $chkcat[$i] = 'toss'; $chksymb[$i] = $1; - } elsif ( /^${T_US}[A-Za-z0-9_]/o ) { + } elsif ( /^${T_US}[A-Za-z0-9_]/o + && ( $TargetPlatform !~ /^hppa/ # need to avoid local labels in this case + || /^L\$\d+$/ ) ) { local($thing); chop($thing = $_); print STDERR "Funny global thing?: $_" unless $KNOWN_FUNNY_THING{$thing} || /^${T_US}_(PRIn|PRStart).*${T_POST_LBL}$/o # pointer reversal GC routines - || /^${T_US}CC_.*${T_POST_LBL}$/ # PROF: _CC_ccident - || /^${T_US}_reg.*${T_POST_LBL}$/; # PROF: __reg - $chk[++$i] .= $_; - $chkcat[$i] = 'misc'; + || /^${T_US}CC_.*${T_POST_LBL}$/o # PROF: _CC_ccident + || /^${T_US}_reg.*${T_POST_LBL}$/o; # PROF: __reg + $chk[++$i] = $_; + $chkcat[$i] = 'misc'; $chksymb[$i] = ''; } else { # simple line (duplicated at the top) @@ -309,19 +532,58 @@ sub mangle_asm { # about the whole module before we start spitting # output. - for ($i = 0; $i < $numchks; $i++) { + local($FIRST_MANGLABLE) = ($TargetPlatform =~ /^(alpha-|hppa|mips-)/) ? 1 : 0; + +# print STDERR "first chunk to mangle: $FIRST_MANGLABLE\n"; + + # Alphas: NB: we start meddling at chunk 1, not chunk 0 + # The first ".rdata" is quite magical; as of GCC 2.7.x, it + # spits a ".quad 0" in after the v first ".rdata"; we + # detect this special case (tossing the ".quad 0")! + local($magic_rdata_seen) = 0; + + # HPPAs, MIPSen: also start medding at chunk 1 + + for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) { $c = $chk[$i]; # convenience copy # print STDERR "\nCHK $i (BEFORE) (",$chkcat[$i],"):\n", $c; - # toss all prologue stuff; + # toss all prologue stuff; HPPA is pretty weird + # (see elsewhere) + $c = &mash_hppa_prologue($c) if $TargetPlatform =~ /^hppa/; + # be slightly paranoid to make sure there's # nothing surprising in there if ( $c =~ /--- BEGIN ---/ ) { if (($p, $r) = split(/--- BEGIN ---/, $c)) { - $p =~ s/^\tpushl \%edi\n//; - $p =~ s/^\tpushl \%esi\n//; - $p =~ s/^\tsubl \$\d+,\%esp\n//; + + if ($TargetPlatform =~ /^i386-/) { + $p =~ s/^\tpushl \%edi\n//; + $p =~ s/^\tpushl \%esi\n//; + $p =~ s/^\tsubl \$\d+,\%esp\n//; + } elsif ($TargetPlatform =~ /^m68k-/) { + $p =~ s/^\tlink a6,#-?\d.*\n//; + $p =~ s/^\tmovel d2,sp\@-\n//; + $p =~ s/^\tmovel d5,sp\@-\n//; # SMmark.* only? + $p =~ s/^\tmoveml \#0x[0-9a-f]+,sp\@-\n//; # SMmark.* only? + } elsif ($TargetPlatform =~ /^mips-/) { + # the .frame/.mask/.fmask that we use is the same + # as that produced by GCC for miniInterpret; this + # gives GDB some chance of figuring out what happened + $FRAME = "\t.frame\t\$sp,2168,\$31\n\t.mask\t0x90000000,-4\n\t.fmask\t0x00000000,0\n"; + $p =~ s/^\t\.(frame).*\n/__FRAME__/g; + $p =~ s/^\t\.(mask|fmask).*\n//g; + $p =~ s/^\t\.cprestore.*\n/\t\.cprestore 416\n/; # 16 + 100 4-byte args + $p =~ s/^\tsubu\t\$sp,\$sp,\d+\n//; + $p =~ s/^\tsw\t\$31,\d+\(\$sp\)\n//; + $p =~ s/^\tsw\t\$fp,\d+\(\$sp\)\n//; + $p =~ s/^\tsw\t\$28,\d+\(\$sp\)\n//; + $p =~ s/__FRAME__/$FRAME/; + } else { + print STDERR "$Pgm: unknown prologue mangling? $TargetPlatform\n"; + } + die "Prologue junk?: $p\n" if $p =~ /^\t[^\.]/; # glue together what's left @@ -332,29 +594,71 @@ sub mangle_asm { # toss all epilogue stuff; again, paranoidly if ( $c =~ /--- END ---/ ) { if (($r, $e) = split(/--- END ---/, $c)) { - $e =~ s/^\tret\n//; - $e =~ s/^\tpopl \%edi\n//; - $e =~ s/^\tpopl \%esi\n//; - $e =~ s/^\taddl \$\d+,\%esp\n//; + if ($TargetPlatform =~ /^i386-/) { + $e =~ s/^\tret\n//; + $e =~ s/^\tpopl \%edi\n//; + $e =~ s/^\tpopl \%esi\n//; + $e =~ s/^\taddl \$\d+,\%esp\n//; + } elsif ($TargetPlatform =~ /^m68k-/) { + $e =~ s/^\tunlk a6\n//; + $e =~ s/^\trts\n//; + } elsif ($TargetPlatform =~ /^mips-/) { + $e =~ s/^\tlw\t\$31,\d+\(\$sp\)\n//; + $e =~ s/^\tlw\t\$fp,\d+\(\$sp\)\n//; + $e =~ s/^\taddu\t\$sp,\$sp,\d+\n//; + $e =~ s/^\tj\t\$31\n//; + } else { + print STDERR "$Pgm: unknown epilogue mangling? $TargetPlatform\n"; + } die "Epilogue junk?: $e\n" if $e =~ /^\t[^\.]/; # glue together what's left $c = $r . $e; + $c =~ s/\n\t\n/\n/; # junk blank line } } + # On SPARCs, we don't do --- BEGIN/END ---, we just + # toss the register-windowing save/restore/ret* instructions + # directly: + if ( $TargetPlatform =~ /^sparc-/ ) { + $c =~ s/^\t(save .*|restore|ret|retl)\n//g; + # throw away PROLOGUE comments + $c =~ s/^\t!#PROLOGUE# 0\n\t!#PROLOGUE# 1\n//; + } + + # On Alphas, the prologue mangling is done a little later (below) + # toss all calls to __DISCARD__ - $c =~ s/^\tcall ${T_US}__DISCARD__\n//go; + $c =~ s/^\t(call|jbsr|jal) ${T_US}__DISCARD__\n//go; + + # MIPS: that may leave some gratuitous asm macros around + # (no harm done; but we get rid of them to be tidier) + $c =~ s/^\t\.set\tnoreorder\n\t\.set\tnomacro\n\taddu\t(\S+)\n\t\.set\tmacro\n\t\.set\treorder\n/\taddu\t$1\n/ + if $TargetPlatform =~ /^mips-/; + + # toss stack adjustment after DoSparks + $c =~ s/^(\tjbsr _DoSparks\n)\taddqw #8,sp/$1/g + if $TargetPlatform =~ /^m68k-/; # this looks old... + + if ( $TargetPlatform =~ /^alpha-/ && + ! $magic_rdata_seen && + $c =~ /^\s*\.rdata\n\t\.quad 0\n\t\.align \d\n/ ) { + $c =~ s/^\s*\.rdata\n\t\.quad 0\n\t\.align (\d)\n/\.rdata\n\t\.align $1\n/; + $magic_rdata_seen = 1; + } + + # pick some end-things and move them to the next chunk # pin a funny end-thing on (for easier matching): $c .= 'FUNNY#END#THING'; - # pick some end-things and move them to the next chunk - while ( $c =~ /${T_MOVE_DIRVS}FUNNY#END#THING/o ) { $to_move = $1; - if ( $to_move =~ /${T_COPY_DIRVS}/ && $i < ($numchks - 1) ) { + if ( $i < ($numchks - 1) + && ( $to_move =~ /${T_COPY_DIRVS}/ + || ($TargetPlatform =~ /^hppa/ && $to_move =~ /align/ && $chkcat[$i+1] eq 'literal') )) { $chk[$i + 1] = $to_move . $chk[$i + 1]; # otherwise they're tossed } @@ -362,6 +666,19 @@ sub mangle_asm { $c =~ s/${T_MOVE_DIRVS}FUNNY#END#THING/FUNNY#END#THING/o; } + if ( $TargetPlatform =~ /^alpha-/ && $c =~ /^\t\.ent\s+(\S+)/ ) { + $ent = $1; + # toss all prologue stuff, except for loading gp, and the ..ng address + if (($p, $r) = split(/^\t\.prologue/, $c)) { + if (($keep, $junk) = split(/\.\.ng:/, $p)) { + $c = $keep . "..ng:\n"; + } else { + print STDERR "malformed code block ($ent)?\n" + } + } + $c .= "\t.frame \$30,0,\$26,0\n\t.prologue" . $r; + } + $c =~ s/FUNNY#END#THING//; # print STDERR "\nCHK $i (AFTER) (",$chkcat[$i],"):\n", $c; @@ -369,30 +686,78 @@ sub mangle_asm { $chk[$i] = $c; # update w/ convenience copy } - # print out all the literal strings first + if ( $TargetPlatform =~ /^alpha-/ ) { + # print out the header stuff first + $chk[0] =~ s/^(\t\.file.*)"(ghc\d+\.c)"/$1"$ifile_root.hc"/; + print OUTASM $chk[0]; + + } elsif ( $TargetPlatform =~ /^hppa/ ) { + print OUTASM $chk[0]; + + } elsif ( $TargetPlatform =~ /^mips-/ ) { + $chk[0] = "\t\.file\t1 \"$ifile_root.hc\"\n" . $chk[0]; + + # get rid of horrible "Revision: .*$" strings + local(@lines0) = split(/\n/, $chk[0]); + local($z) = 0; + while ( $z <= $#lines0 ) { + if ( $lines0[$z] =~ /^\t\.byte\t0x24,0x52,0x65,0x76,0x69,0x73,0x69,0x6f$/ ) { + undef($lines0[$z]); + $z++; + while ( $z <= $#lines0 ) { + undef($lines0[$z]); + last if $lines0[$z] =~ /[,\t]0x0$/; + $z++; + } + } + $z++; + } + $chk[0] = join("\n", @lines0); + $chk[0] =~ s/\n\n+/\n/; + print OUTASM $chk[0]; + } + + # print out all the literal strings next for ($i = 0; $i < $numchks; $i++) { - if ( $chkcat[$i] eq 'string' ) { - print OUTASM $T_HDR_string, $chk[$i]; - + if ( $chkcat[$i] eq 'literal' ) { + print OUTASM $T_HDR_literal, $chk[$i]; + print OUTASM "; end literal\n" if $TargetPlatform =~ /^hppa/; # for the splitter + $chkcat[$i] = 'DONE ALREADY'; } } - for ($i = 0; $i < $numchks; $i++) { + # on the HPPA, print out all the bss next + if ( $TargetPlatform =~ /^hppa/ ) { + for ($i = 1; $i < $numchks; $i++) { + if ( $chkcat[$i] eq 'bss' ) { + print OUTASM "\t.SPACE \$PRIVATE\$\n\t.SUBSPA \$BSS\$\n\t.align 4\n"; + print OUTASM $chk[$i]; + + $chkcat[$i] = 'DONE ALREADY'; + } + } + } + + for ($i = $FIRST_MANGLABLE; $i < $numchks; $i++) { # print STDERR "$i: cat $chkcat[$i], symb $chksymb[$i]\n"; next if $chkcat[$i] eq 'DONE ALREADY'; if ( $chkcat[$i] eq 'misc' ) { - print OUTASM $T_HDR_misc; - &print_doctored($chk[$i], 0); + if ($chk[$i] ne '') { + print OUTASM $T_HDR_misc; + &print_doctored($chk[$i], 0); + } } elsif ( $chkcat[$i] eq 'toss' ) { print STDERR "*** NB: TOSSING code for $chksymb[$i] !!! ***\n"; } elsif ( $chkcat[$i] eq 'data' ) { - print OUTASM $T_HDR_data; - print OUTASM $chk[$i]; + if ($chk[$i] ne '') { + print OUTASM $T_HDR_data; + print OUTASM $chk[$i]; + } } elsif ( $chkcat[$i] eq 'consist' ) { if ( $chk[$i] =~ /$T_hsc_cc_PAT/o ) { @@ -401,14 +766,17 @@ sub mangle_asm { $consist =~ s/\//./g; $consist =~ s/-/_/g; $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - print OUTASM $T_HDR_consist, "${consist}${T_POST_LBL}\n"; + print OUTASM $T_HDR_consist, "${consist}${T_POST_LBL}\n" + if $TargetPlatform !~ /^mips-/; # we just don't try in that case } else { print STDERR "Couldn't grok consistency: ", $chk[$i]; } } elsif ( $chkcat[$i] eq 'splitmarker' ) { # we can just re-constitute this one... - print OUTASM "${T_US}__stg_split_marker",$chksymb[$i],"${T_POST_LBL}\n"; + # NB: we emit _three_ underscores no matter what, + # so ghc-split doesn't have to care. + print OUTASM "___stg_split_marker",$chksymb[$i],"${T_POST_LBL}\n"; } elsif ( $chkcat[$i] eq 'closure' || $chkcat[$i] eq 'infotbl' @@ -446,12 +814,33 @@ sub mangle_asm { $c = $chk[$slowchk{$symb}]; if ( defined($fastchk{$symb}) ) { - $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%edx\n\tjmp \*\%edx\n//; - $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%eax\n\tjmp \*\%eax\n//; + if ( $TargetPlatform =~ /^alpha-/ ) { + $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/; + } elsif ( $TargetPlatform =~ /^hppa/ ) { + $c =~ s/^\s+ldil.*\n\s+ldo.*\n\s+bv.*\n(.*\n)?\s+\.EXIT/$1\t.EXIT/; + } elsif ( $TargetPlatform =~ /^i386-/ ) { + $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%edx\n\tjmp \*\%edx\n//; + $c =~ s/^\tmovl \$${T_US}${symb}_fast\d+,\%eax\n\tjmp \*\%eax\n//; + } elsif ( $TargetPlatform =~ /^mips-/ ) { + $c =~ s/^\tjmp \$31,\(\$27\),0\n\t\.align 4\n\t\.end/\t.align 4\n\t.end/; + } elsif ( $TargetPlatform =~ /^m68k-/ ) { + $c =~ s/^\tjmp ${T_US}${symb}_fast\d+.*\n\tnop\n//; + $c =~ s/^\tjmp ${T_US}${symb}_fast\d+.*\n//; + } elsif ( $TargetPlatform =~ /^sparc-/ ) { + $c =~ s/^\tcall ${T_US}${symb}_fast\d+,.*\n\tnop\n//; + $c =~ s/^\tcall ${T_US}${symb}_fast\d+,.*\n(\t[a-z].*\n)/$1/; + } else { + print STDERR "$Pgm: mystery slow-fast dropthrough: $TargetPlatform\n"; + } } - print STDERR "still has jump to fast entry point:\n$c" - if $c =~ /${T_US}${symb}_fast/; # NB: paranoia + if ( $TargetPlatform !~ /^(alpha-|hppa|mips-)/ ) { + # On alphas, hppa: no very good way to look for "dangling" + # references to fast-entry point. + # (questionable re hppa and mips...) + print STDERR "still has jump to fast entry point:\n$c" + if $c =~ /${T_US}${symb}_fast/; # NB: paranoia + } print OUTASM $T_HDR_entry; @@ -462,7 +851,13 @@ sub mangle_asm { # FAST ENTRY POINT if ( defined($fastchk{$symb}) ) { - print OUTASM $T_HDR_fast; + if ( ! defined($slowchk{$symb}) + # ToDo: the || clause can go once we're no longer + # concerned about producing exactly the same output as before + || $TargetPlatform =~ /^(m68k|sparc|i386)-/ + ) { + print OUTASM $T_HDR_fast; + } &print_doctored($chk[$fastchk{$symb}], 0); $chkcat[$fastchk{$symb}] = 'DONE ALREADY'; } @@ -484,6 +879,15 @@ sub mangle_asm { print OUTASM $T_HDR_direct; &print_doctored($chk[$directchk{$symb}], 0); $chkcat[$directchk{$symb}] = 'DONE ALREADY'; + + } elsif ( $TargetPlatform =~ /^alpha-/ ) { + # Alphas: the commented nop is for the splitter, to ensure + # that no module ends with a label as the very last + # thing. (The linker will adjust the label to point + # to the first code word of the next module linked in, + # even if alignment constraints cause the label to move!) + + print OUTASM "\t# nop\n"; } } else { @@ -497,6 +901,31 @@ sub mangle_asm { \end{code} \begin{code} +sub mash_hppa_prologue { # OK, epilogue, too + local($_) = @_; + + # toss all prologue stuff + s/^\s+\.ENTRY[^\0]*--- BEGIN ---/\t.ENTRY/; + + # Lie about our .CALLINFO + s/^\s+\.CALLINFO.*$/\t.CALLINFO NO_CALLS,NO_UNWIND/; + + # Get rid of P' + + s/LP'/L'/g; + s/RP'/R'/g; + + # toss all epilogue stuff + s/^\s+--- END ---[^\0]*\.EXIT/\t.EXIT/; + + # Sorry; we moved the _info stuff to the code segment. + s/_info,DATA/_info,CODE/g; + + return($_); +} +\end{code} + +\begin{code} sub print_doctored { local($_, $need_fallthru_patch) = @_; @@ -631,13 +1060,13 @@ sub print_doctored { # fix _all_ non-local jumps: - s/^\tjmp \*${T_PRE_LLBL_PAT}/\tJMP___SL/go; - s/^\tjmp ${T_PRE_LLBL_PAT}/\tJMP___L/go; + s/^\tjmp \*${T_X86_PRE_LLBL_PAT}/\tJMP___SL/go; + s/^\tjmp ${T_X86_PRE_LLBL_PAT}/\tJMP___L/go; s/^(\tjmp .*\n)/$exit_patch$1/g; # here's the fix... - s/^\tJMP___SL/\tjmp \*${T_PRE_LLBL}/go; - s/^\tJMP___L/\tjmp ${T_PRE_LLBL}/go; + s/^\tJMP___SL/\tjmp \*${T_X86_PRE_LLBL}/go; + s/^\tJMP___L/\tjmp ${T_X86_PRE_LLBL}/go; # fix post-PerformGC wrapper (re-)entries ??? @@ -656,14 +1085,29 @@ sub print_doctored { #= if /^\t(jmp|call) .*\%ecx/; } - # final peephole fix + # final peephole fixes s/^\tmovl \%eax,36\(\%ebx\)\n\tjmp \*36\(\%ebx\)\n/\tmovl \%eax,36\(\%ebx\)\n\tjmp \*\%eax\n/; + s/^\tmovl \$_(.*),(\%e[abcd]x)\n\tjmp \*$2/\tjmp _$1/g; + + # Hacks to eliminate some reloads of Hp. Worth about 5% code size. + # We could do much better than this, but at least it catches about + # half of the unnecessary reloads. + # Note that these will stop working if either: + # (i) the offset of Hp from BaseReg changes from 80, or + # (ii) the register assignment of BaseReg changes from %ebx + + s/^\tmovl 80\(\%ebx\),\%e.x\n\tmovl \$(.*),(-?[0-9]*)\(\%e.x\)\n\tmovl 80\(\%ebx\),\%e(.)x/\tmovl 80\(\%ebx\),\%e$3x\n\tmovl \$$1,$2\(\%e$3x\)/g; + + s/^\tmovl 80\(\%ebx\),\%e(.)x\n\tmovl (.*),\%e(.)x\n\tmovl \%e$3x,(-?[0-9]*\(\%e$1x\))\n\tmovl 80\(\%ebx\),\%e$1x/\tmovl 80\(\%ebx\),\%e$1x\n\tmovl $2,\%e$3x\n\tmovl \%e$3x,$4/g; + + s/^\tmovl 80\(\%ebx\),\%edx((\n\t(movl|addl) .*,((-?[0-9]*\(.*)|(\%e[abc]x)))+)\n\tmovl 80\(\%ebx\),\%edx/\tmovl 80\(\%ebx\),\%edx$1/g; + s/^\tmovl 80\(\%ebx\),\%eax((\n\t(movl|addl) .*,((-?[0-9]*\(.*)|(\%e[bcd]x)))+)\n\tmovl 80\(\%ebx\),\%eax/\tmovl 80\(\%ebx\),\%eax$1/g; # -------------------------------------------------------- # that's it -- print it # - die "Funny jumps?\n$_" if /${T_X86_BADJMP}/o; # paranoia + #die "Funny jumps?\n$_" if /${T_X86_BADJMP}/o; # paranoia print OUTASM $_; @@ -739,37 +1183,64 @@ sub rev_tbl { local($before) = ''; local($label) = ''; + local(@imports) = (); # hppa only local(@words) = (); local($after) = ''; local(@lines) = split(/\n/, $tbl); local($i, $extra, $words_to_pad, $j); - for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t\.long\s+/; $i++) { + for ($i = 0; $i <= $#lines && $lines[$i] !~ /^\t${T_DOT_WORD}\s+/o; $i++) { $label .= $lines[$i] . "\n", - next if $lines[$i] =~ /^[A-Za-z0-9_]+_info:$/ - || $lines[$i] =~ /^\.globl/ - || $lines[$i] =~ /^${T_US}vtbl_\S+:$/; + next if $lines[$i] =~ /^[A-Za-z0-9_]+_info${T_POST_LBL}$/o + || $lines[$i] =~ /^${T_DOT_GLOBAL}/o + || $lines[$i] =~ /^${T_US}vtbl_\S+${T_POST_LBL}$/o; $before .= $lines[$i] . "\n"; # otherwise... } - for ( ; $i <= $#lines && $lines[$i] =~ /^\t\.long\s+/; $i++) { - push(@words, $lines[$i]); + if ( $TargetPlatform !~ /^hppa/ ) { + for ( ; $i <= $#lines && $lines[$i] =~ /^\t${T_DOT_WORD}\s+/o; $i++) { + push(@words, $lines[$i]); + } + } else { # hppa weirdness + for ( ; $i <= $#lines && $lines[$i] =~ /^\s+\.(word|IMPORT)/; $i++) { + if ($lines[$i] =~ /^\s+\.IMPORT/) { + push(@imports, $lines[$i]); + } else { + # We don't use HP's ``function pointers'' + # We just use labels in code space, like normal people + $lines[$i] =~ s/P%//; + push(@words, $lines[$i]); + } + } } + # now throw away the first word (entry code): shift(@words) if $discard1; +# Padding removed to reduce code size and improve performance on Pentiums. +# Simon M. 13/4/96 # for 486-cache-friendliness, we want our tables aligned # on 16-byte boundaries (.align 4). Let's pad: - $extra = ($#words + 1) % 4; - $words_to_pad = ($extra == 0) ? 0 : 4 - $extra; - for ($j = 0; $j < $words_to_pad; $j++) { push(@words, "\t\.long 0"); } +# $extra = ($#words + 1) % 4; +# $words_to_pad = ($extra == 0) ? 0 : 4 - $extra; +# for ($j = 0; $j < $words_to_pad; $j++) { push(@words, "\t${T_DOT_WORD} 0"); } for (; $i <= $#lines; $i++) { $after .= $lines[$i] . "\n"; } - $tbl = $before . join("\n", (reverse @words)) . "\n" . $label . $after; + # Alphas:If we have anonymous text (not part of a procedure), the + # linker may complain about missing exception information. Bleh. + if ( $TargetPlatform =~ /^alpha-/ && $label =~ /^([A-Za-z0-9_]+):$/) { + $before = "\t.ent $1\n" . $before; + $after .= "\t.end $1\n"; + } + + $tbl = $before + . (($TargetPlatform !~ /^hppa/) ? '' : join("\n", @imports) . "\n") + . join("\n", (reverse @words)) . "\n" + . $label . $after; # print STDERR "before=$before\n"; # print STDERR "label=$label\n"; @@ -781,7 +1252,7 @@ sub rev_tbl { \end{code} \begin{code} -sub mini_mangle_asm { +sub mini_mangle_asm_i386 { local($in_asmf, $out_asmf) = @_; &init_TARGET_STUFF(); @@ -804,6 +1275,33 @@ sub mini_mangle_asm { close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); } +\end{code} + +The HP is a major nuisance. The threaded code mangler moved info +tables from data space to code space, but unthreaded code in the RTS +still has references to info tables in data space. Since the HP +linker is very precise about where symbols live, we need to patch the +references in the unthreaded RTS as well. + +\begin{code} +sub mini_mangle_asm_hppa { + local($in_asmf, $out_asmf) = @_; + + open(INASM, "< $in_asmf") + || &tidy_up_and_die(1,"$Pgm: failed to open `$in_asmf' (to read)\n"); + open(OUTASM,"> $out_asmf") + || &tidy_up_and_die(1,"$Pgm: failed to open `$out_asmf' (to write)\n"); + + while () { + s/_info,DATA/_info,CODE/; # Move _info references to code space + s/P%_PR/_PR/; + print OUTASM; + } + + # finished: + close(OUTASM) || &tidy_up_and_die(1,"Failed writing to $out_asmf\n"); + close(INASM) || &tidy_up_and_die(1,"Failed reading from $in_asmf\n"); +} # make "require"r happy... 1; diff --git a/ghc/driver/ghc-iface.lprl b/ghc/driver/ghc-iface.lprl new file mode 100644 index 0000000..5f0fe31 --- /dev/null +++ b/ghc/driver/ghc-iface.lprl @@ -0,0 +1,271 @@ +%************************************************************************ +%* * +\section[Driver-iface-thing]{Interface-file handling} +%* * +%************************************************************************ + +\begin{code} +sub postprocessHiFile { + local($hsc_hi, # The iface info produced by hsc. + $hifile_target, # The name both of the .hi file we + # already have and which we *might* + # replace. + $going_interactive) = @_; + + local($new_hi) = "$Tmp_prefix.hi-new"; + +# print STDERR `$Cat $hsc_hi`; + + &constructNewHiFile($hsc_hi, $hifile_target, $new_hi); + + # run diff if they asked for it + if ($HiDiff_flag && ! $HiOnStdout && ! $going_interactive && -f $hifile_target) { + &run_something("$Cmp -s $hifile_target $new_hi || $Diff $hifile_target $new_hi 1>&2 || exit 0", + "Diff'ing old and new .$HiSuffix files"); # NB: to stderr + } + + # if we produced an interface file "no matter what", + # print what we got on stderr (ToDo: honor -ohi flag) + if ( $HiOnStdout ) { + print STDERR `$Cat $new_hi`; + } else { + &run_something("$Cmp -s $hifile_target $new_hi || ( $Rm $hifile_target && $Cp $new_hi $hifile_target )", + "Replace .$HiSuffix file, if changed"); + } +} +\end{code} + +\begin{code} +sub constructNewHiFile { + local($hsc_hi, # The iface info produced by hsc. + $hifile_target, # Pre-existing .hi filename (if it exists) + $new_hi) = @_; # Filename for new one + + &readHiFile('old',$hifile_target) unless $HiHasBeenRead{'old'} == 1; + &readHiFile('new',$hsc_hi) unless $HiHasBeenRead{'new'} == 1; + + open(NEWHI, "> $new_hi") || &tidy_up_and_die(1,"Can't open $new_hi (write)\n"); + + local($new_module_version) = &calcNewModuleVersion(); + print NEWHI "interface ", $ModuleName{'new'}, " $new_module_version\n"; + + print NEWHI "__usages__\n", $Stuff{'new:usages'} unless $Stuff{'new:usages'} eq ''; + + local(@version_keys) = sort (keys %Version); + local($num_ver_things) = 0; + foreach $v (@version_keys) { + next unless $v =~ /^new:(.*$)/; + last if $num_ver_things >= 1; + $num_ver_things++; + } + + print NEWHI "__versions__\n" unless $num_ver_things < 1; + foreach $v (@version_keys) { + next unless $v =~ /^new:(.*$)/; + $v = $1; + + &printNewItemVersion($v, $new_module_version), "\n"; + } + + print NEWHI "__exports__\n"; + print NEWHI $Stuff{'new:exports'}; + + if ( $Stuff{'new:instance_modules'} ) { + print NEWHI "__instance_modules__\n"; + print NEWHI $Stuff{'new:instance_modules'}; + } + + if ( $Stuff{'new:fixities'} ) { + print NEWHI "__fixities__\n"; + print NEWHI $Stuff{'new:fixities'}; + } + + if ( $Stuff{'new:declarations'} ) { + print NEWHI "__declarations__\n"; + print NEWHI $Stuff{'new:declarations'}; + } + + if ( $Stuff{'new:instances'} ) { + print NEWHI "__instances__\n"; + print NEWHI $Stuff{'new:instances'}; + } + + if ( $Stuff{'new:pragmas'} ) { + print NEWHI "__pragmas__\n"; + print NEWHI $Stuff{'new:pragmas'}; + } + + close(NEWHI) || &tidy_up_and_die(1,"Failed writing to $new_hi\n"); +} +\end{code} + +\begin{code} +%Version = (); +%Decl = (); # details about individual definitions +%Stuff = (); # where we glom things together +%HiExists = ('old',-1, 'new',-1); # 1 <=> definitely exists; 0 <=> doesn't +%HiHasBeenRead = ('old', 0, 'new', 0); +%ModuleVersion = ('old', 0, 'new', 0); + +sub readHiFile { + local($mod, # module to read; can be special tag 'old' + # (old .hi file for module being compiled) or + # 'new' (new proto-.hi file for...) + $hifile) = @_; # actual file to read + + # info about the old version of this module's interface + $HiExists{$mod} = -1; # 1 <=> definitely exists; 0 <=> doesn't + $HiHasBeenRead{$mod} = 0; + $ModuleVersion{$mod} = 0; + $Stuff{"$mod:usages"} = ''; # stuff glommed together + $Stuff{"$mod:exports"} = ''; + $Stuff{"$mod:instance_modules"} = ''; + $Stuff{"$mod:instances"} = ''; + $Stuff{"$mod:fixities"} = ''; + $Stuff{"$mod:declarations"} = ''; + $Stuff{"$mod:pragmas"} = ''; + + if (! -f $hifile) { # no pre-existing .hi file + $HiExists{$mod} = 0; + return(); + } + + open(HIFILE, "< $hifile") || &tidy_up_and_die(1,"Can't open $hifile (read)\n"); + $HiExists{$mod} = 1; + local($now_in) = ''; + hi_line: while () { + next if /^ *$/; # blank line + + # avoid pre-1.3 interfaces +#print STDERR "now_in:$now_in:$_"; + if ( /\{-# GHC_PRAGMA INTERFACE VERSION . #-\}/ ) { + $HiExists{$mod} = 0; + last hi_line; + } + + if ( /^interface ([A-Z]\S*) (\d+)/ ) { + $ModuleName{$mod} = $1; # not sure this is used much... + $ModuleVersion{$mod} = $2; + + } elsif ( /^interface ([A-Z]\S*)/ && $mod eq 'new' ) { # special case: no version + $ModuleName{'new'} = $1; + + } elsif ( /^__([a-z]+)__$/ ) { + $now_in = $1; + + } elsif ( $now_in eq 'usages' && /^(\S+)\s+(\d+)\s+:: (.*)/ ) { + $Stuff{"$mod:usages"} .= $_; # save the whole thing + + } elsif ( $now_in eq 'versions' && /^(\S+) (\d+)/ ) { + local($item) = $1; + local($n) = $2; +#print STDERR "version read:item=$item, n=$n, line=$_"; + $Version{"$mod:$item"} = $n; + + } elsif ( $now_in eq 'versions' && /^(\S+)/ && $mod eq 'new') { # doesn't have versions + local($item) = $1; +#print STDERR "new version read:item=$item, line=$_"; + $Version{"$mod:$item"} = 'y'; # stub value... + + } elsif ( $now_in =~ /^(exports|instance_modules|instances|fixities|pragmas)$/ ) { + $Stuff{"$mod:$1"} .= $_; # just save it up + + } elsif ( $now_in eq 'declarations' ) { # relatively special treatment needed... + $Stuff{"$mod:declarations"} .= $_; # just save it up + + if ( /^[A-Z][A-Za-z0-9_']*\.(\S+)\s+::\s+/ ) { + $Decl{"$mod:$1"} = $_; + + } elsif ( /^type\s+[A-Z][A-Za-z0-9_']*\.(\S+)/ ) { + $Decl{"$mod:$1"} = $_; + + } elsif ( /^(newtype|data)\s+(.*\s+=>\s+)?[A-Z][A-Za-z0-9_']*\.(\S+)\s+/ ) { + $Decl{"$mod:$3"} = $_; + + } elsif ( /class\s+(.*\s+=>\s+)?[A-Z][A-Za-z0-9_']*\.(\S+)\s+.*where\s+\{.*\};/ ) { + $Decl{"$mod:$2"} = $_; # must be wary of => bit matching after "where"... + } elsif ( /class\s+(.*\s+=>\s+)?[A-Z][A-Za-z0-9_']*\.(\S+)\s+/ ) { + $Decl{"$mod:$2"} = $_; + + } else { # oh, well... + print STDERR "$Pgm: decl line didn't match?\n$_"; + } + + } else { + print STDERR "$Pgm:junk old iface line?:section:$now_in:$_"; + } + } + +# foreach $i ( sort (keys %Decl)) { +# print STDERR "$i: ",$Decl{$i}, "\n"; +# } + + close(HIFILE) || &tidy_up_and_die(1,"Failed reading from $hifile\n"); + $HiHasBeenRead{$mod} = 1; +} +\end{code} + +\begin{code} +sub calcNewModuleVersion { + + return(&mv_change(1,'no old .hi file')) if $HiExists{'old'} == 0; + # could use "time()" as initial version; if a module existed, then was deleted, + # then comes back, we don't want the resurrected one to have an + # lower version number than the original (in case there are any + # lingering references to the original in other .hi files). + + local($unchanged_version) = $ModuleVersion{'old'}; # will return one of these two + local($changed_version) = $unchanged_version + 1; + + return(&mv_change($changed_version,'usages changed')) if $Stuff{'old:usages'} ne $Stuff{'new:usages'}; + + foreach $t ( 'exports', 'instance_modules', 'instances', 'fixities', 'declarations', 'pragmas' ) { + return(&mv_change($changed_version,"$t changed")) if $Stuff{"old:$t"} ne $Stuff{"new:$t"}; + } + + return($unchanged_version); +} + +sub mv_change { + local($mv, $str) = @_; + + print STDERR "$Pgm: module version changed to $mv; reason: $str\n"; + return($mv); +} + +sub printNewItemVersion { + local($item, $mod_version) = @_; + + if (! defined($Decl{"new:$item"}) ) { + print STDERR "$item: no decl?! (nothing into __versions__)\n"; + return; + } + + local($idecl) = $Decl{"new:$item"}; + + if (! defined($Decl{"old:$item"})) { + print STDERR "new: $item\n"; + print NEWHI "$item $mod_version\n"; + } elsif ($idecl ne $Decl{"old:$item"}) { + print STDERR "changed: $item\n"; + print NEWHI "$item $mod_version\n"; + } elsif (! defined($Version{"old:$item"}) ) { + print STDERR "$item: no old version?!\n" + } else { + print NEWHI "$item ", $Version{"old:$item"}, "\n"; + } + return; +} +\end{code} + +\begin{code} +sub findHiChanges { + local($hsc_hi, # The iface info produced by hsc. + $hifile_target) = @_; # Pre-existing .hi filename (if it exists) +} +\end{code} + +\begin{code} +# make "require"r happy... +1; +\end{code} diff --git a/ghc/driver/ghc-recomp.lprl b/ghc/driver/ghc-recomp.lprl new file mode 100644 index 0000000..3414605 --- /dev/null +++ b/ghc/driver/ghc-recomp.lprl @@ -0,0 +1,135 @@ +%************************************************************************ +%* * +\section[Driver-recomp-chking]{Recompilation checker} +%* * +%************************************************************************ + +\begin{code} +sub runRecompChkr { + local($ifile, # originating input file + $ifile_hs, # post-unlit, post-cpp, etc., input file + $ifile_root, # input filename minus suffix + $ofile_target,# the output file that we ultimately hope to produce + $hifile_target# the .hi file ... (ditto) + ) = @_; + + ($i_dev,$i_ino,$i_mode,$i_nlink,$i_uid,$i_gid,$i_rdev,$i_size, + $i_atime,$i_mtime,$i_ctime,$i_blksize,$i_blocks) = stat($ifile); + + if ( ! -f $ofile_target ) { + print STDERR "$Pgm:compile:Output file $ofile_target doesn't exist\n"; + return(1); + } + + ($o_dev,$o_ino,$o_mode,$o_nlink,$o_uid,$o_gid,$o_rdev,$o_size, + $o_atime,$o_mtime,$o_ctime,$o_blksize,$o_blocks) = stat(_); # stat info from -f test + + if ( ! -f $hifile_target ) { + print STDERR "$Pgm:compile:Interface file $hifile_target doesn't exist\n"; + return(1); + } + + ($hi_dev,$hi_ino,$hi_mode,$hi_nlink,$hi_uid,$hi_gid,$hi_rdev,$hi_size, + $hi_atime,$hi_mtime,$hi_ctime,$hi_blksize,$hi_blocks) = stat(_); # stat info from -f test + + if ($i_mtime > $o_mtime) { + print STDERR "$Pgm:recompile:Input file $ifile newer than $ofile_target ($i_mtime > $o_mtime)\n"; + return(1); + } + + # OK, let's see what we used last time; if none of it has + # changed, then we don't need to continue with this compilation. + require('ghc-iface.prl') + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-iface.prl (recomp)!\n"); + &tidy_up_and_die(1,"$Pgm:recomp:why has $hifile_target already been read?\n") + if $HiHasBeenRead{'old'} == 1; + + &readHiFile('old',$hifile_target); + %ModUsed = (); + %Used = (); + + foreach $ul ( split(/;\n/, $Stuff{'old:usages'}) ) { + + $ul =~ /^(\S+)\s+(\d+)\s+:: (.*)/ || die "$Pgm: bad old usages line!\n"; + local($mod) = $1; + local($modver) = $2; + local(@thing) = split(/\s+/, $3); + + $ModUsed{$mod} = $modver; + + local($key, $n); + while ( $#thing >= 0 ) { + $key = "$mod:" . $thing[0]; + $n = $thing[1]; + $Used{$key} = $n; + shift @thing; shift @thing; # toss two + } + } + + # see if we can avoid recompilation just by peering at the + # module-version numbers: + + &makeHiMap() unless $HiMapDone; + + local($used_modules_have_changed) = 0; + used_mod: foreach $um ( keys %ModUsed ) { + if ( ! defined($HiMap{$um}) ) { + print STDERR "$Pgm:recompile:interface for used module $um no longer exists\n"; + foreach $hm ( keys %HiMap ) { + print STDERR "$hm ==> ", $HiMap{$hm}, "\n"; + } + return 1; + } else { + if ( $HiHasBeenRead{$um} ) { + print STDERR "$Pgm:very strange that $um.hi has already been read?!?\n" + } else { + &readHiFile($um, $HiMap{$um}); + } + } + if ( $ModUsed{$um} != $ModuleVersion{$um} ) { + print STDERR "used module version: $um: was: ",$ModUsed{$um}, "; is ", $ModuleVersion{$um}, "\n"; + $used_modules_have_changed = 1; + last used_mod; # no point continuing... + } + } + return 0 if ! $used_modules_have_changed; + + # well, some module version has changed, but maybe no + # entity of interest has... +print STDERR "considering used entities...\n"; + local($used_entities_have_changed) = 0; + + used_entity: foreach $ue ( keys %Used ) { + $ue =~ /([A-Z][A-Za-z0-9_']*):(.+)/; + local($ue_m) = $1; + local($ue_n) = $2; + + die "$Pgm:interface for used-entity module $ue_m doesn't exist\n" + if ! defined($HiMap{$ue_m}); + + &readHiFile($ue_m, $HiMap{$ue_m}) unless $HiHasBeenRead{$ue_m}; + # we might not have read it before... + + if ( !defined($Version{$ue}) ) { + print STDERR "No version info for $ue?!\n"; + + } elsif ( $Used{$ue} != $Version{$ue} ) { + print STDERR "$Pgm:recompile: used entity changed: $ue: was version ",$Used{$ue},"; is ", $Version{$ue}, "\n"; + $used_entities_have_changed = 1; + last used_entity; # no point continuing... + } + } + return 0 if ! $used_entities_have_changed; + + print STDERR "ifile $ifile:\t$i_mtime\n"; + print STDERR "ofile $ofile_target:\t$o_mtime\n"; + print STDERR "hifile $hifile_target:\t$hi_mtime\n"; + + return(1); # OK, *recompile* +} +\end{code} + +\begin{code} +# make "require"r happy... +1; +\end{code} diff --git a/ghc/driver/ghc-split.lprl b/ghc/driver/ghc-split.lprl index 00c116e..3a4dadb 100644 --- a/ghc/driver/ghc-split.lprl +++ b/ghc/driver/ghc-split.lprl @@ -9,7 +9,7 @@ sub inject_split_markers { local($hc_file) = @_; unlink("$Tmp_prefix.unmkd"); - local($to_do) = "cp $hc_file $Tmp_prefix.unmkd"; + local($to_do) = "$Cp $hc_file $Tmp_prefix.unmkd"; &run_something($to_do, 'Prepare to number split markers'); open(TMPI, "< $Tmp_prefix.unmkd") || &tidy_up_and_die(1,"$Pgm: failed to open `$Tmp_prefix.unmkd' (to read)\n"); @@ -191,8 +191,8 @@ sub process_asm_block_sparc { if ( $OptimiseC ) { $str =~ s/_?__stg_split_marker.*:\n//; } else { - $str =~ s/(\.text\n\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/\1/; - $str =~ s/(\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/\1/; + $str =~ s/(\.text\n\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/; + $str =~ s/(\t\.align .\n)\t\.global\s+.*_?__stg_split_marker.*\n\t\.proc.*\n/$1/; } # make sure the *.hc filename gets saved; not just ghc*.c (temp name) @@ -226,10 +226,10 @@ sub process_asm_block_sparc { sub process_asm_block_m68k { local($str) = @_; - # strip the marker (ToDo: something special for unregisterized???) + # strip the marker - $str =~ s/(\.text\n\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/\1/; - $str =~ s/(\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/\1/; + $str =~ s/(\.text\n\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/; + $str =~ s/(\t\.even\n)\t\.globl\s+.*_?__stg_split_marker.*\n/$1/; # it seems prudent to stick on one of these: $str = "\.text\n\t.even\n" . $str; @@ -266,7 +266,7 @@ sub process_asm_block_alpha { if ( $OptimiseC ) { $str =~ s/_?__stg_split_marker.*:\n//; } else { - $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/\1/; + $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/; } # remove/record any literal constants defined here @@ -292,7 +292,7 @@ sub process_asm_block_alpha { # Slide the dummy direct return code into the vtbl .ent/.end block, # to keep the label fixed if it's the last thing in a module, and # to avoid having any anonymous text that the linker will complain about - $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n\1/g; + $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g; print STDERR "### STRIPPED BLOCK (alpha):\n$str" if $Dump_asm_splitting_info; @@ -302,10 +302,10 @@ sub process_asm_block_alpha { sub process_asm_block_iX86 { local($str) = @_; - # strip the marker (ToDo: something special for unregisterized???) + # strip the marker - $str =~ s/(\.text\n\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/\1/; - $str =~ s/(\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/\1/; + $str =~ s/(\.text\n\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/; + $str =~ s/(\t\.align .(,0x90)?\n)\.globl\s+.*_?__stg_split_marker.*\n/$1/; # it seems prudent to stick on one of these: $str = "\.text\n\t.align 4\n" . $str; @@ -396,7 +396,7 @@ sub process_asm_block_mips { if ( $OptimiseC ) { $str =~ s/_?__stg_split_marker.*:\n//; } else { - $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/\1/; + $str =~ s/(\t\.align .\n)\t\.globl\s+.*_?__stg_split_marker.*\n\t\.ent.*\n/$1/; } # remove/record any literal constants defined here @@ -422,7 +422,7 @@ sub process_asm_block_mips { # Slide the dummy direct return code into the vtbl .ent/.end block, # to keep the label fixed if it's the last thing in a module, and # to avoid having any anonymous text that the linker will complain about - $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n\1/g; + $str =~ s/(\t\.end [A-Za-z0-9_]+)\n\t# nop/\tnop\n$1/g; $str .= $UNDEFINED_FUNS; # pin on gratuitiously-large amount of info diff --git a/ghc/driver/ghc.lprl b/ghc/driver/ghc.lprl index 8ccef55..09f1bef 100644 --- a/ghc/driver/ghc.lprl +++ b/ghc/driver/ghc.lprl @@ -37,7 +37,7 @@ possible phases of a compilation: For each input file, the phase to START with is determined by the file's suffix: - .lhs literate Haskell: lit2pgm - - .hs illiterate Haskell: hsp + - .hs illiterate Haskell: hsc - .hc C from the Haskell compiler: gcc - .c C not from the Haskell compiler: gcc - .s assembly language: as @@ -56,7 +56,7 @@ option: Other commonly-used options are: - -O An `optimising' package of options, to produce faster code + -O An `optimising' package of compiler flags, for faster code -prof Compile for cost-centre profiling (add -auto for automagic cost-centres on top-level functions) @@ -108,17 +108,19 @@ if (! $ENV{'GLASGOW_HASKELL_ROOT'}) { # good -- death to environment variables $TopPwd = '$(TOP_PWD)'; $InstLibDirGhc = '$(INSTLIBDIR_GHC)'; $InstDataDirGhc = '$(INSTDATADIR_GHC)'; +# $InstSysLibDir = '$(INSTLIBDIR_HSLIBS)'; ToDo ToDo + $InstSysLibDir = '$(TOP_PWD)/hslibs'; } else { $TopPwd = $ENV{'GLASGOW_HASKELL_ROOT'}; - if ( '$(INSTLIBDIR_GHC)' =~ /^\/(local\/fp|usr\/local)(\/.*)/ ) { - $InstLibDirGhc = $ENV{'GLASGOW_HASKELL_ROOT'} . $2; + if ('$(INSTLIBDIR_GHC)' =~ /.*(\/lib\/ghc\/\d\.\d\d\/[^-]-[^-]-[^-]\/.*)/) { + $InstLibDirGhc = $ENV{'GLASGOW_HASKELL_ROOT'} . $1; } else { print STDERR "GLASGOW_HASKELL_ROOT environment variable is set;\nBut can't untangle $(INSTLIBDIR_GHC).\n(Installation error)\n"; exit(1); } - if ( '$(INSTDATADIR_GHC)' =~ /\/(local\/fp|usr\/local)(\/.*)/ ) { + if ('$(INSTDATADIR_GHC)' =~ /.*(\/lib\/ghc\/\d\.\d\d\/.*)/) { $InstDataDirGhc = $ENV{'GLASGOW_HASKELL_ROOT'} . $2; } else { print STDERR "GLASGOW_HASKELL_ROOT environment variable is set;\nBut can't untangle $(INSTDATADIR_GHC).\n(Installation error)\n"; @@ -128,8 +130,6 @@ if (! $ENV{'GLASGOW_HASKELL_ROOT'}) { # good -- death to environment variables $Status = 0; # just used for exit() status $Verbose = ''; -$CoreLint = ''; -$Time = ''; # ToDo: mkworld-ize the timing command # set up signal handler sub quit_upon_signal { &tidy_up_and_die(1, ''); } @@ -138,7 +138,7 @@ $SIG{'QUIT'} = 'quit_upon_signal'; # where to get "require"d .prl files at runtime (poor man's dynamic loading) # (use LIB, not DATA, because we can't be sure of arch-independence) -@INC = ( ( $(INSTALLING) ) ? "$InstLibDirGhc" +@INC = ( ( $(INSTALLING) ) ? $InstLibDirGhc : "$TopPwd/$(CURRENT_DIR)" ); if ( $ENV{'TMPDIR'} ) { # where to make tmp file names @@ -154,7 +154,12 @@ $Unlit = ( $(INSTALLING) ) ? "$InstLibDirGhc/unlit" : "$TopPwd/$(CURRENT_DIR)/$(GHC_UNLIT)"; @Unlit_flags = (); -$Cat = "cat"; +$Cp = '$(CP)'; +$Rm = '$(RM)'; +$Diff = '$(CONTEXT_DIFF)'; +$Cat = 'cat'; +$Cmp = 'cmp'; +$Time = ''; $HsCpp = # but this is re-set to "cat" (after options) if -cpp not seen ( $(INSTALLING) ) ? "$InstLibDirGhc/hscpp" @@ -162,10 +167,6 @@ $HsCpp = # but this is re-set to "cat" (after options) if -cpp not seen @HsCpp_flags = (); $genSPECS_flag = ''; # See ../utils/hscpp/hscpp.prl -$HsP = ( $(INSTALLING) ) ? "$InstLibDirGhc/hsp" - : "$TopPwd/$(CURRENT_DIR)/$(GHC_HSP)"; -@HsP_flags = (); - $HsC = ( $(INSTALLING) ) ? "$InstLibDirGhc/hsc" : "$TopPwd/$(CURRENT_DIR)/$(GHC_HSC)"; @@ -177,10 +178,11 @@ $SysMan = ( $(INSTALLING) ) ? "$InstLibDirGhc/SysMan" # terrible things to cache behavior. $Specific_heap_size = 6 * 1000 * 1000; $Specific_stk_size = 1000 * 1000; -$Scale_sizes_by = 1.0; -$RTS_style = $(GHC_RTS_STYLE); -@HsC_rts_flags = (); +$Scale_sizes_by = 1.0; +@HsC_rts_flags = (); +@HsP_flags = (); # these are the flags destined solely for + # the flex/yacc parser @HsC_flags = (); @HsC_antiflags = (); \end{code} @@ -189,9 +191,10 @@ The optimisations/etc to be done by the compiler are {\em normally} expressed with a \tr{-O} (or \tr{-O2}) flag, or by its absence. \begin{code} -$OptLevel = 0; # no -O == 0; -O == 1; -O2 == 2; -Ofile == 3 -$MinusO2ForC = 0; # set to 1 if -O2 should be given to C compiler +$OptLevel = 0; # no -O == 0; -O == 1; -O2 == 2; -Ofile == 3 +$MinusO2ForC = 0; # set to 1 if -O2 should be given to C compiler $StolenX86Regs = 4; # **HACK*** of the very worst sort +$CoreLint = ''; \end{code} These variables represent parts of the -O/-O2/etc ``templates,'' @@ -202,41 +205,31 @@ $Oopt_UnfoldingUseThreshold = '-fsimpl-uf-use-threshold3'; $Oopt_MaxSimplifierIterations = '-fmax-simplifier-iterations4'; $Oopt_PedanticBottoms = '-fpedantic-bottoms'; # ON by default $Oopt_MonadEtaExpansion = ''; -#OLD:$Oopt_LambdaLift = ''; -$Oopt_AddAutoSccs = ''; $Oopt_FinalStgProfilingMassage = ''; $Oopt_StgStats = ''; $Oopt_SpecialiseUnboxed = ''; $Oopt_DoSpecialise = '-fspecialise'; $Oopt_FoldrBuild = 1; # On by default! -$Oopt_FB_Support = '-fdo-new-occur-anal -fdo-arity-expand'; +$Oopt_FB_Support = '-fdo-arity-expand'; #$Oopt_FoldrBuildWW = 0; # Off by default $Oopt_FoldrBuildInline = '-fdo-inline-foldr-build'; \end{code} Things to do with C compilers/etc: \begin{code} -$CcUnregd = '$(GHC_DEBUG_HILEV_ASM)'; # our high-level assembler (non-optimising) -$CcRegd = '$(GHC_OPT_HILEV_ASM)'; # our high-level assembler (optimising) -$GccAvailable = $(GHC_GCC_IS_AVAILABLE); # whether GCC avail or not for optimising - +$CcRegd = 'gcc'; @CcBoth_flags = ('-S'); # flags for *any* C compilation @CcInjects = (); -# non-registerizing flags: those for all files, those only for .c files; those only for .hc files -@CcUnregd_flags = ( $GccAvailable ) ? ('-ansi', '-pedantic') : (); -@CcUnregd_flags_c = (); -@CcUnregd_flags_hc= (); - -# ditto; but for registerizing (we must have GCC for this) +# GCC flags: those for all files, those only for .c files; those only for .hc files @CcRegd_flags = ('-ansi', '-D__STG_GCC_REGS__', '-D__STG_TAILJUMPS__'); @CcRegd_flags_c = (); @CcRegd_flags_hc = (); -$As = ''; # assembler is normally the same pgm as used for C compilation +$As = ''; # "assembler" is normally GCC @As_flags = (); -$Lnkr = ''; # linker is normally the same pgm as used for C compilation +$Lnkr = ''; # "linker" is normally GCC @Ld_flags = (); # 'nm' is used for consistency checking (ToDo: mk-world-ify) @@ -283,7 +276,7 @@ $BuildTag = ''; # default is sequential build w/ Appel-style GC %BuildDescr = ('', 'normal sequential', '_p', 'profiling', '_t', 'ticky-ticky profiling', - '_u', 'unregisterized (using portable C only)', +#OLD: '_u', 'unregisterized (using portable C only)', '_mc', 'concurrent', '_mr', 'profiled concurrent', '_mt', 'ticky concurrent', @@ -341,12 +334,15 @@ $BuildTag = ''; # default is sequential build w/ Appel-style GC '_p', 'push(@HsC_flags, \'-fscc-profiling\'); push(@CcBoth_flags, \'-DPROFILING\');', + #and maybe ... + #push(@CcBoth_flags, '-DPROFILING_DETAIL_COUNTS'); + # ticky-ticky sequential '_t', 'push(@HsC_flags, \'-fticky-ticky\'); push(@CcBoth_flags, \'-DTICKY_TICKY\');', - # unregisterized (ToDo????) - '_u', '', +#OLD: # unregisterized (ToDo????) +# '_u', '', # concurrent '_mc', '$StkChkByPageFaultOK = 0; @@ -374,7 +370,8 @@ $BuildTag = ''; # default is sequential build w/ Appel-style GC # GranSim '_mg', '$StkChkByPageFaultOK = 0; - push(@HsC_flags, \'-fconcurrent\'); + push(@HsC_flags, \'-fconcurrent\', \'-fgransim\'); + push(@HsCpp_flags,\'-D__GRANSIM__\', \'-DGRAN\'); push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DGRAN\');', '_2s', 'push (@CcBoth_flags, \'-DGC2s\');', @@ -409,17 +406,17 @@ require special handling. @SysImport_dir = ( $(INSTALLING) ) ? ( "$InstDataDirGhc/imports" ) : ( "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/prelude" - ); + , "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/required" ); -$ghc_version_info = $(PROJECTVERSION) * 100; -$haskell1_version = 2; # i.e., Haskell 1.2 -@Cpp_define = (); +$GhcVersionInfo = 201; # ToDo: int ($(PROJECTVERSION) * 100); +$Haskell1Version = 3; # i.e., Haskell 1.3 +@Cpp_define = (); @UserLibrary_dir= (); #-L things;... @UserLibrary = (); #-l things asked for by the user @SysLibrary_dir = ( ( $(INSTALLING) ) #-syslib things supplied by the system - ? "$InstLibDirGhc" + ? $InstLibDirGhc : ("$TopPwd/$(CURRENT_DIR)/$(GHC_RUNTIMESRC)", "$TopPwd/$(CURRENT_DIR)/$(GHC_RUNTIMESRC)/gmp", "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)") @@ -440,35 +437,28 @@ start with. Linking is weird and kept track of separately. Here are the initial defaults applied to all files: \begin{code} -$Do_lit2pgm = 1; -$Do_hscpp = 1; # but we run 'cat' by default (see after arg check) $Cpp_flag_set = 0; # (hack) $Only_preprocess_C = 0; # pretty hackish -$ProduceHi = 1; # but beware magical value "2"! (hack) $PostprocessCcOutput = 0; -$HiDiff_flag= 0; # native code-gen or via C? $HaveNativeCodeGen = $(GHC_WITH_NATIVE_CODEGEN); -$ProduceS = ''; -if ($HaveNativeCodeGen) { - if ($TargetPlatform =~ /^(alpha|sparc)-/) { - $ProduceS = $TargetPlatform; - } -} -$ProduceC = ($ProduceS) ? 0 : 1; +$HscOut = '-C='; # '-C=' ==> .hc output; '-S=' ==> .s output; '-N=' ==> neither +$HscOut = '-S=' + if $HaveNativeCodeGen && $TargetPlatform =~ /^(alpha|sparc|i386)-/; +$ProduceHi = '-hifile='; +$HiOnStdout = 0; +$HiDiff_flag = 0; $CollectingGCstats = 0; $CollectGhcTimings = 0; -$RegisteriseC = ''; # set to 'o', if using optimised C code (only if avail) - # or if generating equiv asm code $DEBUGging = ''; # -DDEBUG and all that it entails (um... not really) $PROFing = ''; # set to p or e if profiling $PROFgroup = ''; # set to group if an explicit -Ggroup specified $PROFauto = ''; # set to relevant hsc flag if -auto or -auto-all $PROFcaf = ''; # set to relevant hsc flag if -caf-all -#UNUSED:$PROFdict = ''; # set to relevant hsc flag if -dict-all $PROFignore_scc = ''; # set to relevant parser flag if explicit sccs ignored +$UNPROFscc_auto = ''; # set to relevant hsc flag if forcing auto sccs without profiling $TICKYing = ''; # set to t if compiling for ticky-ticky profiling $PARing = ''; # set to p if compiling for PAR $CONCURing = ''; # set to c if compiling for CONCURRENT @@ -479,23 +469,22 @@ $Specific_output_file = ''; # set by -o ; "-" for stdout $Specific_hi_file = ''; # set by -ohi ; "-" for stdout $Specific_dump_file = ''; # set by -odump ; "-" for stdout $Using_dump_file = 0; -$Osuffix = '.o'; -$HiSuffix = '.hi'; -$Do_hsp = 2; # 1 for "old" parser; 2 for "new" parser (in hsc) -$Do_hsc = 1; +$Osuffix = ''; # default: use the normal suffix for that kind of output +$HiSuffix = 'hi'; +$SysHiSuffix= 'hi'; +$Do_recomp_chkr = 0; # don't use the recompilatio checker unless asked $Do_cc = -1; # a MAGIC indeterminate value; will be set to 1 or 0. $Do_as = 1; $Do_lnkr = 1; $Keep_hc_file_too = 0; $Keep_s_file_too = 0; -$CompilingPrelude = 0; +$UseGhcInternals = 0; # if 1, may use GHC* modules $SplitObjFiles = 0; $NoOfSplitFiles = 0; $Dump_parser_output = 0; $Dump_raw_asm = 0; -$Dump_asm_insn_counts = 0; -$Dump_asm_globals_info = 0; $Dump_asm_splitting_info = 0; +$NoImplicitPrelude = 0; # and the list of files @Input_file = (); @@ -516,16 +505,16 @@ $LinkChk = 1; # set to 0 if the link check should *not* be done # major & minor version numbers; major numbers must always agree; # minor disagreements yield a warning. -$HsC_major_version = 29; +$HsC_major_version = 30; $HsC_minor_version = 0; -$Cc_major_version = 33; +$Cc_major_version = 35; $Cc_minor_version = 0; # options: these must always agree $HsC_consist_options = ''; # we record, in this order: # Build tag; debugging? $Cc_consist_options = ''; # we record, in this order: - # Build tag; debugging? registerised? + # Build tag; debugging? \end{code} %************************************************************************ @@ -556,11 +545,10 @@ if (grep(/^-user-prelude$/, @ARGV)) { @ARGV); unshift(@ARGV, - '-prelude', + '-fcompiling-ghc-internals=???', # ToDo!!!! '-O', '-fshow-pragma-name-errs', '-fshow-import-specs', - '-fomit-reexported-instances', '-fglasgow-exts', '-genSPECS', '-DUSE_FOLDR_BUILD', @@ -580,25 +568,25 @@ arg: while($_ = $ARGV[0]) { /^-v$/ && do { $Verbose = '-v'; $Time = 'time'; next arg; }; #---------- what phases are to be run ---------------------------------- + /^-short$/ && do { $Do_recomp_chkr = 1; next arg; }; + /^-cpp$/ && do { $Cpp_flag_set = 1; next arg; }; # change the global default: # we won't run cat; we'll run the real thing - /^-C$/ && do { $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0; - $ProduceC = 1; $ProduceS = ''; + /^-C$/ && do { $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0; $HscOut = '-C='; next arg; }; # stop after generating C - /^-noC$/ && do { $ProduceC = 0; $ProduceS = ''; $ProduceHi = 0; + /^-noC$/ && do { $HscOut = '-N='; $ProduceHi = '-nohifile='; $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0; next arg; }; # leave out actual C generation (debugging) [also turns off interface gen] - /^-hi$/ && do { $ProduceHi = 2; next arg; }; + /^-hi$/ && do { $HiOnStdout = 1; $ProduceHi = '-hifile='; next arg; }; # _do_ generate an interface; usually used as: -noC -hi - # NB: magic value "2" for $ProduceHi (hack) - /^-nohi$/ && do { $ProduceHi = 0; next arg; }; + /^-nohi$/ && do { $ProduceHi = '-nohifile='; next arg; }; # don't generate an interface (even if generating C) /^-hi-diffs$/ && do { $HiDiff_flag = 1; next arg; }; @@ -620,24 +608,6 @@ arg: while($_ = $ARGV[0]) { /^-no-link-chk$/ && do { $LinkChk = 0; next arg; }; # don't do consistency-checking after a link - # generate code for a different target architecture; e.g., m68k - # ToDo: de-Glasgow-ize & probably more... -# OLD: -# /^-target$/ && do { $TargetPlatform = &grab_arg_arg('-target', ''); -# if ($TargetPlatform ne $HostPlatform) { -# if ( $TargetPlatform =~ /^m68k-/ ) { -# $CcUnregd = $CcRegd = 'gcc-m68k'; -# } else { -# print STDERR "$Pgm: Can't handle -target $TargetPlatform\n"; -# $Status++; -# } -# } -# next arg; }; - - /^-unregisteri[sz]ed$/ && do { $RegisteriseC = 'no'; - $ProduceC = 1; $ProduceS = ''; # via C, definitely - next arg; }; - /^-tmpdir$/ && do { $Tmp_prefix = &grab_arg_arg('-tmpdir', ''); $Tmp_prefix = "$Tmp_prefix/ghc$$"; $ENV{'TMPDIR'} = $Tmp_prefix; # for those who use it... @@ -650,6 +620,13 @@ arg: while($_ = $ARGV[0]) { # "-o -" sends it to stdout # if has a directory component, that dir must already exist + /^-odir$/ && do { $Specific_output_dir = &grab_arg_arg('-odir', ''); + if (! -d $Specific_output_dir) { + print STDERR "$Pgm: -odir: no such directory: $Specific_output_dir\n"; + $Status++; + } + next arg; }; + /^-o$/ && do { $Specific_output_file = &grab_arg_arg('-o', ''); if ($Specific_output_file ne '-' && $Specific_output_file =~ /(.*)\/[^\/]*$/) { @@ -661,6 +638,13 @@ arg: while($_ = $ARGV[0]) { } next arg; }; + /^-osuf$/ && do { $Osuffix = &grab_arg_arg('-osuf', ''); + if ($Osuffix =~ /\./ ) { + print STDERR "$Pgm: -osuf suffix shouldn't contain a .\n"; + $Status++; + } + next arg; }; + # -ohi ; send the interface to ; "-ohi -" to send to stdout /^-ohi$/ && do { $Specific_hi_file = &grab_arg_arg('-ohi', ''); if ($Specific_hi_file ne '-' @@ -673,6 +657,20 @@ arg: while($_ = $ARGV[0]) { } next arg; }; + /^-hisuf$/ && do { $HiSuffix = &grab_arg_arg('-hisuf', ''); + if ($HiSuffix =~ /\./ ) { + print STDERR "$Pgm: -hisuf suffix shouldn't contain a .\n"; + $Status++; + } + next arg; }; + /^-hisuf-prelude$/ && do { # as esoteric as they come... + $SysHiSuffix = &grab_arg_arg('-hisuf-prelude', ''); + if ($SysHiSuffix =~ /\./ ) { + print STDERR "$Pgm: -hisuf-prelude suffix shouldn't contain a .\n"; + $Status++; + } + next arg; }; + /^-odump$/ && do { $Specific_dump_file = &grab_arg_arg('-odump', ''); if ($Specific_dump_file =~ /(.*)\/[^\/]*$/) { local($dir_part) = $1; @@ -683,23 +681,6 @@ arg: while($_ = $ARGV[0]) { } next arg; }; - /^-odir$/ && do { $Specific_output_dir = &grab_arg_arg('-odir', ''); - if (! -d $Specific_output_dir) { - print STDERR "$Pgm: -odir: no such directory: $Specific_output_dir\n"; - $Status++; - } - next arg; }; - - /^-osuf$/ && do { $Osuffix = &grab_arg_arg('-osuf', ''); next arg; }; - /^-hisuf$/ && do { $HiSuffix = &grab_arg_arg('-hisuf', ''); - push(@HsP_flags, "-h$HiSuffix"); - next arg; }; - - /^-hisuf-prelude$/ && do { # as esoteric as they come... - local($suffix) = &grab_arg_arg('-hisuf-prelude', ''); - push(@HsP_flags, "-g$suffix"); - next arg; }; - #-------------- scc & Profiling Stuff ---------------------------------- /^-prof$/ && do { $PROFing = 'p'; next arg; }; # profiling -- details later! @@ -717,19 +698,22 @@ arg: while($_ = $ARGV[0]) { $PROFcaf = '-fauto-sccs-on-individual-cafs'; next arg; }; -# UNUSED: -# /^-dict-all/ && do { # generate individual SCC annotations on dictionaries -# $PROFdict = '-fauto-sccs-on-individual-dicts'; -# next arg; }; - /^-ignore-scc$/ && do { # forces ignore of scc annotations even if profiling $PROFignore_scc = '-W'; next arg; }; - /^-G(.*)$/ && do { push(@HsC_flags, $_); # set group for cost centres + /^-G(.*)$/ && do { push(@HsC_flags, "-G=$1"); # set group for cost centres next arg; }; + /^-unprof-scc-auto/ && do { + # generate auto SCCs on top level bindings when not profiling + # used to measure optimisation effects of presence of sccs + $UNPROFscc_auto = ( /-all/ ) + ? '-fauto-sccs-on-all-toplevs' + : '-fauto-sccs-on-exported-toplevs'; + next arg; }; + #--------- ticky/concurrent/parallel ----------------------------------- # we sort out the details a bit later on @@ -816,12 +800,12 @@ arg: while($_ = $ARGV[0]) { /^-syslib(.*)/ && do { local($syslib) = &grab_arg_arg('-syslib',$1); print STDERR "$Pgm: no such system library (-syslib): $syslib\n", - $Status++ unless $syslib =~ /^(hbc|ghc|contrib)$/; + $Status++ unless $syslib =~ /^(hbc|ghc|posix|contrib)$/; unshift(@SysImport_dir, $(INSTALLING) - ? "$InstDataDirGhc/imports/$syslib" - : "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/$syslib"); + ? "$InstSysLibDir/$syslib/imports" + : "$TopPwd/hslibs/$syslib/src"); unshift(@SysLibrary, ('-lHS' . $syslib )); @@ -836,10 +820,8 @@ arg: while($_ = $ARGV[0]) { # these change what executable is run for each phase: /^-pgmL(.*)$/ && do { $Unlit = $1; next arg; }; /^-pgmP(.*)$/ && do { $HsCpp = $1; next arg; }; - /^-pgmp(.*)$/ && do { $HsP = $1; next arg; }; /^-pgmC(.*)$/ && do { $HsC = $1; next arg; }; - /^-pgmcO(.*)$/ && do { $CcRegd = $1; next arg; }; - /^-pgmc(.*)$/ && do { $CcUnregd = $1; next arg; }; + /^-pgmcO?(.*)$/ && do { $CcRegd = $1; next arg; }; # the O? for back compat /^-pgma(.*)$/ && do { $As = $1; next arg; }; /^-pgml(.*)$/ && do { $Lnkr = $1; next arg; }; @@ -847,15 +829,8 @@ arg: while($_ = $ARGV[0]) { # these allow arbitrary option-strings to go to any phase: /^-optL(.*)$/ && do { push(@Unlit_flags, $1); next arg; }; /^-optP(.*)$/ && do { push(@HsCpp_flags, $1); next arg; }; - /^-optp(.*)$/ && do { push(@HsP_flags, $1); next arg; }; /^-optCrts(.*)$/&& do { push(@HsC_rts_flags, $1); next arg; }; /^-optC(.*)$/ && do { push(@HsC_flags, $1); next arg; }; - /^-optcNhc(.*)$/ && do { push(@CcUnregd_flags_hc,$1); next arg; }; - /^-optcNc(.*)$/ && do { push(@CcUnregd_flags_c,$1); next arg; }; - /^-optcN(.*)$/ && do { push(@CcUnregd_flags, $1); next arg; }; - /^-optcOhc(.*)$/&& do { push(@CcRegd_flags_hc,$1); next arg; }; - /^-optcOc(.*)$/ && do { push(@CcRegd_flags_c, $1); next arg; }; - /^-optcO(.*)$/ && do { push(@CcRegd_flags, $1); next arg; }; /^-optc(.*)$/ && do { push(@CcBoth_flags, $1); next arg; }; /^-opta(.*)$/ && do { push(@As_flags, $1); next arg; }; /^-optl(.*)$/ && do { push(@Ld_flags, $1); next arg; }; @@ -868,46 +843,27 @@ arg: while($_ = $ARGV[0]) { $genSPECS_flag = $_; next arg; }; - #---------- Haskell parser (hsp) --------------------------------------- - /^-ddump-parser$/ && do { $Dump_parser_output = 1; next arg; }; - #---------- post-Haskell "assembler"------------------------------------ - /^-ddump-raw-asm$/ && do { $Dump_raw_asm = 1; next arg; }; - /^-ddump-asm-insn-counts$/ && do { $Dump_asm_insn_counts = 1; next arg; }; - /^-ddump-asm-globals-info$/ && do { $Dump_asm_globals_info = 1; next arg; }; - + /^-ddump-raw-asm$/ && do { $Dump_raw_asm = 1; next arg; }; /^-ddump-asm-splitting-info$/ && do { $Dump_asm_splitting_info = 1; next arg; }; #---------- Haskell compiler (hsc) ------------------------------------- -# possibly resurrect LATER -# /^-fspat-profiling$/ && do { push(@HsC_flags, '-fticky-ticky'); -# $ProduceS = ''; $ProduceC = 1; # must use C compiler -# push(@CcBoth_flags, '-DDO_SPAT_PROFILING'); -# push(@CcBoth_flags, '-fno-schedule-insns'); # not essential -# next arg; }; - /^-keep-hc-files?-too$/ && do { $Keep_hc_file_too = 1; next arg; }; /^-keep-s-files?-too$/ && do { $Keep_s_file_too = 1; next arg; }; - /^-fhaskell-1\.3$/ && do { $haskell1_version = 3; - push(@HsP_flags, '-3'); - push(@HsC_flags, $_); - $TopClosureFile =~ s/TopClosureXXXX/TopClosure13XXXX/; - unshift(@SysImport_dir, - $(INSTALLING) - ? "$InstDataDirGhc/imports/haskell-1.3" - : "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/haskell-1.3"); + /^-fhaskell-1\.3$/ && do { next arg; }; # a no-op right now - unshift(@SysLibrary, '-lHS13'); + /^-fignore-interface-pragmas$/ && do { push(@HsC_flags, $_); next arg; }; - next arg; }; + /^-fno-implicit-prelude$/ && do { $NoImplicitPrelude= 1; push(@HsC_flags, $_); next arg; }; - /^-fno-implicit-prelude$/ && do { push(@HsP_flags, '-P'); next arg; }; - /^-fignore-interface-pragmas$/ && do { push(@HsP_flags, '-p'); next arg; }; + # ToDo: rename to -fcompiling-ghc-internals= + /^-fcompiling-ghc-internals(.*)/ && do { local($m) = &grab_arg_arg('-fcompiling-ghc-internals',$1); + push(@HsC_flags, "-fcompiling-ghc-internals=$m"); + next arg; }; - /^-prelude$/ && do { $CompilingPrelude = 1; - push(@HsC_flags, $_); next arg; }; + /^-fusing-ghc-internals$/ && do { $UsingGhcInternals = 1; next arg; }; /^-user-prelude-force/ && do { # ignore if not -user-prelude next arg; }; @@ -916,37 +872,36 @@ arg: while($_ = $ARGV[0]) { local($sname) = &grab_arg_arg('-split-objs', $1); $sname =~ s/ //g; # no spaces - if ( $TargetPlatform =~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/ ) { + if ( $TargetPlatform !~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/ ) { + $SplitObjFiles = 0; + print STDERR "WARNING: don't know how to split objects on this platform: $TargetPlatform\n`-split-objs' option ignored\n"; + } else { $SplitObjFiles = 1; - $ProduceS = ''; - $ProduceC = 1; + $HscOut = '-C='; - push(@HsC_flags, "-fglobalise-toplev-names$sname"); + push(@HsC_flags, "-fglobalise-toplev-names=$sname"); push(@CcBoth_flags, '-DUSE_SPLIT_MARKERS'); require('ghc-split.prl') || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-split.prl!\n"); - } else { - $SplitObjFiles = 0; - print STDERR "WARNING: don't know how to split objects on this platform: $TargetPlatform\n`-split-objs' option ignored\n"; } next arg; }; /^-f(hide-builtin-names|min-builtin-names)$/ && do { push(@HsC_flags, $_); - push(@HsP_flags, '-P'); # don't read Prelude.hi - push(@HsP_flags, '-N'); # allow foo# names +# push(@HsC_flags, '-fno-implicit-prelude'); # don't read Prelude.hi +# push(@HsP_flags, '-N'); # allow foo# names next arg; }; - /^-f(glasgow-exts|hide-builtin-instances)$/ + /^-fglasgow-exts$/ && do { push(@HsC_flags, $_); push(@HsP_flags, '-N'); # push(@HsC_flags, '-fshow-import-specs'); - if ( ! $(INSTALLING) ) { - unshift(@SysImport_dir, - "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/glaExts"); - } +# if ( ! $(INSTALLING) ) { +# unshift(@SysImport_dir, +# "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/glaExts"); +# } next arg; }; /^-fspeciali[sz]e-unboxed$/ @@ -954,18 +909,16 @@ arg: while($_ = $ARGV[0]) { $Oopt_SpecialiseUnboxed = '-fspecialise-unboxed'; next arg; }; /^-fspeciali[sz]e$/ - && do { $Oopt_DoSpecialise = '-fspecialise'; - next arg; }; + && do { $Oopt_DoSpecialise = '-fspecialise'; next arg; }; /^-fno-speciali[sz]e$/ - && do { $Oopt_DoSpecialise = ''; - next arg; }; + && do { $Oopt_DoSpecialise = ''; next arg; }; # Now the foldr/build options, which are *on* by default (for -O). /^-ffoldr-build$/ && do { $Oopt_FoldrBuild = 1; - $Oopt_FB_Support = '-fdo-new-occur-anal -fdo-arity-expand'; + $Oopt_FB_Support = '-fdo-arity-expand'; #print "Yes F/B\n"; next arg; }; @@ -991,16 +944,10 @@ arg: while($_ = $ARGV[0]) { # && do { $Oopt_FoldrBuildWW = 1; next arg; }; - /^-fasm-(.*)$/ && do { $ProduceS = $1; $ProduceC = 0; # force using nativeGen - push(@HsC_flags, $_); # if from the command line - next arg; }; + # --------------- - /^-fvia-C$/ && do { $ProduceS = ''; $ProduceC = 1; # force using C compiler - next arg; }; - - /^-f(no-)?omit-frame-pointer$/ && do { - unshift(@CcBoth_flags, ( $_ )); - next arg; }; + /^-fasm-(.*)$/ && do { $HscOut = '-S='; next arg; }; # force using nativeGen + /^-fvia-C$/ && do { $HscOut = '-C='; next arg; }; # force using C compiler # --------------- @@ -1027,15 +974,12 @@ arg: while($_ = $ARGV[0]) { if ($num < 2 || $num > 8) { die "Bad experimental flag: $_\n"; } else { - $ProduceS = ''; $ProduceC = 1; # force using C compiler + $HscOut = '-C='; # force using C compiler push(@HsC_flags, "$what$num"); push(@CcRegd_flags, "-D__STG_REGS_AVAIL__=$num"); } next arg; }; -# /^-flambda-lift$/ # so Simon can do some testing; ToDo:rm -# && do { $Oopt_LambdaLift = $_; next arg; }; - # --------------- /^-fno-(.*)$/ && do { push(@HsC_antiflags, "-f$1"); @@ -1059,27 +1003,8 @@ arg: while($_ = $ARGV[0]) { $StolenX86Regs = $1; next arg; }; - /^-mtoggle-sp-mangling/ && do { # for iX86 boxes only; for RTS only - print STDERR "$Pgm: warning: -mtoggle-sp-mangling is no longer supported\n"; -# $SpX86Mangling = 1 - $SpX86Mangling; - next arg; }; - #*************** ... and lots of debugging ones (form: -d* ) - /^-darity-checks$/ && do { - push(@HsC_flags, $_); - push(@CcBoth_flags, '-D__DO_ARITY_CHKS__'); - next arg; }; - /^-darity-checks-C-only$/ && do { - # so we'll have arity-checkable .hc files - # should we decide we need them later... - push(@HsC_flags, '-darity-checks'); - next arg; }; - /^-dno-stk-checks$/ && do { - push(@HsC_flags, '-dno-stk-chks'); - push(@CcBoth_flags, '-D__OMIT_STK_CHKS__'); - next arg; }; - # -d(no-)core-lint is done this way so it is turn-off-able. /^-dcore-lint/ && do { $CoreLint = '-dcore-lint'; next arg; }; /^-dno-core-lint/ && do { $CoreLint = ''; next arg; }; @@ -1093,9 +1018,6 @@ arg: while($_ = $ARGV[0]) { #*************** ... and now all these -R* ones for its runtime system... - /^-Rhbc$/ && do { $RTS_style = 'hbc'; next arg; }; - /^-Rghc$/ && do { $RTS_style = 'ghc'; next arg; }; - /^-Rscale-sizes?(.*)/ && do { $Scale_sizes_by = &grab_arg_arg('-Rscale-sizes', $1); next arg; }; @@ -1149,11 +1071,6 @@ arg: while($_ = $ARGV[0]) { /^-Rghc-timing/ && do { $CollectGhcTimings = 1; next arg; }; #---------- C high-level assembler (gcc) ------------------------------- -# OLD: and dangerous -# /^-g$/ && do { push(@CcBoth_flags, $_); next arg; }; -# /^-(p|pg)$/ && do { push(@CcBoth_flags, $_); push(@Ld_flags, $_); next arg; }; -# /^-(fpic|fPIC)$/ && do { push(@CcBoth_flags, $_); push(@As_flags, $_); next arg; }; - /^-(Wall|ansi|pedantic)$/ && do { push(@CcBoth_flags, $_); next arg; }; # -dgcc-lint is a useful way of making GCC very fussy. @@ -1176,20 +1093,14 @@ arg: while($_ = $ARGV[0]) { #---------- mixed cc and linker magic ---------------------------------- # this optimisation stuff is finally sorted out later on... -# /^-O0$/ && do { # turn all optimisation *OFF* -# $OptLevel = -1; -# $ProduceS = ''; $ProduceC = 1; # force use of C compiler -# next arg; }; - /^-O2-for-C$/ && do { $MinusO2ForC = 1; next arg; }; /^-O[1-2]?$/ && do { +# print STDERR "$Pgm: NOTE: this version of GHC doesn't support -O or -O2\n"; local($opt_lev) = ( /^-O2$/ ) ? 2 : 1; # max 'em $OptLevel = ( $opt_lev > $OptLevel ) ? $opt_lev : $OptLevel; - if ( $OptLevel == 2 ) { # force use of C compiler - $ProduceS = ''; $ProduceC = 1; - } + $HscOut = '-C=' if $OptLevel == 2; # force use of C compiler next arg; }; /^-Onot$/ && do { $OptLevel = 0; next arg; }; # # set it to @@ -1278,17 +1189,20 @@ if ($Specific_output_dir ne '' && $Specific_output_file ne '') { if ( ! $PROFing ) { # warn about any scc exprs found (in case scc used as identifier) push(@HsP_flags, '-W'); -} else { - $Oopt_AddAutoSccs = '-fadd-auto-sccs' if $PROFauto; - $Oopt_FinalStgProfilingMassage = '-fmassage-stg-for-profiling'; + # add -auto sccs even if not profiling ! + push(@HsC_flags, $UNPROFscc_auto) if $UNPROFscc_auto; + +} else { push(@HsC_flags, $PROFauto) if $PROFauto; push(@HsC_flags, $PROFcaf) if $PROFcaf; -#UNUSED: push(@HsC_flags, $PROFdict) if $PROFdict; + #push(@HsC_flags, $PROFdict) if $PROFdict; + + $Oopt_FinalStgProfilingMassage = '-fmassage-stg-for-profiling'; push(@HsP_flags, (($PROFignore_scc) ? $PROFignore_scc : '-S')); - if ($SplitObjFiles && ! $CompilingPrelude) { + if ( $SplitObjFiles ) { # can't split with cost centres -- would need global and externs print STDERR "$Pgm: WARNING: splitting objects when profiling will *BREAK* if any _scc_s are present!\n"; # (but it's fine if there aren't any _scc_s around...) @@ -1366,19 +1280,10 @@ It really really wants to be the last STG-to-STG pass that is run. \end{description} \begin{code} -# OLD: -#@HsC_minusO0_flags -# = ( $Oopt_AddAutoSccs, -# '-fsimplify', # would rather *not* run the simplifier (ToDo) -# '\(', '\)', # nothing special at all ???? -# -# $Oopt_FinalStgProfilingMassage -# ); - @HsC_minusNoO_flags = ( '-fsimplify', '\(', - "$Oopt_FB_Support", + $Oopt_FB_Support, # '-falways-float-lets-from-lets', # no idea why this was here (WDP 95/09) '-ffloat-lets-exposing-whnf', '-ffloat-primops-ok', @@ -1386,12 +1291,12 @@ It really really wants to be the last STG-to-STG pass that is run. # '-fdo-lambda-eta-expansion', # too complicated '-freuse-con', # '-flet-to-case', # no strictness analysis, so... - "$Oopt_PedanticBottoms", -# "$Oopt_MonadEtaExpansion", # no thanks + $Oopt_PedanticBottoms, +# $Oopt_MonadEtaExpansion, # no thanks '-fsimpl-uf-use-threshold0', '-fessential-unfoldings-only', -# "$Oopt_UnfoldingUseThreshold", # no thanks - "$Oopt_MaxSimplifierIterations", +# $Oopt_UnfoldingUseThreshold, # no thanks + $Oopt_MaxSimplifierIterations, '\)', $Oopt_AddAutoSccs, # '-ffull-laziness', # removed 95/04 WDP following Andr\'e's lead @@ -1402,19 +1307,17 @@ It really really wants to be the last STG-to-STG pass that is run. @HsC_minusO_flags # NOTE: used for *both* -O and -O2 (some conditional bits) = ( - # initial simplify: mk specialiser and autoscc happy: minimum effort please + # initial simplify: mk specialiser happy: minimum effort please '-fsimplify', '\(', - "$Oopt_FB_Support", + $Oopt_FB_Support, '-fkeep-spec-pragma-ids', # required before specialisation '-fsimpl-uf-use-threshold0', '-fessential-unfoldings-only', '-fmax-simplifier-iterations1', - "$Oopt_PedanticBottoms", + $Oopt_PedanticBottoms, '\)', - $Oopt_AddAutoSccs, # need some basic simplification first - ($Oopt_DoSpecialise) ? ( '-fspecialise-overloaded', $Oopt_SpecialiseUnboxed, @@ -1423,7 +1326,7 @@ It really really wants to be the last STG-to-STG pass that is run. '-fsimplify', # need dependency anal after specialiser ... '\(', # need tossing before calc-inlinings ... - "$Oopt_FB_Support", + $Oopt_FB_Support, '-ffloat-lets-exposing-whnf', '-ffloat-primops-ok', '-fcase-of-case', @@ -1431,10 +1334,10 @@ It really really wants to be the last STG-to-STG pass that is run. '-fdo-eta-reduction', '-fdo-lambda-eta-expansion', '-freuse-con', - "$Oopt_PedanticBottoms", - "$Oopt_MonadEtaExpansion", - "$Oopt_UnfoldingUseThreshold", - "$Oopt_MaxSimplifierIterations", + $Oopt_PedanticBottoms, + $Oopt_MonadEtaExpansion, + $Oopt_UnfoldingUseThreshold, + $Oopt_MaxSimplifierIterations, '\)', '-fcalc-inlinings1', @@ -1444,7 +1347,7 @@ It really really wants to be the last STG-to-STG pass that is run. # '-ffoldr-build-worker-wrapper', # '-fsimplify', # '\(', -# "$Oopt_FB_Support", +# $Oopt_FB_Support, # '-ffloat-lets-exposing-whnf', # '-ffloat-primops-ok', # '-fcase-of-case', @@ -1452,10 +1355,10 @@ It really really wants to be the last STG-to-STG pass that is run. # '-fdo-eta-reduction', # '-fdo-lambda-eta-expansion', # '-freuse-con', -# "$Oopt_PedanticBottoms", -# "$Oopt_MonadEtaExpansion", -# "$Oopt_UnfoldingUseThreshold", -# "$Oopt_MaxSimplifierIterations", +# $Oopt_PedanticBottoms, +# $Oopt_MonadEtaExpansion, +# $Oopt_UnfoldingUseThreshold, +# $Oopt_MaxSimplifierIterations, # '\)', # ) : (), @@ -1470,7 +1373,7 @@ It really really wants to be the last STG-to-STG pass that is run. '\(', '-fignore-inline-pragma', # **** NB! '-fdo-foldr-build', # NB - "$Oopt_FB_Support", + $Oopt_FB_Support, '-ffloat-lets-exposing-whnf', '-ffloat-primops-ok', '-fcase-of-case', @@ -1478,10 +1381,10 @@ It really really wants to be the last STG-to-STG pass that is run. '-fdo-eta-reduction', '-fdo-lambda-eta-expansion', '-freuse-con', - "$Oopt_PedanticBottoms", - "$Oopt_MonadEtaExpansion", - "$Oopt_UnfoldingUseThreshold", - "$Oopt_MaxSimplifierIterations", + $Oopt_PedanticBottoms, + $Oopt_MonadEtaExpansion, + $Oopt_UnfoldingUseThreshold, + $Oopt_MaxSimplifierIterations, '\)', ) : (), @@ -1489,7 +1392,7 @@ It really really wants to be the last STG-to-STG pass that is run. '-fsimplify', '\(', - "$Oopt_FB_Support", + $Oopt_FB_Support, '-ffloat-lets-exposing-whnf', '-ffloat-primops-ok', '-fcase-of-case', @@ -1501,17 +1404,17 @@ It really really wants to be the last STG-to-STG pass that is run. # you need to inline foldr and build ($Oopt_FoldrBuild) ? ('-fdo-foldr-build') : (), # but do reductions if you see them! - "$Oopt_PedanticBottoms", - "$Oopt_MonadEtaExpansion", - "$Oopt_UnfoldingUseThreshold", - "$Oopt_MaxSimplifierIterations", + $Oopt_PedanticBottoms, + $Oopt_MonadEtaExpansion, + $Oopt_UnfoldingUseThreshold, + $Oopt_MaxSimplifierIterations, '\)', '-fstrictness', '-fsimplify', '\(', - "$Oopt_FB_Support", + $Oopt_FB_Support, '-ffloat-lets-exposing-whnf', '-ffloat-primops-ok', '-fcase-of-case', @@ -1520,10 +1423,10 @@ It really really wants to be the last STG-to-STG pass that is run. '-fdo-lambda-eta-expansion', '-freuse-con', '-flet-to-case', # Aha! Only done after strictness analysis - "$Oopt_PedanticBottoms", - "$Oopt_MonadEtaExpansion", - "$Oopt_UnfoldingUseThreshold", - "$Oopt_MaxSimplifierIterations", + $Oopt_PedanticBottoms, + $Oopt_MonadEtaExpansion, + $Oopt_UnfoldingUseThreshold, + $Oopt_MaxSimplifierIterations, '\)', '-ffloat-inwards', @@ -1533,13 +1436,13 @@ It really really wants to be the last STG-to-STG pass that is run. # ( ($OptLevel != 2) # ? '' -# : "-fliberate-case -fsimplify \\( "$Oopt_FB_Support" -ffloat-lets-exposing-whnf -ffloat-primops-ok -fcase-of-case -fdo-case-elim -fdo-eta-reduction -fdo-lambda-eta-expansion -freuse-con -flet-to-case $Oopt_PedanticBottoms $Oopt_MonadEtaExpansion $Oopt_UnfoldingUseThreshold $Oopt_MaxSimplifierIterations \\)" ), +# : "-fliberate-case -fsimplify \\( $Oopt_FB_Support -ffloat-lets-exposing-whnf -ffloat-primops-ok -fcase-of-case -fdo-case-elim -fdo-eta-reduction -fdo-lambda-eta-expansion -freuse-con -flet-to-case $Oopt_PedanticBottoms $Oopt_MonadEtaExpansion $Oopt_UnfoldingUseThreshold $Oopt_MaxSimplifierIterations \\)" ), # Final clean-up simplification: '-fsimplify', '\(', - "$Oopt_FB_Support", + $Oopt_FB_Support, '-ffloat-lets-exposing-whnf', '-ffloat-primops-ok', '-fcase-of-case', @@ -1552,10 +1455,10 @@ It really really wants to be the last STG-to-STG pass that is run. $Oopt_FoldrBuildInline, ($Oopt_FoldrBuild) ? ('-fdo-foldr-build') : (), # but still do reductions if you see them! - "$Oopt_PedanticBottoms", - "$Oopt_MonadEtaExpansion", - "$Oopt_UnfoldingUseThreshold", - "$Oopt_MaxSimplifierIterations", + $Oopt_PedanticBottoms, + $Oopt_MonadEtaExpansion, + $Oopt_UnfoldingUseThreshold, + $Oopt_MaxSimplifierIterations, '\)', # '-fstatic-args', @@ -1581,14 +1484,10 @@ It really really wants to be the last STG-to-STG pass that is run. Sort out what we're going to do about optimising. First, the @hsc@ flags and regular @cc@ flags to worry about: \begin{code} -#if ( $OptLevel < 0 ) { - -# &add_Hsc_flags( @HsC_minusO0_flags ); - if ( $OptLevel <= 0 ) { # for this level, we tell the parser -fignore-interface-pragmas - push(@HsP_flags, '-p'); + push(@HsC_flags, '-fignore-interface-pragmas'); # and tell the compiler not to produce them push(@HsC_flags, '-fomit-interface-pragmas'); @@ -1612,31 +1511,24 @@ if ( $OptLevel <= 0 ) { %************************************************************************ %* * -\subsection{Check for registerising, consistency, etc.} +\subsection{Check for consistency, etc.} %* * %************************************************************************ -Are we capable of generating ``registerisable'' C (either using -C or via equivalent native code)? - -\begin{code} -$RegisteriseC = ( $GccAvailable - && $RegisteriseC ne 'no' # not explicitly *un*set... - && ($TargetPlatform =~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/) - ) ? 'o' : ''; -\end{code} - Sort out @$BuildTag@, @$PROFing@, @$CONCURing@, @$PARing@, @$GRANing@, @$TICKYing@: \begin{code} if ( $BuildTag ne '' ) { local($b) = $BuildDescr{$BuildTag}; - if ($PROFing eq 'p') { print STDERR "$Pgm: Can't mix $b with profiling.\n"; exit 1; } if ($CONCURing eq 'c') { print STDERR "$Pgm: Can't mix $b with -concurrent.\n"; exit 1; } if ($PARing eq 'p') { print STDERR "$Pgm: Can't mix $b with -parallel.\n"; exit 1; } if ($GRANing eq 'g') { print STDERR "$Pgm: Can't mix $b with -gransim.\n"; exit 1; } if ($TICKYing eq 't') { print STDERR "$Pgm: Can't mix $b with -ticky.\n"; exit 1; } + # ok to have a user-way profiling build + # eval the profiling opts ... but leave user-way BuildTag + if ($PROFing eq 'p') { eval($EvaldSetupOpts{'_p'}); } + } elsif ( $PROFing eq 'p' ) { if ($PARing eq 'p') { print STDERR "$Pgm: Can't do profiling with -parallel.\n"; exit 1; } if ($GRANing eq 'g') { print STDERR "$Pgm: Can't do profiling with -gransim.\n"; exit 1; } @@ -1671,11 +1563,9 @@ if ( $BuildTag ne '' ) { \begin{code} if ( $BuildTag ne '' ) { # something other than normal sequential... - push(@HsP_flags, "-g$BuildTag.hi"); # use appropriate Prelude .hi files + push(@HsP_flags, "-syshisuffix=$BuildTag.hi"); # use appropriate Prelude .hi files - $ProduceC = 1; $ProduceS = ''; # must go via C - -# print STDERR "eval...",$EvaldSetupOpts{$BuildTag},"\n"; + $HscOut = '-C='; # must go via C eval($EvaldSetupOpts{$BuildTag}); } @@ -1684,7 +1574,7 @@ if ( $BuildTag ne '' ) { # something other than normal sequential... Decide what the consistency-checking options are in force for this run: \begin{code} $HsC_consist_options = "${BuildTag},${DEBUGging}"; -$Cc_consist_options = "${BuildTag},${DEBUGging},${RegisteriseC}"; +$Cc_consist_options = "${BuildTag},${DEBUGging}"; \end{code} %************************************************************************ @@ -1704,28 +1594,24 @@ if ($TargetPlatform =~ /^alpha-/) { # we know how to *mangle* asm for alpha unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK; - unshift(@CcBoth_flags, ('-static')) if $GccAvailable; + unshift(@CcBoth_flags, ('-static')); } elsif ($TargetPlatform =~ /^hppa/) { # we know how to *mangle* asm for hppa unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); - unshift(@CcBoth_flags, ('-static')) if $GccAvailable; + unshift(@CcBoth_flags, ('-static')); # We don't put in '-mlong-calls', because it's only # needed for very big modules (sigh), and we don't want # to hobble ourselves further on all the other modules # (most of them). - unshift(@CcBoth_flags, ('-D_HPUX_SOURCE')) if $GccAvailable; + unshift(@CcBoth_flags, ('-D_HPUX_SOURCE')); # ___HPUX_SOURCE, not _HPUX_SOURCE, is #defined if -ansi! # (very nice, but too bad the HP /usr/include files don't agree.) } elsif ($TargetPlatform =~ /^i386-/) { # we know how to *mangle* asm for X86 unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); - unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) - if $StkChkByPageFaultOK && $TargetPlatform !~ /linux/; - # NB: cannot do required signal magic on Linux for such stk chks */ - - unshift(@CcRegd_flags, ('-m486')); # not worth not doing + unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK; # -fno-defer-pop : basically the same game as for m68k # @@ -1737,8 +1623,6 @@ if ($TargetPlatform =~ /^alpha-/) { unshift(@CcRegd_flags, '-fomit-frame-pointer'); unshift(@CcRegd_flags, "-DSTOLEN_X86_REGS=$StolenX86Regs"); - unshift(@CcBoth_flags, ('-static')) if $GccAvailable; # maybe unnecessary??? - } elsif ($TargetPlatform =~ /^m68k-/) { # we know how to *mangle* asm for m68k unshift (@CcRegd_flags, ('-D__STG_REV_TBLS__')); @@ -1759,6 +1643,12 @@ if ($TargetPlatform =~ /^alpha-/) { # maybe gives reg alloc a better time # also: -fno-defer-pop is not sufficiently well-behaved without it +} elsif ($TargetPlatform =~ /^mips-/) { + # we (hope to) know how to *mangle* asm for MIPSen + unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); + unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK; + unshift(@CcBoth_flags, ('-static')); + } elsif ($TargetPlatform =~ /^powerpc-/) { # we know how to *mangle* asm for PowerPC unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); @@ -1769,11 +1659,6 @@ if ($TargetPlatform =~ /^alpha-/) { unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK; -} elsif ($TargetPlatform =~ /^mips-/) { - # we (hope to) know how to *mangle* asm for MIPSen - unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__')); - unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK; - unshift(@CcBoth_flags, ('-static')) if $GccAvailable; } \end{code} @@ -1783,36 +1668,27 @@ Should really be whether or not we prepend underscores to global symbols, not an architecture test. (JSM) \begin{code} +$Under = ( $TargetPlatform =~ /^alpha-/ + || $TargetPlatform =~ /^hppa/ + || $TargetPlatform =~ /^mips-sgi-irix/ + || $TargetPlatform =~ /^powerpc-/ + || $TargetPlatform =~ /-solaris/ + || $TargetPlatform =~ /-linux$/ + ) + ? '' : '_'; + unshift(@Ld_flags, - ( $TargetPlatform =~ /^alpha-/ - || $TargetPlatform =~ /^hppa/ - || $TargetPlatform =~ /^mips-sgi-irix/ - || $TargetPlatform =~ /^powerpc-/ - || $TargetPlatform =~ /-solaris/ - ) - ? (($Ld_main) ? ( - '-u', 'Main_' . $Ld_main . '_closure', - ) : (), - '-u', 'unsafePerformPrimIO_fast1', - '-u', 'Nil_closure', - '-u', 'IZh_static_info', - '-u', 'False_inregs_info', - '-u', 'True_inregs_info', - '-u', 'CZh_static_info', - '-u', 'DEBUG_REGS') # just for fun, now... - - # nice friendly a.out machines... - : (($Ld_main) ? ( - '-u', '_Main_' . $Ld_main . '_closure', + (($Ld_main) ? ( + '-u', "${Under}Main_" . $Ld_main . '_closure', ) : (), - '-u', '_unsafePerformPrimIO_fast1', - '-u', '_Nil_closure', - '-u', '_IZh_static_info', - '-u', '_False_inregs_info', - '-u', '_True_inregs_info', - '-u', '_CZh_static_info', - '-u', '_DEBUG_REGS') - ); + '-u', "${Under}GHCbase_unsafePerformPrimIO_fast1", + '-u', "${Under}Prelude_Z91Z93_closure", # i.e., [] + '-u', "${Under}Prelude_IZh_static_info", + '-u', "${Under}Prelude_False_inregs_info", + '-u', "${Under}Prelude_True_inregs_info", + '-u', "${Under}Prelude_CZh_static_info", + '-u', "${Under}DEBUG_REGS")) + ; # just for fun, now... \end{code} %************************************************************************ @@ -1827,19 +1703,18 @@ Ready for Business. \begin{code} # default includes must be added AFTER option processing -if ( $(INSTALLING) ) { +if ( ! $(INSTALLING) ) { + push (@Include_dir, "$TopPwd/$(CURRENT_DIR)/$(GHC_INCLUDESRC)"); +} else { push (@Include_dir, "$InstLibDirGhc/includes"); push (@Include_dir, "$InstDataDirGhc/includes"); - -} else { - push (@Include_dir, "$TopPwd/$(CURRENT_DIR)/$(GHC_INCLUDESRC)"); } \end{code} \begin{code} local($f); foreach $f (@SysLibrary) { - $f .= "${BuildTag}" if $f =~ /^-lHS/; + $f .= $BuildTag if $f =~ /^-lHS/; } # fiddle the TopClosure file name... @@ -1896,7 +1771,7 @@ Record largest specific heapsize, if any. $Specific_heap_size = $Specific_heap_size * $Scale_sizes_by; push(@HsC_rts_flags, '-H'.$Specific_heap_size); $Specific_stk_size = $Specific_stk_size * $Scale_sizes_by; -push(@HsC_rts_flags, (($RTS_style eq 'ghc') ? '-K' : '-A').$Specific_stk_size); +push(@HsC_rts_flags, "-K$Specific_stk_size"); # hack to avoid running hscpp $HsCpp = $Cat if ! $Cpp_flag_set; @@ -1906,15 +1781,19 @@ If no input or link files seen, then we let 'em feed in stdin; this is mainly for debugging. \begin{code} if ($#Input_file < 0 && $#Link_file < 0) { - push(@Input_file, '-'); + @Input_file = ( '-' ); + + open(INF, "> $Tmp_prefix.hs") || &tidy_up_and_die(1,"Can't open $Tmp_prefix.hs\n"); + print STDERR "Enter your Haskell program, end with ^D (on a line of its own):\n"; + while (<>) { print INF $_; } + close(INF) || &tidy_up_and_die(1,"Failed writing to $Tmp_prefix.hs\n"); } \end{code} Tell the world who we are, if they asked. \begin{code} -if ($Verbose) { - print STDERR "$(PROJECTNAME), version $(PROJECTVERSION) $(PROJECTPATCHLEVEL)\n"; -} +print STDERR "$(PROJECTNAME), version $(PROJECTVERSION) $(PROJECTPATCHLEVEL)\n" + if $Verbose; \end{code} %************************************************************************ @@ -1940,19 +1819,18 @@ if ( $Status > 0 ) { # don't link if there were errors... Link if appropriate. \begin{code} if ($Do_lnkr) { - local($libdirs); + local($libdirs) = ''; + # glue them together: push(@UserLibrary_dir, @SysLibrary_dir); - if ($#UserLibrary_dir < 0) { - $libdirs = ''; - } else { - $libdirs = '-L' . join(' -L',@UserLibrary_dir); - } + + $libdirs = '-L' . join(' -L',@UserLibrary_dir) if $#UserLibrary_dir >= 0; + # for a linker, use an explicitly given one, or the going C compiler ... - local($lnkr) = ( $Lnkr ) ? $Lnkr : ($RegisteriseC ? $CcRegd : $CcUnregd ); + local($lnkr) = ( $Lnkr ) ? $Lnkr : $CcRegd; - local($output)= ($Specific_output_file ne '') ? "-o $Specific_output_file" : ''; - @Files_to_tidy = ($Specific_output_file ne '') ? "$Specific_output_file" : 'a.out'; + local($output) = ($Specific_output_file ne '') ? "-o $Specific_output_file" : ''; + @Files_to_tidy = ($Specific_output_file ne '') ? $Specific_output_file : 'a.out'; local($to_do) = "$lnkr $Verbose @Ld_flags $output @Link_file $TopClosureFile $libdirs @UserLibrary @SysLibrary"; &run_something($to_do, 'Linker'); @@ -1990,7 +1868,7 @@ if ($Do_lnkr) { $pvm_executable = $ENV{'PVM_ROOT'} . '/bin/' . $ENV{'PVM_ARCH'} . "/$pvm_executable"; - &run_something("rm -f $pvm_executable; cp -p $executable $pvm_executable && rm -f $executable", 'Moving binary to PVM land'); + &run_something("$Rm -f $pvm_executable; $Cp -p $executable $pvm_executable && $Rm -f $executable", 'Moving binary to PVM land'); # OK, now create the magic script for "$executable" open(EXEC, "> $executable") || &tidy_up_and_die(1,"$Pgm: couldn't open $executable to write!\n"); @@ -2042,7 +1920,7 @@ print STDERR "Exec failed!!!: $SysMan $debug $nprocessors @nonPVM_args\n"; exit(1); EOSCRIPT2 close(EXEC) || die "Failed closing $executable\n"; - chmod 0755, "$executable"; + chmod 0755, $executable; } } @@ -2059,452 +1937,383 @@ exit $Status; # will still be 0 if all went well \begin{code} sub ProcessInputFile { - local($ifile) = @_; # input file name - local($ifile_root); # root of or basename of input file - local($ifile_root_file); # non-directory part of $ifile_root + local($ifile) = @_; # input file name + local($ifile_root); # root of or basename of input file + local($ofile_target); # ultimate output file we hope to produce + # from input file (need to know for recomp + # checking purposes) + local($hifile_target);# ditto (but .hi file) \end{code} Handle the weirdity of input from stdin. \begin{code} - if ($ifile eq '-') { - open(INF, "> $Tmp_prefix.hs") || &tidy_up_and_die(1,"Can't open $Tmp_prefix.hs\n"); - print STDERR "Enter your Haskell program, end with ^D (on a line of its own):\n"; - while (<>) { print INF $_; } - close(INF) || &tidy_up_and_die(1,"Failed writing to $Tmp_prefix.hs\n"); - $ifile = "$Tmp_prefix.hs"; - $ifile_root = '_stdin'; - $ifile_root_file = $ifile_root; + if ($ifile ne '-') { + ($ifile_root = $ifile) =~ s/\.[^\.\/]+$//; + $ofile_target = # may be reset later... + ($Specific_output_file ne '' && ! $Do_lnkr) + ? $Specific_output_file + : &odir_ify($ifile_root, 'o'); + $hifile_target= ($Specific_hi_file ne '') + ? $Specific_hi_file + : "$ifile_root.$HiSuffix"; # ToDo: odirify? + # NB: may change if $ifile_root isn't module name (??) } else { - ($ifile_root = $ifile) =~ s/\.[^\.\/]+$//; - ($ifile_root_file = $ifile_root) =~ s|.*/||; + $ifile = "$Tmp_prefix.hs"; # we know that's where we put the input + $ifile_root = '_stdin'; + $ofile_target = '_stdout'; # gratuitous? + $hifile_target= '_stdout'; # ditto? } \end{code} -We now decide what phases of the compilation system we will run over -this file. The defaults are the ones established when processing flags. -(That established what the last phase run for all files is.) +We need to decide what phases of the compilation system we will run +over this file. The defaults are the ones established when processing +flags. (That established what the last phase run for all files is.) -The lower-case names are the local ones (as is usual), just for this -one file. +We do the pre-recompilation-checker phases here; the rest later. \begin{code} - local($do_lit2pgm) = $Do_lit2pgm; - local($do_hscpp) = $Do_hscpp; - local($do_hsp) = $Do_hsp; - local($do_hsc) = $Do_hsc; - local($do_as) = $Do_as; - local($do_cc) = ( $Do_cc != -1) # i.e., it was set explicitly - ? $Do_cc - : ( ($ProduceC) ? 1 : 0 ); \end{code} Look at the suffix and decide what initial phases of compilation may be dropped off for this file. Also the rather boring business of which files are coming-in/going-out. + +Again, we'll do the post-recompilation-checker parts of this later. \begin{code} + local($do_lit2pgm) = ($ifile =~ /\.lhs$/) ? 1 : 0; + local($do_hscpp) = 1; # but "hscpp" might really be "cat" + local($do_hsc) = 1; + local($do_cc) = ( $Do_cc != -1) # i.e., it was set explicitly + ? $Do_cc + : ( ($HscOut eq '-C=') ? 1 : 0 ); + local($do_as) = $Do_as; + # names of the files to stuff between phases # defaults are temporaries local($in_lit2pgm) = $ifile; local($lit2pgm_hscpp) = "$Tmp_prefix.lpp"; - local($hscpp_hsp) = "$Tmp_prefix.cpp"; - local($hsp_hsc) = "$Tmp_prefix.hsp"; - local($hsc_cc) = "$Tmp_prefix.hc"; - - # to help C compilers grok .hc files [ToDo: de-hackify] - local($cc_help) = "ghc$$.c"; - local($cc_help_s) = "ghc$$.s"; - - local($hsc_hi) = "$Tmp_prefix$HiSuffix"; + local($hscpp_hsc) = "$Tmp_prefix.cpp"; + local($hsc_out) = ( $HscOut eq '-C=' ) ? "$Tmp_prefix.hc" : "$Tmp_prefix.s" ; + local($hsc_hi) = "$Tmp_prefix.hi"; local($cc_as_o) = "${Tmp_prefix}_o.s"; # temporary for raw .s file if opt C - local($cc_as) = "$Tmp_prefix.s"; - local($as_out) = ($Specific_output_file ne '' && ! $Do_lnkr) - ? $Specific_output_file - : &odir_ify("${ifile_root}${Osuffix}"); + local($cc_as) = "$Tmp_prefix.s"; # mangled or hsc-produced .s code + local($as_out) = $ofile_target; - local($is_hc_file) = 1; #Is the C code .hc or .c + local($is_hc_file) = 1; #Is the C code .hc or .c? Assume .hc for now if ($ifile =~ /\.lhs$/) { - push(@Link_file, &odir_ify("${ifile_root}${Osuffix}")); + ; # nothing to change } elsif ($ifile =~ /\.hs$/) { $do_lit2pgm = 0; $lit2pgm_hscpp = $ifile; - push(@Link_file, &odir_ify("${ifile_root}${Osuffix}")); } elsif ($ifile =~ /\.hc$/) { - $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 1; - $hsc_cc = $ifile; - push(@Link_file, &odir_ify("${ifile_root}${Osuffix}")); + $do_lit2pgm = 0; $do_hscpp = 0; $do_hsc = 0; $do_cc = 1; + $hsc_out = $ifile; } elsif ($ifile =~ /\.c$/) { - $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 1; - $hsc_cc = $ifile; $is_hc_file = 0; - push(@Link_file, &odir_ify("${ifile_root}${Osuffix}")); + $do_lit2pgm = 0; $do_hscpp = 0; $do_hsc = 0; $do_cc = 1; + $hsc_out = $ifile; $is_hc_file = 0; } elsif ($ifile =~ /\.s$/) { - $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 0; + $do_lit2pgm = 0; $do_hscpp = 0; $do_hsc = 0; $do_cc = 0; $cc_as = $ifile; - push(@Link_file, &odir_ify("${ifile_root}${Osuffix}")); - } else { - if ($ifile !~ /\.a$/) { - print STDERR "$Pgm: don't recognise suffix on `$ifile'; passing it through to linker\n"; - } - $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 0; $do_as = 0; - push(@Link_file, $ifile); + } else { # don't know what it is, but nothing to do herein... + $do_lit2pgm = 0; $do_hscpp = 0; $do_hsc = 0; $do_cc = 0; $do_as = 0; } + + # OK, have a bash on the first two phases: + &runLit2pgm($in_lit2pgm, $lit2pgm_hscpp) + if $do_lit2pgm; + + &runHscpp($in_lit2pgm, $lit2pgm_hscpp, $hscpp_hsc) + if $do_hscpp; \end{code} +We now think about whether to run hsc/cc or not (when hsc produces .s +stuff, it effectively takes the place of both phases). + To get the output file name right: for each phase that we are {\em -not} going to run, set its input (i.e., the output of its preceding phase) to -@"$ifile_root."@. +not} going to run, set its input (i.e., the output of its preceding +phase) to @"$ifile_root."@. \begin{code} - # lit2pgm -- no preceding phase - if (! $do_hscpp) { - $lit2pgm_hscpp = "$ifile_root.lpp????"; # not done - } - if (! $do_hsp) { - $hscpp_hsp = "$ifile_root.cpp????"; # not done - } - if (! $do_hsc) { - $hsp_hsc = "$ifile_root.hsp????"; # not done - } - if (! $do_cc) { - $hsc_cc = &odir_ify("$ifile_root.hc"); - } - if (! $do_as) { - if ($Specific_output_file ne '') { - $cc_as = $Specific_output_file; - } else { - $cc_as = &odir_ify(( $Only_preprocess_C ) ? "$ifile_root.i" : "$ifile_root.s"); - } - } -\end{code} + local($going_interactive) = $HscOut eq '-N=' || $ifile_root eq '_stdin'; -OK, now do it! Note that we don't come back from a @run_something@ if -it fails. -\begin{code} - if ($do_lit2pgm) { - local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $lit2pgm_hscpp; ". - "$Unlit @Unlit_flags $in_lit2pgm - >> $lit2pgm_hscpp"; - @Files_to_tidy = ( $lit2pgm_hscpp ); - &run_something($to_do, 'literate pre-processor'); - } - if ($do_hscpp) { - # ToDo: specific output? - if ($HsCpp eq $Cat) { - local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsp; ". - "$HsCpp $lit2pgm_hscpp >> $hscpp_hsp"; - @Files_to_tidy = ( $hscpp_hsp ); - &run_something($to_do, 'Ineffective C pre-processor'); - } else { - local($includes) = '-I' . join(' -I',@Include_dir); - local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsp; ". - "$HsCpp $Verbose $genSPECS_flag @HsCpp_flags -D__HASKELL1__=$haskell1_version -D__GLASGOW_HASKELL__=$ghc_version_info $includes $lit2pgm_hscpp >> $hscpp_hsp"; - @Files_to_tidy = ( $hscpp_hsp ); - &run_something($to_do, 'Haskellised C pre-processor'); - } - } - if ($do_hsp) { - # glue imports onto HsP_flags - # if new parser, then put a comma on the front of all of them. - local($hsprefix) = ($do_hsp == 2) ? ',' : ''; - - foreach $a ( @HsP_flags ) { $a = "$hsprefix$a" unless $a =~ /^,/; } - foreach $dir ( @Import_dir ) { push(@HsP_flags, "$hsprefix-I$dir"); } - foreach $dir ( @SysImport_dir ) { push(@HsP_flags, "$hsprefix-J$dir"); } + if (! $do_cc && ! $do_as) { # stopping after hsc + $hsc_out = ($Specific_output_file ne '') + ? $Specific_output_file + : &odir_ify($ifile_root, ($HscOut eq '-C=') ? 'hc' : 's'); + + $ofile_target = $hsc_out; # reset } - if ($do_hsp == 1) { # "old" parser - local($to_do) = "$HsP $Verbose @HsP_flags $hscpp_hsp > $hsp_hsc"; - @Files_to_tidy = ( $hsp_hsc ); - &run_something($to_do, 'Haskell parser'); - if ($Dump_parser_output) { - print STDERR `$Cat $hsp_hsc`; - } - @HsP_flags = (); # reset! + if (! $do_as) { # stopping after gcc (or hsc) + $cc_as = ($Specific_output_file ne '') + ? $Specific_output_file + : &odir_ify($ifile_root, ( $Only_preprocess_C ) ? 'i' : 's'); + + $ofile_target = $cc_as; # reset } - if ($do_hsc) { - # here, we may produce .hc and/or .hi files - local($output) = ''; - local($c_source) = "$ifile_root.hc"; - local($c_output) = $hsc_cc; # defaults - local($s_output) = $cc_as; - local($hi_output) = "$ifile_root$HiSuffix"; - local($going_interactive) = 0; - - if ($Specific_output_file ne '' && ! $do_cc) { - $c_source = $c_output = $Specific_output_file; - @Files_to_tidy = ( $Specific_output_file ) if $Specific_output_file ne '-'; - } - if ($Specific_hi_file ne '') { - # we change the suffix (-hisuf) even if a specific -ohi file: - $Specific_hi_file =~ s/\.hi$/$HiSuffix/; - $hi_output = $Specific_hi_file; - @Files_to_tidy = ( $Specific_hi_file ) if $Specific_hi_file ne '-'; - } - if ( ! ($ProduceC || $ProduceS) - || $ifile_root eq '_stdin' # going interactive... - || ($c_output eq '-' && $hi_output eq '-')) { - $going_interactive = 1; -#OLD: $output = '1>&2'; # interactive/debugging, to stderr - @Files_to_tidy = (); - # don't need .hi (unless magic value "2" says we wanted it anyway): - if ( $ProduceHi == 2 ) { - $output .= " -hi$hsc_hi"; - unlink($hsc_hi); # needs to be cleared; will be appended to - } else { - $ProduceHi = 0; - } - $do_cc = 0; $do_as = 0; $Do_lnkr = 0; # and we won't go any further... - } +\end{code} - if ( ! $going_interactive ) { - if ( $ProduceHi ) { - # we always go to a temp file for these (for later diff'ing) - $output = "-hi$hsc_hi"; - unlink($hsc_hi); # needs to be cleared; will be appended to - @Files_to_tidy = ( $hsc_hi ); - } - if ( $ProduceC ) { - $output .= " -C$c_output"; - push(@Files_to_tidy, $c_output); - - open(CFILE, "> $c_output") || &tidy_up_and_die(1,"$Pgm: failed to open `$c_output' (to write)\n"); - print CFILE "#line 2 \"$c_source\"\n"; - close(CFILE) || &tidy_up_and_die(1,"Failed writing to $c_output\n"); - # the "real" C output will then be appended - } - if ( $ProduceS ) { - $output .= " -fasm-$ProduceS -S$s_output"; - push(@Files_to_tidy, $s_output); - - # ToDo: ummm,... this isn't doing anything (WDP 94/11) - open(SFILE, "> $s_output") || &tidy_up_and_die(1,"$Pgm: failed to open `$s_output' (to write)\n"); - close(SFILE) || &tidy_up_and_die(1,"Failed writing to $s_output\n"); - # the "real" assembler output will then be appended - } - } +Check if hsc needs to be run at all. - # if we're compiling foo.hs, we want the GC stats to end up in foo.stat - if ( $CollectingGCstats ) { - if ($RTS_style eq 'hbc') { - push(@HsC_rts_flags, '-S'); # puts it in "STAT" - } else { - push(@HsC_rts_flags, "-S$ifile_root.stat"); - push(@Files_to_tidy, "$ifile_root.stat"); - } - } +\begin{code} + local($more_processing_required) = 1; - if ( $CollectGhcTimings ) { # assume $RTS_style eq 'ghc' - # emit nofibbish time/bytes-alloc stats to stderr; - # see later .stat file post-processing - push(@HsC_rts_flags, "-s$Tmp_prefix.stat"); - push(@Files_to_tidy, "$Tmp_prefix.stat"); - } + if ( $Do_recomp_chkr && $do_hsc && ! $going_interactive ) { + # recompilation-checking is important enough to live off by itself + require('ghc-recomp.prl') + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-recomp.prl!\n"); - local($dump); - if ($Specific_dump_file ne '') { - $dump = "2>> $Specific_dump_file"; - $Using_dump_file = 1; - } else { - $dump = ''; - } - - local($to_do); - if ($RTS_style eq 'hbc') { - # NB: no parser flags - $to_do = "$HsC < $hsp_hsc $dump @HsC_rts_flags - @HsC_flags $CoreLint $Verbose $output"; - } elsif ($do_hsp == 1) { # old style parser -- no HsP_flags - $to_do = "$HsC < $hsp_hsc $dump @HsC_flags $CoreLint $Verbose $output +RTS @HsC_rts_flags"; - } else { # new style - $to_do = "$HsC ,-H @HsP_flags ,$hscpp_hsp $dump @HsC_flags $CoreLint $Verbose $output +RTS @HsC_rts_flags"; - } - &run_something($to_do, 'Haskell compiler'); + $more_processing_required + = &runRecompChkr($ifile, $hscpp_hsc, $ifile_root, $ofile_target, $hifile_target); - # compensate further for HBC's -S rts opt: - if ($CollectingGCstats && $RTS_style eq 'hbc') { - unlink("$ifile_root.stat"); - rename('STAT', "$ifile_root.stat"); - } + print STDERR "$Pgm:recompile: NOT NEEDED!\n" if ! $more_processing_required; + } - # finish business w/ nofibbish time/bytes-alloc stats - &process_ghc_timings() if $CollectGhcTimings; + $do_hsc = 0, $do_cc = 0, $do_as = 0 if ! $more_processing_required; +\end{code} - # if non-interactive, heave in the consistency info at the end - # NB: pretty hackish (depends on how $output is set) - if ( ! $going_interactive ) { - if ( $ProduceC ) { - $to_do = "echo 'static char ghc_hsc_ID[] = \"\@(#)hsc $ifile\t$HsC_major_version.$HsC_minor_version,$HsC_consist_options\";' >> $c_output"; - } - if ( $ProduceS ) { - local($consist) = "hsc.$ifile.$HsC_major_version.$HsC_minor_version.$HsC_consist_options"; - $consist =~ s/,/./g; - $consist =~ s/\//./g; - $consist =~ s/-/_/g; - $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? - $to_do = "echo '\n\t.text\n$consist:' >> $s_output"; - } - &run_something($to_do, 'Pin on Haskell consistency info'); - } +\begin{code} + if ( $do_hsc ) { + + &runHsc($ifile_root, $hsc_out, $hsc_hi, $going_interactive); - # call the special mangler to produce the .hi/.h(h?) files... - &diff_hi_file($hsc_hi, $hi_output) - if $ProduceHi == 1 && ! $going_interactive; -#OLD: &extract_c_and_hi_files("$Tmp_prefix.hsc", $c_output, $hi_output, $c_source) + # interface-handling is important enough to live off by itself + require('ghc-iface.prl') + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-iface.prl!\n"); - # if we produced an interface file "no matter what", - # print what we got on stderr (ToDo: honor -ohi flag) - if ( $ProduceHi == 2 ) { - print STDERR `$Cat $hsc_hi`; - } + &postprocessHiFile($hsc_hi, $hifile_target, $going_interactive); # save a copy of the .hc file, even if we are carrying on... - if ($ProduceC && $do_cc && $Keep_hc_file_too) { - local($to_do) = "$(RM) $ifile_root.hc; cp $c_output $ifile_root.hc"; + if ($HscOut eq '-C=' && $do_cc && $Keep_hc_file_too) { + local($to_do) = "$Rm $ifile_root.hc; $Cp $hsc_out $ifile_root.hc"; &run_something($to_do, 'Saving copy of .hc file'); } # save a copy of the .s file, even if we are carrying on... - if ($ProduceS && $do_as && $Keep_s_file_too) { - local($to_do) = "$(RM) $ifile_root.s; cp $cc_as $ifile_root.s"; + if ($HscOut eq '-S=' && $do_as && $Keep_s_file_too) { + local($to_do) = "$Rm $ifile_root.s; $Cp $hsc_out $ifile_root.s"; &run_something($to_do, 'Saving copy of .s file'); } # if we're going to split up object files, # we inject split markers into the .hc file now - if ( $ProduceC && $SplitObjFiles ) { - &inject_split_markers ( $c_output ); + if ( $HscOut eq '-C=' && $SplitObjFiles ) { + &inject_split_markers ( $hsc_out ); } } + if ($do_cc) { + &runGcc ($is_hc_file, $hsc_out, $cc_as_o); + &runMangler($is_hc_file, $cc_as_o, $cc_as, $ifile_root); + } + + &split_asm_file($cc_as) if $do_as && $SplitObjFiles; + + &runAs($as_out, $ifile_root) if $do_as; +\end{code} + +Finally, decide what to queue up for linker input. +\begin{code} + # tentatively assume we will eventually produce linker input: + push(@Link_file, &odir_ify($ifile_root, 'o')); + + if ($ifile !~ /\.(lhs|hs|hc|c|s)$/) { + print STDERR "$Pgm: don't recognise suffix on `$ifile'; passing it through to linker\n" + if $ifile !~ /\.a$/; + + # oops; we tentatively pushed the wrong thing; fix & do the right thing + pop(@Link_file); push(@Link_file, $ifile); + } + +} # end of ProcessInputFile +\end{code} + +%************************************************************************ +%* * +\section[Driver-run-phases]{Routines to run the various phases} +%* * +%************************************************************************ + +\begin{code} +sub runLit2pgm { + local($in_lit2pgm, $lit2pgm_hscpp) = @_; + + local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $lit2pgm_hscpp && ". + "$Unlit @Unlit_flags $in_lit2pgm - >> $lit2pgm_hscpp"; + @Files_to_tidy = ( $lit2pgm_hscpp ); + + &run_something($to_do, 'literate pre-processor'); +} +\end{code} + +\begin{code} +sub runHscpp { + local($in_lit2pgm, $lit2pgm_hscpp, $hscpp_hsc) = @_; + + local($to_do); + + if ($HsCpp eq $Cat) { + $to_do = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsc && ". + "$HsCpp $lit2pgm_hscpp >> $hscpp_hsc"; + @Files_to_tidy = ( $hscpp_hsc ); + &run_something($to_do, 'Ineffective C pre-processor'); + } else { local($includes) = '-I' . join(' -I',@Include_dir); - local($cc); - local($s_output); - local($c_flags) = "@CcBoth_flags"; - local($ddebug_flag) = ( $DEBUGging ) ? '-DDEBUG' : ''; - if ($RegisteriseC) { - $cc = $CcRegd; - $s_output = ($is_hc_file || $TargetPlatform =~ /^(hppa|i386)/) ? $cc_as_o : $cc_as; - $c_flags .= " @CcRegd_flags"; - $c_flags .= ($is_hc_file) ? " @CcRegd_flags_hc" : " @CcRegd_flags_c"; - } else { - $cc = $CcUnregd; - $s_output = $cc_as; - $c_flags .= " @CcUnregd_flags"; - $c_flags .= ($is_hc_file) ? " @CcUnregd_flags_hc" : " @CcUnregd_flags_c"; - } - - # C compiler won't like the .hc extension. So we create - # a tmp .c file which #include's the needful. - open(TMP, "> $cc_help") || &tidy_up_and_die(1,"$Pgm: failed to open `$cc_help' (to write)\n"); - if ( $is_hc_file ) { - print TMP <= 0; - } - # heave in the consistency info - print TMP "static char ghc_cc_ID[] = \"\@(#)cc $ifile\t$Cc_major_version.$Cc_minor_version,$Cc_consist_options\";\n"; + $to_do = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsc && ". + "$HsCpp $Verbose $genSPECS_flag @HsCpp_flags -D__HASKELL1__=$Haskell1Version -D__GLASGOW_HASKELL__=$GhcVersionInfo $includes $lit2pgm_hscpp >> $hscpp_hsc"; + @Files_to_tidy = ( $hscpp_hsc ); + &run_something($to_do, 'Haskellised C pre-processor'); + } +} +\end{code} - # and #include the real source - print TMP "#include \"$hsc_cc\"\n"; - close(TMP) || &tidy_up_and_die(1,"Failed writing to $cc_help\n"); +\begin{code} +sub runHsc { + local($ifile_root, $hsc_out, $hsc_hi, $going_interactive) = @_; - local($to_do) = "$cc $Verbose $ddebug_flag $c_flags @Cpp_define -D__HASKELL1__=$haskell1_version $includes $cc_help > $Tmp_prefix.ccout 2>&1 && ( if [ $cc_help_s != $s_output ] ; then mv $cc_help_s $s_output ; else exit 0 ; fi )"; - # note: __GLASGOW_HASKELL__ is pointedly *not* #defined at the C level. - if ( $Only_preprocess_C ) { # HACK ALERT! - $to_do =~ s/ -S\b//g; - } - @Files_to_tidy = ( $cc_help, $cc_help_s, $s_output ); - $PostprocessCcOutput = 1; # hack, dear hack... - &run_something($to_do, 'C compiler'); - $PostprocessCcOutput = 0; - unlink($cc_help, $cc_help_s); - - if ( ($RegisteriseC && $is_hc_file) - || $Dump_asm_insn_counts - || $Dump_asm_globals_info ) { - # dynamically load assembler-fiddling code, which we are about to use - local($target) = 'oops'; - $target = '-alpha' if $TargetPlatform =~ /^alpha-/; - $target = '-hppa' if $TargetPlatform =~ /^hppa/; - $target = '' if $TargetPlatform =~ /^i386-/; - $target = '-m68k' if $TargetPlatform =~ /^m68k-/; - $target = '-mips' if $TargetPlatform =~ /^mips-/; - $target = '' if $TargetPlatform =~ /^powerpc-/; - $target = '-solaris' if $TargetPlatform =~ /^sparc-sun-solaris2/; - $target = '-sparc' if $TargetPlatform =~ /^sparc-sun-sunos4/; - - $target ne 'oops' - || &tidy_up_and_die(1,"$Pgm: panic: can't decipher $TargetPlatform!\n"); - require("ghc-asm$target.prl") - || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm$target.prl!\n"); - } + # prepend comma to HsP flags (so hsc can tell them apart...) + foreach $a ( @HsP_flags ) { $a = ",$a" unless $a =~ /^,/; } - if ( $Dump_raw_asm ) { # to stderr, before mangling - local($to_pr) = ($RegisteriseC) ? $cc_as_o : $cc_as ; - print STDERR `cat $to_pr`; - } + &makeHiMap() unless $HiMapDone; + push(@HsC_flags, "-himap=$HiMapFile"); - if ($RegisteriseC) { - if ($is_hc_file) { - # post-process the assembler [.hc files only] - &mangle_asm($cc_as_o, $cc_as); - - } elsif ($TargetPlatform =~ /^hppa/) { - # minor mangling of non-threaded files for hp-pa only - require('ghc-asm-hppa.prl') - || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm-hppa.prl!\n"); - &mini_mangle_asm($cc_as_o, $cc_as); - - } elsif ($TargetPlatform =~ /^i386/) { - # extremely-minor OFFENSIVE mangling of non-threaded just one file - require('ghc-asm.prl') - || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm.prl!\n"); - &mini_mangle_asm($cc_as_o, $cc_as); - } - } + # here, we may produce .hc/.s and/or .hi files + local($output) = ''; + @Files_to_tidy = (); - # collect interesting (static-use) info - &dump_asm_insn_counts($cc_as) if $Dump_asm_insn_counts; - &dump_asm_globals_info($cc_as) if $Dump_asm_globals_info; + if ( $going_interactive ) { + # don't need .hi unless going to show it on stdout: + $ProduceHi = '-nohifile=' if ! $HiOnStdout; + $do_cc = 0; $do_as = 0; $Do_lnkr = 0; # and we won't go any further... + } - # save a copy of the .s file, even if we are carrying on... - if ($do_as && $Keep_s_file_too) { - local($to_do) = "$(RM) $ifile_root.s; cp $cc_as $ifile_root.s"; - &run_something($to_do, 'Saving copy of .s file'); - } + # set up for producing output/.hi; note that flag twiddling + # may mean that nothing will actually be produced: + $output = "$ProduceHi$hsc_hi $HscOut$hsc_out"; + @Files_to_tidy = ( $hsc_hi, $hsc_out ); + + # if we're compiling foo.hs, we want the GC stats to end up in foo.stat + if ( $CollectingGCstats ) { + push(@HsC_rts_flags, "-S$ifile_root.stat"); + push(@Files_to_tidy, "$ifile_root.stat"); } - if ($do_as) { - # if we're splitting .o files... - if ( $SplitObjFiles ) { - &split_asm_file ( $cc_as ); - } + if ( $CollectGhcTimings ) { # assume $RTS_style eq 'ghc' + # emit nofibbish time/bytes-alloc stats to stderr; + # see later .stat file post-processing + push(@HsC_rts_flags, "-s$Tmp_prefix.stat"); + push(@Files_to_tidy, "$Tmp_prefix.stat"); + } - local($asmblr) = ( $As ) ? $As : ($RegisteriseC ? $CcRegd : $CcUnregd ); + local($dump) = ''; + if ($Specific_dump_file ne '') { + $dump = "2>> $Specific_dump_file"; + $Using_dump_file = 1; + } - if ( ! $SplitObjFiles ) { - local($to_do) = "$asmblr -o $as_out -c @As_flags $cc_as"; - @Files_to_tidy = ( $as_out ); - &run_something($to_do, 'Unix assembler'); + local($to_do); + $to_do = "$HsC @HsP_flags ,$hscpp_hsc $dump @HsC_flags $CoreLint $Verbose $output +RTS @HsC_rts_flags"; + &run_something($to_do, 'Haskell compiler'); + + # finish business w/ nofibbish time/bytes-alloc stats + &process_ghc_timings() if $CollectGhcTimings; + + # if non-interactive, heave in the consistency info at the end + # NB: pretty hackish (depends on how $output is set) + if ( ! $going_interactive ) { + if ( $HscOut eq '-C=' ) { + $to_do = "echo 'static char ghc_hsc_ID[] = \"\@(#)hsc $ifile\t$HsC_major_version.$HsC_minor_version,$HsC_consist_options\";' >> $hsc_out"; + + } elsif ( $HscOut eq '-S=' ) { + local($consist) = "hsc.$ifile.$HsC_major_version.$HsC_minor_version.$HsC_consist_options"; + $consist =~ s/,/./g; + $consist =~ s/\//./g; + $consist =~ s/-/_/g; + $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly? + $to_do = "echo '\n\t.text\n$consist:' >> $hsc_out"; + } + &run_something($to_do, 'Pin on Haskell consistency info'); + } +} +\end{code} - } else { # more complicated split-ification... +Use \tr{@Import_dir} and \tr{@SysImport_dir} to make a tmp file +of (module-name, pathname) pairs, one per line, separated by a space. +\begin{code} +%HiMap = (); +$HiMapDone = 0; +$HiMapFile = ''; - # must assemble files $Tmp_prefix__[1 .. $NoOfSplitFiles].s +sub makeHiMap { - for ($f = 1; $f <= $NoOfSplitFiles; $f++ ) { - local($split_out) = &odir_ify("${ifile_root}__${f}${Osuffix}"); - local($to_do) = "$asmblr -o $split_out -c @As_flags ${Tmp_prefix}__${f}.s"; - @Files_to_tidy = ( $split_out ); + # collect in %HiMap; write later; also used elsewhere in driver - &run_something($to_do, 'Unix assembler'); + local($mod, $path, $d, $e); + + foreach $d ( @Import_dir ) { + opendir(DIR, $d) || &tidy_up_and_die(1,"$Pgm: error when reading directory: $d\n"); + local(@entry) = readdir(DIR); + foreach $e ( @entry ) { + next unless $e =~ /([A-Z][A-Za-z0-9_]*)\.$HiSuffix$/o; + $mod = $1; + $path = "$d/$e"; + $path =~ s,^\./,,; + + if ( ! defined($HiMap{$mod}) ) { + $HiMap{$mod} = $path; + } else { + &already_mapped_err($mod, $HiMap{$mod}, $path); } } + closedir(DIR); # || &tidy_up_and_die(1,"$Pgm: error when closing directory: $d\n"); } -} # end of ProcessInputFile + + foreach $d ( @SysImport_dir ) { + opendir(DIR, $d) || &tidy_up_and_die(1,"$Pgm: error when reading directory: $d\n"); + local(@entry) = readdir(DIR); + foreach $e ( @entry ) { + next unless $e =~ /([A-Z][A-Za-z0-9_]*)\.$SysHiSuffix$/o; + next if $NoImplicitPrelude && $e =~ /Prelude\.$SysHiSuffix$/o; + + $mod = $1; + $path = "$d/$e"; + $path =~ s,^\./,,; + + if ( ! defined($HiMap{$mod}) ) { + $HiMap{$mod} = $path; + } elsif ( $mod ne 'Main' ) { # saves useless warnings... + &already_mapped_err($mod, $HiMap{$mod}, $path); + } + } + closedir(DIR); # || &tidy_up_and_die(1,"$Pgm: error when closing directory: $d\n"); + } + + $HiMapFile = "$Tmp_prefix.himap"; + unlink($HiMapFile); + open(HIMAP, "> $HiMapFile") || &tidy_up_and_die(1,"$Pgm: can't open $HiMapFile\n"); + foreach $d (keys %HiMap) { + print HIMAP $d, ' ', $HiMap{$d}, "\n"; + } + close(HIMAP) || &tidy_up_and_die(1,"$Pgm: error when closing $HiMapFile\n"); + + $HiMapDone = 1; +} + +sub already_mapped_err { + local($mod, $mapped_to, $path) = @_; + + # OK, it isn't really an error if $mapped_to and $path turn + # out to be the same thing. + ($m_dev,$m_ino,$m_mode,$m_nlink,$m_uid,$m_gid,$m_rdev,$m_size, + $m_atime,$m_mtime,$m_ctime,$m_blksize,$m_blocks) = stat($mapped_to); + ($p_dev,$p_ino,$p_mode,$p_nlink,$p_uid,$p_gid,$p_rdev,$p_size, + $p_atime,$p_mtime,$p_ctime,$p_blksize,$p_blocks) = stat($path); + + return if $m_ino == $p_ino; # same inode number + + print STDERR "$Pgm: module $mod already mapped to $mapped_to (inode $m_ino)"; + print STDERR ";\n\tignoring: $path (inode $p_ino)\n"; +} \end{code} %************************************************************************ @@ -2520,14 +2329,157 @@ EOINCL %************************************************************************ \begin{code} +sub osuf_ify { + local($ofile,$def_suffix) = @_; + + return(($Osuffix eq '') ? "$ofile.$def_suffix" : "$ofile.$Osuffix" ); +} + sub odir_ify { - local($orig_file) = @_; + local($orig_file, $def_suffix) = @_; if ($Specific_output_dir eq '') { # do nothing - return($orig_file); + &osuf_ify($orig_file, $def_suffix); } else { local ($orig_file_only); ($orig_file_only = $orig_file) =~ s|.*/||; - return("$Specific_output_dir/$orig_file_only"); + &osuf_ify("$Specific_output_dir/$orig_file_only",$def_suffix); + } +} +\end{code} + +\begin{code} +sub runGcc { + local($is_hc_file, $hsc_out, $cc_as_o) = @_; + + local($includes) = '-I' . join(' -I', @Include_dir); + local($cc); + local($s_output); + local($c_flags) = "@CcBoth_flags"; + local($ddebug_flag) = ( $DEBUGging ) ? '-DDEBUG' : ''; + + # "input" files to use that are not in some weird directory; + # to help C compilers grok .hc files [ToDo: de-hackify] + local($cc_help) = "ghc$$.c"; + local($cc_help_s) = "ghc$$.s"; + + $cc = $CcRegd; + $s_output = ($is_hc_file || $TargetPlatform =~ /^(hppa|i386)/) ? $cc_as_o : $cc_as; + $c_flags .= " @CcRegd_flags"; + $c_flags .= ($is_hc_file) ? " @CcRegd_flags_hc" : " @CcRegd_flags_c"; + + # C compiler won't like the .hc extension. So we create + # a tmp .c file which #include's the needful. + open(TMP, "> $cc_help") || &tidy_up_and_die(1,"$Pgm: failed to open `$cc_help' (to write)\n"); + if ( $is_hc_file ) { + print TMP <= 0; + } + # heave in the consistency info + print TMP "static char ghc_cc_ID[] = \"\@(#)cc $ifile\t$Cc_major_version.$Cc_minor_version,$Cc_consist_options\";\n"; + + # and #include the real source + print TMP "#include \"$hsc_out\"\n"; + close(TMP) || &tidy_up_and_die(1,"Failed writing to $cc_help\n"); + + local($to_do) = "$cc $Verbose $ddebug_flag $c_flags @Cpp_define -D__HASKELL1__=$Haskell1Version $includes $cc_help > $Tmp_prefix.ccout 2>&1 && ( if [ $cc_help_s != $s_output ] ; then mv $cc_help_s $s_output ; else exit 0 ; fi )"; + # note: __GLASGOW_HASKELL__ is pointedly *not* #defined at the C level. + if ( $Only_preprocess_C ) { # HACK ALERT! + $to_do =~ s/ -S\b//g; + } + @Files_to_tidy = ( $cc_help, $cc_help_s, $s_output ); + $PostprocessCcOutput = 1; # hack, dear hack... + &run_something($to_do, 'C compiler'); + $PostprocessCcOutput = 0; + unlink($cc_help, $cc_help_s); +} +\end{code} + +\begin{code} +sub runMangler { + local($is_hc_file, $cc_as_o, $cc_as, $ifile_root) = @_; + + if ( $is_hc_file ) { + # dynamically load assembler-fiddling code, which we are about to use: + require('ghc-asm.prl') + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm.prl!\n"); + } + + print STDERR `cat $cc_as_o` if $Dump_raw_asm; # to stderr, before mangling + + if ($is_hc_file) { + # post-process the assembler [.hc files only] + &mangle_asm($cc_as_o, $cc_as); + +#OLD: for sanity: + local($target) = 'oops'; + $target = '-alpha' if $TargetPlatform =~ /^alpha-/; + $target = '-hppa' if $TargetPlatform =~ /^hppa/; + $target = '' if $TargetPlatform =~ /^i386-/; + $target = '-m68k' if $TargetPlatform =~ /^m68k-/; + $target = '-mips' if $TargetPlatform =~ /^mips-/; + $target = '' if $TargetPlatform =~ /^powerpc-/; + $target = '-solaris' if $TargetPlatform =~ /^sparc-sun-solaris2/; + $target = '-sparc' if $TargetPlatform =~ /^sparc-sun-sunos4/; + + if ( $target ne '' ) { + require("ghc-asm$target.prl") + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm$target.prl!\n"); + &mangle_asm($cc_as_o, "$cc_as-2"); # the OLD one! + &run_something("$Cmp -s $cc_as-2 $cc_as || $Diff $cc_as-2 $cc_as 1>&2 || exit 0", + "Diff'ing old and new mangled .s files"); # NB: to stderr + } + + } elsif ($TargetPlatform =~ /^hppa/) { + # minor mangling of non-threaded files for hp-pa only + require('ghc-asm.prl') + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm-hppa.prl!\n"); + &mini_mangle_asm_hppa($cc_as_o, $cc_as); + + } elsif ($TargetPlatform =~ /^i386/) { + # extremely-minor OFFENSIVE mangling of non-threaded just one file + require('ghc-asm.prl') + || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm.prl!\n"); + &mini_mangle_asm_i386($cc_as_o, $cc_as); + } + + # save a copy of the .s file, even if we are carrying on... + if ($do_as && $Keep_s_file_too) { + local($to_do) = "$Rm $ifile_root.s; $Cp $cc_as $ifile_root.s"; + &run_something($to_do, 'Saving copy of .s file'); + } +} +\end{code} + +\begin{code} +sub runAs { + local($as_out, $ifile_root) = @_; + + local($asmblr) = ( $As ) ? $As : $CcRegd; + + if ( ! $SplitObjFiles ) { + local($to_do) = "$asmblr -o $as_out -c @As_flags $cc_as"; + @Files_to_tidy = ( $as_out ); + &run_something($to_do, 'Unix assembler'); + + } else { # more complicated split-ification... + + # must assemble files $Tmp_prefix__[1 .. $NoOfSplitFiles].s + + for ($f = 1; $f <= $NoOfSplitFiles; $f++ ) { + local($split_out) = &odir_ify("${ifile_root}__${f}",'o'); + local($to_do) = "$asmblr -o $split_out -c @As_flags ${Tmp_prefix}__${f}.s"; + @Files_to_tidy = ( $split_out ); + + &run_something($to_do, 'Unix assembler'); + } } } \end{code} @@ -2592,60 +2544,6 @@ sub run_something { %************************************************************************ %* * -\subsection[Driver-demangle-C-and-hi]{@extract_c_and_hi_files@: Unscramble Haskell-compiler output} -%* * -%************************************************************************ - -Update interface if the tmp one is newer... -We first have to fish the module name out of the interface. -\begin{code} -sub diff_hi_file { - local($tmp_hi_file, $hi_file) = @_; - local($if_modulename) = ''; - - # extract the module name - - open(TMP, "< $tmp_hi_file")|| &tidy_up_and_die(1,"$Pgm: failed to open `$tmp_hi_file' (to read)\n"); - while () { - if ( /^interface ([A-Za-z0-9'_]+) / ) { - $if_modulename = $1; - } - } - close(TMP) || &tidy_up_and_die(1,"Failed reading from $tmp_hi_file\n"); - &tidy_up_and_die(1,"No module name in $tmp_hi_file\n") - if ! $if_modulename; - - #compare/diff with old one - - if ($hi_file eq '-') { - &run_something("cat $tmp_hi_file", "copy interface to stdout"); - - } else { - if ($Specific_hi_file eq '' && $if_modulename ne '') { - if ( $hi_file =~ /\// ) { - $hi_file =~ s/\/[^\/]+$//; - $hi_file .= "/$if_modulename$HiSuffix"; - } else { - $hi_file = "$if_modulename$HiSuffix"; - } - print STDERR "interface really going into: $hi_file\n" if $Verbose; - } - - if ($HiDiff_flag && -f $hi_file) { - local($diffcmd) = '$(CONTEXT_DIFF)'; - - &run_something("cmp -s $tmp_hi_file $hi_file || $(CONTEXT_DIFF) $hi_file $tmp_hi_file 1>&2 || exit 0", - "Diff'ing old and new $HiSuffix files"); # NB: to stderr - } - - &run_something("cmp -s $tmp_hi_file $hi_file || ( $(RM) $hi_file && $(CP) $tmp_hi_file $hi_file )", - "Comparing old and new $HiSuffix files"); - } -} -\end{code} - -%************************************************************************ -%* * \subsection[Driver-ghctiming]{Emit nofibbish GHC timings} %* * %************************************************************************ @@ -2728,7 +2626,7 @@ sub process_ghc_timings { \begin{code} sub tidy_up { - local($to_do) = "\n$(RM) $Tmp_prefix*"; + local($to_do) = "\n$Rm $Tmp_prefix*"; if ( $Tmp_prefix !~ /^\s*$/ ) { print STDERR "$to_do\n" if $Verbose; system($to_do); @@ -2812,3 +2710,4 @@ sub add_Hsc_flags { } } \end{code} + diff --git a/ghc/includes/COptJumps.lh b/ghc/includes/COptJumps.lh index db8516d..458c93c 100644 --- a/ghc/includes/COptJumps.lh +++ b/ghc/includes/COptJumps.lh @@ -254,7 +254,8 @@ register void *_procedure __asm__("$27"); \begin{code} #if i386_TARGET_ARCH -#ifdef solaris2_TARGET_OS +/* *not* a good way to do this (WDP 96/05) */ +#if defined(solaris2_TARGET_OS) || defined(linux_TARGET_OS) #define MINI_INTERPRET_END "miniInterpretEnd" #else #define MINI_INTERPRET_END "_miniInterpretEnd" diff --git a/ghc/includes/COptWraps.lh b/ghc/includes/COptWraps.lh index da57a40..4334cae 100644 --- a/ghc/includes/COptWraps.lh +++ b/ghc/includes/COptWraps.lh @@ -69,9 +69,23 @@ but unfortunately, we have to cater to ANSI C as well.) do {SaveAllStgRegs(); PerformGC(args); RestoreAllStgRegs();} while(0) #define DO_STACKOVERFLOW(headroom,args) \ do {SaveAllStgRegs(); StackOverflow(headroom,args); RestoreAllStgRegs();} while(0) + +#if defined(GRAN) + +#define DO_YIELD(args) DO_GRAN_YIELD(args) +#define DO_GRAN_YIELD(liveness) \ + do {SaveAllStgRegs(); Yield(liveness); RestoreAllStgRegs();} while(0) + +#define DO_PERFORM_RESCHEDULE(liveness_mask,reenter) \ + do {SaveAllStgRegs(); PerformReschedule(liveness_mask,reenter); RestoreAllStgRegs();} while(0) + +#else + #define DO_YIELD(args) \ do {SaveAllStgRegs(); Yield(args); RestoreAllStgRegs();} while(0) +#endif /* GRAN */ + \end{code} %************************************************************************ @@ -168,12 +182,35 @@ extern void callWrapper_safe(STG_NO_ARGS); void PerformGC_wrapper PROTO((W_)); void StackOverflow_wrapper PROTO((W_, W_)); void Yield_wrapper PROTO((W_)); +# ifdef GRAN +void PerformReschedule_wrapper PROTO((W_, W_)); +void GranSimAllocate_wrapper PROTO((I_, P_, W_)); +void GranSimUnallocate_wrapper PROTO((I_, P_, W_)); +void GranSimFetch_wrapper PROTO((P_)); +void GranSimExec_wrapper PROTO((W_, W_, W_, W_, W_)); +# endif #endif #define DO_GC(args) PerformGC_wrapper(args) #define DO_STACKOVERFLOW(headroom,args) StackOverflow_wrapper(headroom,args) + +# ifdef GRAN + +#define DO_YIELD(args) DO_GRAN_YIELD(args) +#define DO_GRAN_YIELD(liveness) Yield_wrapper(liveness) + +#define DO_PERFORMRESCHEDULE(liveness, always_reenter_node) PerformReschedule_wrapper(liveness, always_reenter_node) +#define DO_GRANSIMALLOCATE(n, node, liveness) GranSimAllocate_wrapper(n, node, liveness) +#define DO_GRANSIMUNALLOCATE(n, node, liveness) GranSimUnallocate_wrapper(n, node, liveness) +#define DO_GRANSIMFETCH(node) GranSimFetch_wrapper(node) +#define DO_GRANSIMEXEC(arith,branch,load,store,floats) GranSimExec_wrapper(arith,branch,load,store,floats) + +# else + #define DO_YIELD(args) Yield_wrapper(args) +# endif + #endif /* __GNUC__ && __STG_GCC_REGS__ */ \end{code} @@ -377,7 +414,7 @@ gets whatever it's after. #define WRAPPER_NAME(f) /*nothing*/ -#ifdef solaris2_TARGET_OS +#if defined(solaris2_TARGET_OS) || defined(linux_TARGET_OS) #define REAL_NAME(f) #f #else #define REAL_NAME(f) "_" #f @@ -566,7 +603,6 @@ gets whatever it's after. %************************************************************************ \begin{code} - #if sparc_TARGET_ARCH #define MAGIC_CALL_SETUP \ @@ -577,6 +613,11 @@ gets whatever it's after. "\tstd %i2,[%fp-32]\n" \ "\tstd %i4,[%fp-24]"); +/* We leave nothing to chance here; we have seen + GCC stick "unwanted" code in the branch delay + slot, causing mischief (WDP 96/05) +*/ +#ifdef GRAN #define MAGIC_CALL \ __asm__ volatile ( \ "ld [%%fp-40],%%o5\n" \ @@ -590,6 +631,21 @@ gets whatever it's after. __asm__ volatile ( \ "std %f0,[%fp-40]\n" \ "\tstd %o0,[%fp-32]"); +#else +#define MAGIC_CALL \ + __asm__ volatile ( \ + "ld [%%fp-40],%%o5\n" \ + "\tld [%%fp-36],%%o0\n" \ + "\tld [%%fp-32],%%o1\n" \ + "\tld [%%fp-28],%%o2\n" \ + "\tld [%%fp-24],%%o3\n" \ + "\tld [%%fp-20],%%o4\n" \ + "\tcall %%o5\n" \ + "\tnop\n" \ + "\tstd %%f0,[%%fp-40]\n"\ + "\tstd %%o0,[%%fp-32]" \ + : : : "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%f0", "%g1", "%g2", "%g3", "%g4", "memory"); +#endif #define MAGIC_RETURN \ __asm__ volatile ( \ diff --git a/ghc/includes/CostCentre.lh b/ghc/includes/CostCentre.lh index ed1fe26..79c4272 100644 --- a/ghc/includes/CostCentre.lh +++ b/ghc/includes/CostCentre.lh @@ -44,19 +44,19 @@ The compiler declares a static block for each @_scc_@ annotation in the source using the @CC_DECLARE@ macro where @label@, @module@ and @group@ are strings and @ident@ the cost centre identifier. -\begin{code} -# define CC_IS_CAF 'C' -# define CC_IS_DICT 'D' +\begin{code} +# define CC_IS_CAF 'c' +# define CC_IS_DICT 'd' # define CC_IS_SUBSUMED 'S' -# define CC_IS_BORING '\0' +# define CC_IS_BORING 'B' # define STATIC_CC_REF(cc_ident) &CAT2(cc_ident,_struct) # define DYN_CC_REF(cc_ident) cc_ident /* unused */ -# define CC_DECLARE(cc_ident,name,module,group,subsumed,is_local) \ - is_local struct cc CAT2(cc_ident,_struct) \ - = {NOT_REGISTERED, UNHASHED, name, module, group, \ - subsumed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; \ +# define CC_DECLARE(cc_ident,name,module,group,subsumed,is_local) \ + is_local struct cc CAT2(cc_ident,_struct) \ + = {NOT_REGISTERED, UNHASHED, name, module, group, \ + subsumed, INIT_CC_STATS}; \ is_local CostCentre cc_ident = STATIC_CC_REF(cc_ident) #endif /* defined(PROFILING) || defined(CONCURRENT) */ @@ -96,7 +96,9 @@ turn on @PROFILING@. Get them out of the way.... # define SET_CC_HDR(closure, cc) /* Dont set CC header */ # define SET_STATIC_CC_HDR(cc) /* No static CC header */ -# define SET_CCC(cc_ident,is_dupd) +# define SET_CCC(cc_ident,do_scc_count) +# define SET_DICT_CCC(cc_ident,do_scc_count) +# define SET_CCC_RTS(cc_ident,do_sub_count,do_count) # define RESTORE_CCC(cc) @@ -104,6 +106,9 @@ turn on @PROFILING@. Get them out of the way.... # define ENTER_CC_TCL(closure) # define ENTER_CC_F(cc) # define ENTER_CC_FCL(closure) +# define ENTER_CC_FSUB() +# define ENTER_CC_FCAF(cc) +# define ENTER_CC_FLOAD(cc) # define ENTER_CC_PAP(cc) # define ENTER_CC_PAP_CL(closure) @@ -152,7 +157,7 @@ CC_EXTERN(CC_CAFs); /* prelude cost centre (CAFs only) */ CC_EXTERN(CC_DICTs); /* prelude cost centre (DICTs only) */ # define IS_CAF_OR_DICT_CC(cc) \ - (((cc)->is_subsumed == CC_IS_CAF) || ((cc)->is_subsumed == CC_IS_DICT)) + ((cc)->is_subsumed & ' ') /* tests for lower case character */ # define IS_SUBSUMED_CC(cc) ((cc)->is_subsumed == CC_IS_SUBSUMED) @@ -200,14 +205,23 @@ not count the entry to avoid large counts arising from simple recursion. (Huh? WDP 94/07) \begin{code} -# define SET_CCC_X(cc,is_dupd) \ - do { \ - if (!(is_dupd)) { CCC->sub_scc_count++; } /* inc subcc count of CCC */ \ - CCC = (CostCentre)(cc); /* set CCC to ident cc */ \ - if (!(is_dupd)) { CCC->scc_count++; } /* inc scc count of new CCC*/ \ +# define SET_CCC_X(cc,do_subcc_count,do_subdict_count,do_scc_count) \ + do { \ + if ((do_subcc_count)) { CCC->sub_scc_count++; } /* inc subcc count of CCC */ \ + if ((do_subdict_count)) { CCC->sub_dictcc_count++; } /* inc sub dict count of CCC */ \ + CCC = (CostCentre)(cc); /* set CCC to ident cc */ \ + ASSERT_IS_REGISTERED(CCC,1); \ + if ((do_scc_count)) { CCC->scc_count++; } /* inc scc count of new CCC*/ \ } while(0) -# define SET_CCC(cc_ident,is_dupd) SET_CCC_X(STATIC_CC_REF(cc_ident),is_dupd) +# define SET_CCC(cc_ident,do_scc_count) \ + SET_CCC_X(STATIC_CC_REF(cc_ident),do_scc_count,0,do_scc_count) + +# define SET_DICT_CCC(cc_ident,do_scc_count) \ + SET_CCC_X(STATIC_CC_REF(cc_ident),0,do_scc_count,do_scc_count) + +# define SET_CCC_RTS(cc_ident,do_sub_count,do_scc_count) \ + SET_CCC_X(STATIC_CC_REF(cc_ident),do_sub_count,0,do_scc_count) \end{code} We have this @RESTORE_CCC@ macro, rather than just an assignment, @@ -225,9 +239,9 @@ On entry to top level CAFs we count the scc ... # define ENTER_CC_CAF_X(cc) \ do { \ CCC->sub_cafcc_count++; /* inc subcaf count of CCC */ \ - CCC = (CostCentre)(cc); /* set CCC to ident cc */ \ + CCC = (CostCentre)(cc); /* set CCC to ident cc */ \ ASSERT_IS_REGISTERED(CCC,1); \ - CCC->cafcc_count++; /* inc cafcc count of CCC */ \ + CCC->scc_count++; /* inc scc count of CAF cc */ \ } while(0) # define ENTER_CC_CAF(cc_ident) ENTER_CC_CAF_X(STATIC_CC_REF(cc_ident)) @@ -236,14 +250,14 @@ On entry to top level CAFs we count the scc ... On entering a closure we only count the enter to thunks ... \begin{code} -# define ENTER_CC_T(cc) \ - do { \ - CCC = (CostCentre)(cc); \ - ASSERT_IS_REGISTERED(CCC,1); \ - CCC->thunk_count++; /* inc thunk count of new CCC */ \ +# define ENTER_CC_T(cc) \ + do { \ + CCC = (CostCentre)(cc); \ + ASSERT_IS_REGISTERED(CCC,1); \ + CCC_DETAIL_COUNT(CCC->thunk_count); \ } while(0) -# define ENTER_CC_TCL(closure) \ +# define ENTER_CC_TCL(closure) \ ENTER_CC_T(CC_HDR(closure)) /* Here is our special "hybrid" case when we do *not* set the CCC. @@ -256,13 +270,38 @@ On entering a closure we only count the enter to thunks ... ASSERT_IS_REGISTERED(cc,1); \ if ( ! IS_CAF_OR_DICT_CC(cc) ) { \ CCC = cc; \ + } else { \ + CCC_DETAIL_COUNT(cc->caffun_subsumed); \ + CCC_DETAIL_COUNT(CCC->subsumed_caf_count); \ } \ - CCC->function_count++; \ + CCC_DETAIL_COUNT(CCC->function_count); \ } while(0) # define ENTER_CC_FCL(closure) \ ENTER_CC_F(CC_HDR(closure)) +# define ENTER_CC_FSUB() \ + do { \ + CCC_DETAIL_COUNT(CCC->subsumed_fun_count); \ + CCC_DETAIL_COUNT(CCC->function_count); \ + } while(0) + +# define ENTER_CC_FCAF(centre) \ + do { \ + CostCentre cc = (CostCentre) (centre); \ + ASSERT_IS_REGISTERED(cc,1); \ + CCC_DETAIL_COUNT(cc->caffun_subsumed); \ + CCC_DETAIL_COUNT(CCC->subsumed_caf_count); \ + CCC_DETAIL_COUNT(CCC->function_count); \ + } while(0) + +# define ENTER_CC_FLOAD(cc) \ + do { \ + CCC = (CostCentre)(cc); \ + ASSERT_IS_REGISTERED(CCC,1); \ + CCC_DETAIL_COUNT(CCC->function_count); \ + } while(0) + /* These ENTER_CC_PAP things are only used in the RTS */ # define ENTER_CC_PAP(centre) \ @@ -271,13 +310,22 @@ On entering a closure we only count the enter to thunks ... ASSERT_IS_REGISTERED(cc,1); \ if ( ! IS_CAF_OR_DICT_CC(cc) ) { \ CCC = cc; \ + } else { \ + CCC_DETAIL_COUNT(cc->caffun_subsumed); \ + CCC_DETAIL_COUNT(CCC->subsumed_caf_count); \ } \ - CCC->pap_count++; \ + CCC_DETAIL_COUNT(CCC->pap_count); \ } while(0) # define ENTER_CC_PAP_CL(closure) \ ENTER_CC_PAP(CC_HDR(closure)) +# if defined(PROFILING_DETAIL_COUNTS) +# define CCC_DETAIL_COUNT(inc_this) ((inc_this)++) +# else +# define CCC_DETAIL_COUNT(inc_this) /*nothing*/ +# endif + #endif /* PROFILING */ \end{code} @@ -357,7 +405,7 @@ We don't want to attribute costs to an unregistered cost-centre: # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) /*nothing*/ #else # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) \ - do { \ + do { /* beware of cc name-capture */ \ CostCentre c_c = (CostCentre) (cc); \ if (c_c->registered == NOT_REGISTERED) { \ fprintf(stderr,"Entering unregistered CC: %s\n",c_c->label); \ @@ -398,6 +446,8 @@ reuse @CON_K@ (or something) in runtime/main/StgStartup.lhc. Similarily, the SP stuff should probably be the highly uninformative @INTERNAL_KIND@. +SOF 4/96: Renamed MallocPtr_K to ForeignObj_K + \begin{code} #if defined(PROFILING) @@ -409,7 +459,7 @@ Similarily, the SP stuff should probably be the highly uninformative # define ARR_K 6 # ifndef PAR -# define MallocPtr_K 7 /* Malloc Pointer */ +# define ForeignObj_K 7 /* Malloc Pointer */ # define SPT_K 8 /* Stable Pointer Table */ # endif /* !PAR */ @@ -569,19 +619,19 @@ extern hash_t index_type PROTO((ClCategory clcat)); memory alloc macros. \begin{code} -# define CC_TICK(cc) \ - do { CostCentre centre = (CostCentre) (cc); \ - ASSERT_IS_REGISTERED(centre,1); \ - centre->time_ticks += 1; \ +# define CC_TICK(centre) \ + do { CostCentre cc = (CostCentre) (centre); \ + ASSERT_IS_REGISTERED(cc,1); \ + cc->time_ticks += 1; \ } while(0) # if defined(PROFILING) -# define CC_ALLOC(cc, size, kind) \ - do { CostCentre cc_ = (CostCentre) (cc); \ - ASSERT_IS_REGISTERED(cc_,0/*OK if OVERHEAD*/); \ - cc_->mem_allocs += 1; \ - cc_->mem_alloc += (size) - (PROF_FIXED_HDR + TICKY_FIXED_HDR); \ - } while(0) /* beware name-capture by ASSERT_IS...! */ +# define CC_ALLOC(centre, size, kind) \ + do { CostCentre cc = (CostCentre) (centre); \ + ASSERT_IS_REGISTERED(cc,0/*OK if OVERHEAD*/); \ + CCC_DETAIL_COUNT(cc->mem_allocs); \ + cc->mem_alloc += (size) - (PROF_FIXED_HDR + TICKY_FIXED_HDR); \ + } while(0) # endif \end{code} @@ -610,13 +660,7 @@ rtsBool cc_to_ignore PROTO((CostCentre)); \begin{code} # if defined(PROFILING) -extern I_ heap_profile_init PROTO((char *select_cc_str, - char *select_mod_str, - char *select_grp_str, - char *select_descr_str, - char *select_typ_str, - char *select_kind_str, - char *argv[])); +I_ heap_profile_init PROTO((char *argv[])); extern void heap_profile_finish(STG_NO_ARGS); @@ -628,8 +672,11 @@ extern void (* heap_profile_fn) PROTO((P_ closure,I_ size)); extern I_ earlier_ticks; /* no. of earlier ticks grouped */ extern hash_t time_intervals; /* no. of time intervals reported -- 18 */ -# define HEAP_PROFILE_CLOSURE(closure,size) \ - STGCALL2(void,(void *, P_, I_),(*heap_profile_fn),closure,size) /*R SM2s.lh */ +# define HEAP_PROFILE_CLOSURE(closure,size) \ + do { \ + if (heap_profile_fn) { \ + STGCALL2(void,(void *, P_, I_),(*heap_profile_fn),closure,size); \ + }} while(0) # endif /* PROFILING */ \end{code} diff --git a/ghc/includes/GranSim.lh b/ghc/includes/GranSim.lh index eea0b24..e2da0d1 100644 --- a/ghc/includes/GranSim.lh +++ b/ghc/includes/GranSim.lh @@ -7,44 +7,241 @@ %* * %************************************************************************ +Dummy definitions if we are not compiling for GrAnSim. + +\begin{code} +#ifndef GRAN +#define GRAN_ALLOC_HEAP(n,liveness) /* nothing */ +#define GRAN_UNALLOC_HEAP(n,liveness) /* nothing */ +#define GRAN_FETCH() /* nothing */ +#define GRAN_FETCH_AND_RESCHEDULE(liveness) /* nothing */ +#define GRAN_RESCHEDULE(liveness, reenter) /* nothing */ +#define GRAN_EXEC(arith,branch,loads,stores,floats) /* nothing */ +#define GRAN_SPARK() /* nothing */ +#endif +\end{code} + +First the basic types specific to GrAnSim. + \begin{code} -#ifdef GRAN - -# define IS_IDLE(proc) ((IdleProcs & PE_NUMBER((long)proc)) != 0l) -# define ANY_IDLE (Idlers > 0) -# define MAKE_IDLE(proc) do { if(!IS_IDLE(proc)) { ++Idlers; IdleProcs |= PE_NUMBER(proc); } } while(0) -# define MAKE_BUSY(proc) do { if(IS_IDLE(proc)) { --Idlers; IdleProcs &= ~PE_NUMBER(proc); } } while(0) - -/* Event Types */ -# define STARTTHREAD 0 /* Start a newly created thread */ -# define CONTINUETHREAD 1 /* Continue running the first thread in the queue */ -# define RESUMETHREAD 2 /* Resume a previously running thread */ -# define MOVESPARK 3 /* Move a spark from one PE to another */ -# define MOVETHREAD 4 /* Move a thread from one PE to another */ -# define FINDWORK 5 /* Search for work */ -# define FETCHNODE 6 /* Fetch a node */ -# define FETCHREPLY 7 /* Receive a node */ - -# define EVENT_PROC(evt) (evt->proc) -# define EVENT_CREATOR(evt) (evt->creator) -# define EVENT_TIME(evt) (evt->time) -# define EVENT_TYPE(evt) (evt->evttype) -# define EVENT_TSO(evt) (evt->tso) -# define EVENT_NODE(evt) (evt->node) -# define EVENT_SPARK(evt) (evt->spark) -# define EVENT_NEXT(evt) (eventq)(evt->next) - -#endif /* GRAN */ +#if defined(GRAN) +#define GRANSIMSTATS_BINARY RTSflags.GranFlags.granSimStats_Binary +#elif defined(PAR) +#define GRANSIMSTATS_BINARY RTSflags.ParFlags.granSimStats_Binary +#endif + +#ifdef PAR +ullong msTime(STG_NO_ARGS); +# define CURRENT_TIME msTime() +# define TIME_ON_PROC(p) msTime() + +# define CURRENT_PROC thisPE +#endif + +#if defined(GRAN) + +#if !defined(COMPILING_GHC) +#include "RtsFlags.h" +#endif + +# define CURRENT_TIME CurrentTime[CurrentProc] +# define TIME_ON_PROC(p) CurrentTime[p] +# define CURRENT_PROC CurrentProc +#endif #if defined(GRAN) || defined(PAR) + +/* Granularity event types for output (see DumpGranEvent) */ +enum gran_event_types { + GR_START = 0, GR_STARTQ, + GR_STEALING, GR_STOLEN, GR_STOLENQ, + GR_FETCH, GR_REPLY, GR_BLOCK, GR_RESUME, GR_RESUMEQ, + GR_SCHEDULE, GR_DESCHEDULE, + GR_END, + SP_SPARK, SP_SPARKAT, SP_USED, SP_PRUNED, SP_EXPORTED, SP_ACQUIRED, + GR_ALLOC, + GR_TERMINATE, + GR_SYSTEM_START, GR_SYSTEM_END, /* only for debugging */ + GR_EVENT_MAX +}; + +/* Prototypes of functions needed both in GRAN and PAR setup */ void DumpGranEvent PROTO((enum gran_event_types name, P_ tso)); -void DumpSparkGranEvent PROTO((enum gran_event_types name, W_ id)); -void DumpGranEventAndNode PROTO((enum gran_event_types name, P_ tso, P_ node, PROC proc)); -void DumpRawGranEvent PROTO((PROC pe, enum gran_event_types name, W_ id)); -void DumpGranInfo PROTO((PROC pe, P_ tso, rtsBool mandatory_thread)); +void DumpRawGranEvent PROTO((PROC proc, PROC p, enum gran_event_types name, P_ tso, P_ node, I_ len)); +void DumpStartEventAt PROTO((TIME time, PROC proc, PROC p, enum gran_event_types name, + P_ tso, P_ node, I_ len)); +void DumpGranInfo PROTO((PROC proc, P_ tso, rtsBool mandatory_thread)); +void DumpTSO PROTO((P_ tso)); + void grterminate PROTO((TIME v)); +void grputw PROTO((TIME v)); + +extern unsigned CurrentProc; + /* I have no idea what this is supposed to be in the PAR case WDP 96/03 */ + +#endif /* GRAN || PAR */ + +/* ---------- The rest of this file is GRAN only ---------- */ + +#if defined(GRAN) +rtsBool any_idle PROTO((STG_NO_ARGS)); +int idlers PROTO((STG_NO_ARGS)); + +enum proc_status { + Idle = 0, /* empty threadq */ + Sparking, /* non-empty sparkq; FINDWORK has been issued */ + Starting, /* STARTTHREAD has been issue */ + Fetching, /* waiting for remote data (only if block-on-fetch) */ + Fishing, /* waiting for remote spark/thread */ + Busy /* non-empty threadq, with head of queue active */ +}; + +typedef struct event { + PROC proc; /* Processor id */ + PROC creator; /* Processor id of PE that created the event */ + EVTTYPE evttype; /* Event type */ + TIME time; /* Time at which event happened */ + P_ tso; /* Associated TSO, if relevant, Nil_closure otherwise*/ + P_ node; /* Associated node, if relevant, Nil_closure otherwise*/ + sparkq spark; /* Associated SPARK, if relevant, NULL otherwise */ + I_ gc_info; /* Counter of heap objects to mark (used in GC only)*/ + struct event *next; + } *eventq; + +/* Macros for accessing components of the event structure */ +#define EVENT_PROC(evt) (evt->proc) +#define EVENT_CREATOR(evt) (evt->creator) +#define EVENT_TIME(evt) (evt->time) +#define EVENT_TYPE(evt) (evt->evttype) +#define EVENT_TSO(evt) (evt->tso) +#define EVENT_NODE(evt) (evt->node) +#define EVENT_SPARK(evt) (evt->spark) +#define EVENT_GC_INFO(evt) (evt->gc_info) +#define EVENT_NEXT(evt) (eventq)(evt->next) + +/* Maximum number of PEs that can be simulated */ +#define MAX_PROC (BITS_IN(W_)) + +#if 0 +extern W_ IdleProcs, Idlers; +#endif + +/* Processor numbers to bitmasks and vice-versa */ +#define MainProc 0 /* Id of main processor */ +#define MAX_PRI 10000 /* max possible priority */ +#define MAIN_PRI MAX_PRI /* priority of main thread */ + +/* GrAnSim uses IdleProcs as bitmask to indicate which procs are idle */ +#define PE_NUMBER(n) (1l << (long)n) +#define ThisPE PE_NUMBER(CurrentProc) +#define MainPE PE_NUMBER(MainProc) +#define Everywhere (~0l) +#define Nowhere (0l) + +#define IS_LOCAL_TO(ga,proc) ((1l << (long) proc) & ga) + +#define GRAN_TIME_SLICE 1000 /* max time between 2 ReSchedules */ + +#if 1 + +#define IS_IDLE(proc) (procStatus[proc] == Idle) +#define IS_SPARKING(proc) (procStatus[proc] == Sparking) +#define IS_STARTING(proc) (procStatus[proc] == Starting) +#define IS_FETCHING(proc) (procStatus[proc] == Fetching) +#define IS_FISHING(proc) (procStatus[proc] == Fishing) +#define IS_BUSY(proc) (procStatus[proc] == Busy) +#define ANY_IDLE (any_idle()) +#define MAKE_IDLE(proc) do { procStatus[proc] = Idle; } while(0) +#define MAKE_SPARKING(proc) do { procStatus[proc] = Sparking; } while(0) +#define MAKE_STARTING(proc) do { procStatus[proc] = Starting; } while(0) +#define MAKE_FETCHING(proc) do { procStatus[proc] = Fetching; } while(0) +#define MAKE_FISHING(proc) do { procStatus[proc] = Fishing; } while(0) +#define MAKE_BUSY(proc) do { procStatus[proc] = Busy; } while(0) + +#else + +#define IS_IDLE(proc) ((IdleProcs & PE_NUMBER((long)proc)) != 0l) +#define ANY_IDLE (Idlers > 0) +#define MAKE_IDLE(proc) do { \ + if (!IS_IDLE(proc)) { \ + ++Idlers; \ + IdleProcs |= PE_NUMBER(proc); \ + procStatus[proc] = Idle; \ + } \ + } while(0) +#define MAKE_BUSY(proc) do { \ + if (IS_IDLE(proc)) { \ + --Idlers; \ + IdleProcs &= ~PE_NUMBER(proc); \ + procStatus[proc] = Busy; \ + } \ + } while(0) +#endif + +/* Number of last event type */ +#define MAX_EVENT 9 + +/* Event Types (internal use only) */ +#define STARTTHREAD 0 /* Start a newly created thread */ +#define CONTINUETHREAD 1 /* Continue running the first thread in the queue */ +#define RESUMETHREAD 2 /* Resume a previously running thread */ +#define MOVESPARK 3 /* Move a spark from one PE to another */ +#define MOVETHREAD 4 /* Move a thread from one PE to another */ +#define FINDWORK 5 /* Search for work */ +#define FETCHNODE 6 /* Fetch a node */ +#define FETCHREPLY 7 /* Receive a node */ +#define GLOBALBLOCK 8 /* Block a TSO on a remote node */ +#define UNBLOCKTHREAD 9 /* Make a TSO runnable */ + +#if defined(GRAN_CHECK) +/* Prototypes of GrAnSim debugging functions */ +void G_PRINT_NODE(P_); +void G_TREE(P_); +void G_INFO_TABLE(P_); +void G_CURR_THREADQ(I_); +void G_THREADQ(P_, I_); +void G_TSO(P_, I_); +void G_EVENT(eventq, I_); +void G_EVENTQ(I_); +void G_PE_EQ(PROC, I_); +void G_SPARK(sparkq, I_); +void G_SPARKQ(sparkq, I_); +void G_CURR_SPARKQ(I_); +void G_PROC(I_, I_); +void GP(I_); +void GCP(); +void GT(P_); +void GCT(); +void GEQ(); +void GTQ(PROC); +void GCTQ(); +void GSQ(PROC); +void GCSQ(); +void GN(P_); +void GIT(P_); +void pC(P_); +void DN(P_); +void DIT(P_); +void DT(P_); +/* void DS(P_); */ +#endif + +/* Interface to event queues */ +extern eventq EventHd; /* global event queue */ +extern char *event_names[]; +eventq get_next_event PROTO(()); +TIME get_time_of_next_event PROTO(()); +void newevent PROTO((PROC proc, PROC creator, TIME time, EVTTYPE + evttype, P_ tso, P_ node, sparkq spark)); +void prepend_event PROTO((eventq event)); +eventq grab_event PROTO((STG_NO_ARGS)); +void print_event PROTO((eventq event)); +void print_eventq PROTO((eventq hd)); +void print_spark PROTO((sparkq spark)); +void print_sparkq PROTO((sparkq hd)); + +/* void DumpPruneEvent PROTO((PROC proc, sparkq spark)); */ -# ifdef GRAN I_ SaveSparkRoots PROTO((I_)); I_ SaveEventRoots PROTO((I_)); @@ -53,19 +250,179 @@ I_ RestoreEventRoots PROTO((I_)); IF_RTS(int init_gr_simulation PROTO((int, char **, int, char **));) IF_RTS(void end_gr_simulation(STG_NO_ARGS);) -# endif -# ifdef PAR -ullong msTime(STG_NO_ARGS); -# define CURRENT_TIME msTime() +/* These constants are defaults for the RTS flags of GranSim */ -# define CURRENT_PROC thisPE +/* Communication Cost Model (EDS-like), max_proc > 2. */ -# else /* GRAN */ +#define LATENCY 1000 /* Latency for single packet */ +#define ADDITIONAL_LATENCY 100 /* Latency for additional packets */ +#define BASICBLOCKTIME 10 +#define FETCHTIME (LATENCY*2+MSGUNPACKTIME) +#define LOCALUNBLOCKTIME 10 +#define GLOBALUNBLOCKTIME (LATENCY+MSGUNPACKTIME) -# define CURRENT_TIME CurrentTime[CurrentProc] -# define CURRENT_PROC CurrentProc -# endif +#define MSGPACKTIME 0 /* Cost of creating a packet */ +#define MSGUNPACKTIME 0 /* Cost of receiving a packet */ +#define MSGTIDYTIME 0 /* Cost of cleaning up after send */ + +#define MAX_FISHES 1 /* max no. of outstanding spark steals */ +/* How much to increase GrAnSims internal packet size if an overflow + occurs. + NB: This is a GrAnSim internal variable and is independent of the + simulated packet buffer size. +*/ + +#define GRANSIM_DEFAULT_PACK_BUFFER_SIZE 200 +#define REALLOC_SZ 50 +/* extern W_ gran_mpacktime, gran_mtidytime, gran_munpacktime; */ + +/* Thread cost model */ +#define THREADCREATETIME (25+THREADSCHEDULETIME) +#define THREADQUEUETIME 12 /* Cost of adding a thread to the running/runnable queue */ +#define THREADDESCHEDULETIME 75 /* Cost of descheduling a thread */ +#define THREADSCHEDULETIME 75 /* Cost of scheduling a thread */ +#define THREADCONTEXTSWITCHTIME (THREADDESCHEDULETIME+THREADSCHEDULETIME) + +/* Instruction Cost model (SPARC, including cache misses) */ +#define ARITH_COST 1 +#define BRANCH_COST 2 +#define LOAD_COST 4 +#define STORE_COST 4 +#define FLOAT_COST 1 /* ? */ + +#define HEAPALLOC_COST 11 + +#define PRI_SPARK_OVERHEAD 5 +#define PRI_SCHED_OVERHEAD 5 + +/* Miscellaneous Parameters */ +extern rtsBool DoFairSchedule; +extern rtsBool DoReScheduleOnFetch; +extern rtsBool SimplifiedFetch; +extern rtsBool DoStealThreadsFirst; +extern rtsBool DoAlwaysCreateThreads; +extern rtsBool DoThreadMigration; +extern rtsBool DoGUMMFetching; +extern I_ FetchStrategy; +extern rtsBool PreferSparksOfLocalNodes; +extern rtsBool DoPrioritySparking, DoPriorityScheduling; +extern I_ SparkPriority, SparkPriority2, ThunksToPack; +/* These come from debug options -bD? */ +extern rtsBool NoForward; +extern rtsBool PrintFetchMisses; + +extern TIME TimeOfNextEvent, EndOfTimeSlice; /* checked from the threaded world! */ +extern I_ avoidedCS; /* Unused!! ToDo: Remake libraries and nuke this var */ +extern rtsBool IgnoreEvents; /* HACK only for testing */ + +#if defined(GRAN_CHECK) +/* Variables for gathering misc statistics */ +extern I_ tot_low_pri_sparks; +extern I_ rs_sp_count, rs_t_count, ntimes_total, fl_total, no_of_steals; +extern I_ tot_packets, tot_packet_size, tot_cuts, tot_thunks, + tot_sq_len, tot_sq_probes, tot_sparks, withered_sparks, + tot_add_threads, tot_tq_len, non_end_add_threads; +#endif + +extern I_ fetch_misses; +#if defined(GRAN_COUNT) +extern I_ nUPDs, nUPDs_old, nUPDs_new, nUPDs_BQ, nPAPs, BQ_lens; #endif + +extern FILE *gr_file; +/* extern rtsBool no_gr_profile; */ +/* extern rtsBool do_sp_profile; */ + +extern rtsBool NeedToReSchedule; + +void GranSimAllocate PROTO((I_ n, P_ node, W_ liveness)); +void GranSimUnAllocate PROTO((I_ n, P_ node, W_ liveness)); +I_ GranSimFetch PROTO((P_ node)); +void GranSimExec PROTO((W_ ariths, W_ branches, W_ loads, W_ stores, W_ floats)); +void GranSimSpark PROTO((W_ local, P_ node)); +void GranSimSparkAt PROTO((sparkq spark, P_ where, I_ identifier)); +void GranSimSparkAtAbs PROTO((sparkq spark, PROC proc, I_ identifier)); +void GranSimBlock PROTO((P_ tso, PROC proc, P_ node)); +void PerformReschedule PROTO((W_, rtsBool)); + +#define GRAN_ALLOC_HEAP(n,liveness) \ + GranSimAllocate_wrapper(n,0,0); + +#define GRAN_UNALLOC_HEAP(n,liveness) \ + GranSimUnallocate_wrapper(n,0,0); + +#if 0 + +#define GRAN_FETCH() \ + GranSimFetch_wrapper(Node); + +#define GRAN_FETCH_AND_RESCHEDULE(liveness_mask,reenter) \ + do { if(liveness_mask&LIVENESS_R1) \ + SaveAllStgRegs(); \ + GranSimFetch(Node); \ + PerformReschedule(liveness_mask,reenter); \ + RestoreAllStgRegs(); \ + } while(0) + +#define GRAN_RESCHEDULE(liveness_mask,reenter) \ + PerformReschedule_wrapper(liveness_mask,reenter) + +#else + +#define GRAN_FETCH() /*nothing */ + +#define GRAN_FETCH_AND_RESCHEDULE(liveness_mask,reenter) \ + do { if(liveness_mask&LIVENESS_R1) \ + SaveAllStgRegs(); \ + GranSimFetch(Node); \ + PerformReschedule(liveness_mask,reenter); \ + RestoreAllStgRegs(); \ + } while(0) + +#define GRAN_RESCHEDULE(liveness_mask,reenter) GRAN_FETCH_AND_RESCHEDULE(liveness_mask,reenter) + +#endif + +#define THREAD_CONTEXT_SWITCH(liveness_mask,reenter) \ + do { \ + if (context_switch /* OR_INTERVAL_EXPIRED */) { \ + GRAN_RESCHEDULE(liveness_mask,reenter); \ + } }while(0) + +#if 0 + +#define GRAN_EXEC(arith,branch,load,store,floats) \ + GranSimExec_wrapper(arith,branch,load,store,floats); + +#else + +#define GRAN_EXEC(arith,branch,load,store,floats) \ + { \ + W_ cost = RTSflags.GranFlags.gran_arith_cost*arith + \ + RTSflags.GranFlags.gran_branch_cost*branch + \ + RTSflags.GranFlags.gran_load_cost*load + \ + RTSflags.GranFlags.gran_store_cost*store + \ + RTSflags.GranFlags.gran_float_cost*floats; \ + TSO_EXECTIME(CurrentTSO) += cost; \ + CurrentTime[CurrentProc] += cost; \ + } + +#endif + +#define GRAN_YIELD(liveness) \ + do { \ + if ( (CurrentTime[CurrentProc]>=EndOfTimeSlice) || \ + ((CurrentTime[CurrentProc]>=TimeOfNextEvent) && \ + (TimeOfNextEvent!=0) && !IgnoreEvents )) { \ + DO_GRAN_YIELD(liveness); \ + } \ + } while (0); + +#define ADD_TO_SPARK_QUEUE(spark) \ + STGCALL1(void,(),add_to_spark_queue,spark) \ + +#endif /* GRAN */ + \end{code} diff --git a/ghc/includes/Jmakefile b/ghc/includes/Jmakefile index 74ab648..90a2819 100644 --- a/ghc/includes/Jmakefile +++ b/ghc/includes/Jmakefile @@ -63,12 +63,14 @@ PLAT_H_FILES = config.h platform.h #undef __native_h /* Literate-pgmming suffix rules used herein */ -LitSuffixRule(.lh,.h) -LitSuffixRule(.lc,.c) +UnlitSuffixRule(.lh,.h) +UnlitSuffixRule(.lc,.c) all :: /* so it is first */ @: +UnlitNeededHere(depend) + #if GhcWithNativeCodeGen == YES GhcDriverNeededHere(depend all mkNativeHdr.o) /* we use its C-compiling know-how */ @@ -101,9 +103,3 @@ ExtraStuffToClean( $(H_FILES_FROM_LH_FILES) ) EtagsNeededHere(tags) /* need this to do "make tags" */ ClearTagsFile() CTagsTarget( $(H_FILES) ) - -LitStuffNeededHere(docs depend) -InfoStuffNeededHere(docs) - -LitDocRootTargetWithNamedOutput(root,lit,root-standalone) -LitDocRootTargetWithNamedOutput(c-as-asm,lit,c-as-asm-standalone) diff --git a/ghc/includes/Parallel.lh b/ghc/includes/Parallel.lh index cbf0e55..4d060cf 100644 --- a/ghc/includes/Parallel.lh +++ b/ghc/includes/Parallel.lh @@ -115,8 +115,9 @@ Get this out of the way. These are all null definitions. # define SET_TASK_ACTIVITY(act) /* nothing */ -# else -# ifdef GRAN +#endif + +#if defined(GRAN) # define GA_HDR_SIZE 1 @@ -130,13 +131,10 @@ Get this out of the way. These are all null definitions. PROCS(closure) = (W_)(procs) /* Set closure's location */ # define SET_GRAN_HDR(closure,pe) SET_PROCS(closure,pe) -# if defined(GRAN_TNG) # define SET_STATIC_PROCS(closure) , (W_) (Everywhere) -# else -# define SET_STATIC_PROCS(closure) , (W_) (MainPE) -# endif /* GRAN_TNG */ # define SET_TASK_ACTIVITY(act) /* nothing */ +#endif \end{code} %************************************************************************ @@ -154,7 +152,7 @@ for local closures that have no global address), and @setGA@ to store a new global address for a local closure which did not previously have one. \begin{code} -# else /* it must be PARallel (to end of file) */ +#if defined(PAR) # define GA_HDR_SIZE 0 @@ -445,13 +443,8 @@ Special info-table for local blocking queues. %************************************************************************ \begin{code} -# ifdef GRAN -# define HAVE_SPARK ((PendingSparksHd[REQUIRED_POOL] != Nil_closure) || \ - (PendingSparksHd[ADVISORY_POOL] != Nil_closure)) -# else # define HAVE_SPARK ((PendingSparksHd[REQUIRED_POOL] < PendingSparksTl[REQUIRED_POOL]) \ || (PendingSparksHd[ADVISORY_POOL] < PendingSparksTl[ADVISORY_POOL])) -# endif # define HAVE_WORK (RUNNING_THREAD || HAVE_SPARK) # define RUNNING_THREAD (CurrentTSO != NULL) @@ -470,33 +463,31 @@ This constant defines how many words of data we can pack into a single packet in the parallel (GUM) system. \begin{code} -# ifdef PAR void InitPackBuffer(STG_NO_ARGS); -P_ PackNearbyGraph PROTO((P_ closure,W_ *size)); P_ PackTSO PROTO((P_ tso, W_ *size)); P_ PackStkO PROTO((P_ stko, W_ *size)); P_ AllocateHeap PROTO((W_ size)); /* Doesn't belong */ -P_ get_closure_info PROTO((P_ closure, W_ *size, W_ *ptrs, W_ *nonptrs, W_ *vhs)); - -rtsBool isOffset PROTO((globalAddr *ga)), - isFixed PROTO((globalAddr *ga)); - void InitClosureQueue (STG_NO_ARGS); P_ DeQueueClosure(STG_NO_ARGS); void QueueClosure PROTO((P_ closure)); rtsBool QueueEmpty(STG_NO_ARGS); void PrintPacket PROTO((P_ buffer)); -void doGlobalGC(STG_NO_ARGS); -P_ UnpackGraph PROTO((W_ *buffer, globalAddr **gamap, W_ *nGAs)); -# endif +P_ get_closure_info PROTO((P_ closure, W_ *size, W_ *ptrs, W_ *nonptrs, W_ *vhs, char *type)); + +rtsBool isOffset PROTO((globalAddr *ga)), + isFixed PROTO((globalAddr *ga)); +void doGlobalGC(STG_NO_ARGS); + +P_ PackNearbyGraph PROTO((P_ closure,W_ *size)); +P_ UnpackGraph PROTO((W_ *buffer, globalAddr **gamap, W_ *nGAs)); \end{code} \begin{code} -# define PACK_HEAP_REQUIRED \ - ((RTSflags.ParFlags.packBufferSize - PACK_HDR_SIZE) / (PACK_GA_SIZE + _FHS) * (SPEC_HS + 2)) +# define PACK_HEAP_REQUIRED \ + ((RTSflags.ParFlags.packBufferSize - PACK_HDR_SIZE) / (PACK_GA_SIZE + _FHS) * (SPEC_HS + 2)) extern W_ *PackBuffer; /* size: can be set via option */ extern long *buffer; /* HWL_ */ @@ -518,12 +509,55 @@ extern void AllocClosureQueue(W_ size); # define PACK_HDR_SIZE 1 /* Words of header in a packet */ # define PACK_PLC_SIZE 2 /* Size of a packed PLC in words */ - + +#endif \end{code} -End multi-slurp protection: \begin{code} -# endif /* yes, it is PARallel */ -#endif /* it was GRAN or PARallel */ + +#if defined(GRAN) +/* ToDo: Check which of the PAR routines are needed in GranSim -- HWL */ +void InitPackBuffer(STG_NO_ARGS); +P_ AllocateHeap PROTO((W_ size)); /* Doesn't belong */ +P_ PackNearbyGraph PROTO((P_ closure, P_ tso, W_ *packbuffersize)); +P_ PackOneNode PROTO((P_ closure, P_ tso, W_ *packbuffersize)); +P_ UnpackGraph PROTO((P_ buffer)); + +void InitClosureQueue (STG_NO_ARGS); +P_ DeQueueClosure(STG_NO_ARGS); +void QueueClosure PROTO((P_ closure)); +rtsBool QueueEmpty(STG_NO_ARGS); +void PrintPacket PROTO((P_ buffer)); + +P_ get_closure_info PROTO((P_ closure, W_ *size, W_ *ptrs, W_ *nonptrs, W_ *vhs, char *type)); + +/* These are needed in the packing code to get the size of the packet + right. The closures itself are never built in GrAnSim. */ +# define FETCHME_VHS IND_VHS +# define FETCHME_HS IND_HS + +# define FETCHME_GA_LOCN FETCHME_HS + +# define FETCHME_CLOSURE_SIZE(closure) IND_CLOSURE_SIZE(closure) +# define FETCHME_CLOSURE_NoPTRS(closure) 0L +# define FETCHME_CLOSURE_NoNONPTRS(closure) (IND_CLOSURE_SIZE(closure)-IND_VHS) + +# define MAX_GAS (RTSflags.GranFlags.packBufferSize / PACK_GA_SIZE) +# define PACK_GA_SIZE 3 /* Size of a packed GA in words */ + /* Size of a packed fetch-me in words */ +# define PACK_FETCHME_SIZE (PACK_GA_SIZE + FIXED_HS) +# define PACK_HDR_SIZE 4 /* Words of header in a packet */ + +# define PACK_HEAP_REQUIRED \ + ((RTSflags.GranFlags.packBufferSize - PACK_HDR_SIZE) / (PACK_GA_SIZE + _FHS) * (SPEC_HS + 2)) + +# define PACK_FLAG_LOCN 0 +# define PACK_TSO_LOCN 1 +# define PACK_UNPACKED_SIZE_LOCN 2 +# define PACK_SIZE_LOCN 3 +# define MAGIC_PACK_FLAG 0xfabc +#endif #endif /* Parallel_H */ \end{code} + + diff --git a/ghc/includes/RtsFlags.lh b/ghc/includes/RtsFlags.lh index 9a7bbaa..c7a8af9 100644 --- a/ghc/includes/RtsFlags.lh +++ b/ghc/includes/RtsFlags.lh @@ -31,14 +31,14 @@ struct GC_FLAGS { 2 set: details of minor collections 4 set: details of major collections, except marking 8 set: ditto, but marking this time - 16 set: GC of MallocPtrs + 16 set: GC of ForeignObjs 32 set: GC of Concurrent things */ -#define DEBUG_TRACE_MINOR_GC 2 -#define DEBUG_TRACE_MAJOR_GC 4 -#define DEBUG_TRACE_MARKING 8 -#define DEBUG_TRACE_MALLOCPTRS 16 -#define DEBUG_TRACE_CONCURRENT 32 +#define DEBUG_TRACE_MINOR_GC 2 +#define DEBUG_TRACE_MAJOR_GC 4 +#define DEBUG_TRACE_MARKING 8 +#define DEBUG_TRACE_FOREIGNOBJS 16 +#define DEBUG_TRACE_CONCURRENT 32 rtsBool lazyBlackHoling; rtsBool doSelectorsAtGC; @@ -86,6 +86,13 @@ struct PROFILING_FLAGS { # define DESCRchar 'D' # define TYPEchar 'Y' # define TIMEchar 'T' + + char *ccSelector; + char *modSelector; + char *grpSelector; + char *descrSelector; + char *typeSelector; + char *kindSelector; }; #endif @@ -113,6 +120,83 @@ struct PAR_FLAGS { #ifdef GRAN struct GRAN_FLAGS { + rtsBool granSimStats; /* Full .gr profile (rtsTrue) or only END events? */ + rtsBool granSimStats_suppressed; /* No .gr profile at all */ + rtsBool granSimStats_Binary; + rtsBool granSimStats_Sparks; + rtsBool granSimStats_Heap; + rtsBool labelling; + W_ packBufferSize; + W_ packBufferSize_internal; + + I_ proc; /* number of processors */ + I_ max_fishes; /* max number of spark or thread steals */ + TIME time_slice; /* max time slice of one reduction thread */ + + /* Communication Cost Variables -- set in main program */ + W_ gran_latency; /* Latency for single packet */ + W_ gran_additional_latency; /* Latency for additional packets */ + W_ gran_fetchtime; + W_ gran_lunblocktime; /* Time for local unblock */ + W_ gran_gunblocktime; /* Time for global unblock */ + W_ gran_mpacktime; /* Cost of creating a packet */ + W_ gran_munpacktime; /* Cost of receiving a packet */ + W_ gran_mtidytime; /* Cost of cleaning up after send */ + + W_ gran_threadcreatetime; /* Thread creation costs */ + W_ gran_threadqueuetime; /* Cost of adding a thread to the running/runnable queue */ + W_ gran_threaddescheduletime; /* Cost of descheduling a thread */ + W_ gran_threadscheduletime; /* Cost of scheduling a thread */ + W_ gran_threadcontextswitchtime; /* Cost of context switch */ + + /* Instruction Costs */ + W_ gran_arith_cost; /* arithmetic instructions (+,i,< etc) */ + W_ gran_branch_cost; /* branch instructions */ + W_ gran_load_cost; /* load into register */ + W_ gran_store_cost; /* store into memory */ + W_ gran_float_cost; /* floating point operations */ + + W_ gran_heapalloc_cost; /* heap allocation costs */ + + /* Overhead for granularity control mechanisms */ + /* overhead per elem of spark queue */ + W_ gran_pri_spark_overhead; + /* overhead per elem of thread queue */ + W_ gran_pri_sched_overhead; + + /* GrAnSim-Light: This version puts no bound on the number of + processors but in exchange doesn't model communication costs + (all communication is 0 cost). Mainly intended to show maximal + degree of parallelism in the program (*not* to simulate the + execution on a real machine). */ + + rtsBool Light; + + rtsBool DoFairSchedule ; /* fair scheduling alg? default: unfair */ + rtsBool DoReScheduleOnFetch ; /* async. communication? */ + rtsBool DoStealThreadsFirst; /* prefer threads over sparks when stealing */ + rtsBool SimplifiedFetch; /* fast but inaccurate fetch modelling */ + rtsBool DoAlwaysCreateThreads; /* eager thread creation */ + rtsBool DoGUMMFetching; /* bulk fetching */ + rtsBool DoThreadMigration; /* allow to move threads */ + I_ FetchStrategy; /* what to do when waiting for data */ + rtsBool PreferSparksOfLocalNodes; /* prefer local over global sparks */ + rtsBool DoPrioritySparking; /* sparks sorted by priorities */ + rtsBool DoPriorityScheduling; /* threads sorted by priorities */ + I_ SparkPriority; /* threshold for cut-off mechanism */ + I_ SparkPriority2; + rtsBool RandomPriorities; + rtsBool InversePriorities; + rtsBool IgnorePriorities; + I_ ThunksToPack; /* number of thunks in packet + 1 */ + rtsBool RandomSteal; /* steal spark/thread from random proc */ + rtsBool NoForward; /* no forwarding of fetch messages */ + rtsBool PrintFetchMisses; /* print number of fetch misses */ + + W_ debug; + rtsBool event_trace; + rtsBool event_trace_all; + }; #endif /* GRAN */ diff --git a/ghc/includes/RtsTypes.lh b/ghc/includes/RtsTypes.lh index a72694c..7e22652 100644 --- a/ghc/includes/RtsTypes.lh +++ b/ghc/includes/RtsTypes.lh @@ -70,43 +70,6 @@ typedef W_ TIME; typedef GLOBAL_TASK_ID PROC; #endif -#if defined(GRAN) || defined(PAR) -/* Granularity event types for output */ -enum gran_event_types { - GR_START = 0, GR_STARTQ, - GR_STEALING, GR_STOLEN, GR_STOLENQ, - GR_FETCH, GR_REPLY, GR_BLOCK, GR_RESUME, GR_RESUMEQ, - GR_SCHEDULE, GR_DESCHEDULE, - GR_END, - SP_SPARK, SP_SPARKAT, SP_USED, SP_PRUNED, SP_EXPORTED, SP_ACQUIRED, - GR_TERMINATE, - GR_EVENT_MAX -}; - -#endif - -#ifdef GRAN - -typedef struct spark -{ - struct spark *prev, *next; - P_ node; - I_ name, global; -} *sparkq; - -typedef struct event { - PROC proc; /* Processor id */ - PROC creator; /* Processor id of PE that created the event */ - EVTTYPE evttype; /* Event type */ - TIME time; /* Time at which event happened */ - P_ tso; /* Associated TSO, if relevant, Nil_closure otherwise*/ - P_ node; /* Associated node, if relevant, Nil_closure otherwise*/ - sparkq spark; /* Associated SPARK, if relevant, NULL otherwise */ - struct event *next; - } *eventq; - -#endif - \end{code} A cost centre is represented by a pointer to a static structure @@ -124,24 +87,32 @@ typedef struct cc { char *module; /* name of module in which _scc_ occurs */ char *group; /* name of group in which _scc_ occurs */ - char is_subsumed; /* '\0' => *not* a CAF or dict cc */ - /* 'C' => *is* a CAF cc */ - /* 'D' => *is* a dictionary cc */ + char is_subsumed; /* 'B' => *not* a CAF/dict/sub cc */ + /* 'S' => *is* a subsumed cc */ + /* 'c' => *is* a CAF cc */ + /* 'd' => *is* a dictionary cc */ + /* IS_CAF_OR_DICT tests for lowercase bit */ /* Statistics Gathered */ W_ scc_count; /* no of scc expression instantiations */ W_ sub_scc_count; /* no of scc's set inside this cc */ - W_ cafcc_count; /* no of scc expression instantiations */ W_ sub_cafcc_count; /* no of scc's set inside this cc */ + W_ sub_dictcc_count; /* no of scc's set inside this cc */ +#if defined(PROFILING_DETAIL_COUNTS) W_ thunk_count; /* no of {thunk,function,PAP} enters */ W_ function_count; /* in this cost centre */ W_ pap_count; + W_ mem_allocs; /* no of allocations */ + + W_ subsumed_fun_count; /* no of functions subsumed */ + W_ subsumed_caf_count; /* no of caf/dict funs subsumed */ + W_ caffun_subsumed; /* no of subsumes from this caf/dict */ +#endif W_ time_ticks; /* no of timer interrupts -- current interval */ W_ prev_ticks; /* no of timer interrupts -- previous intervals */ - W_ mem_allocs; /* no of allocations */ W_ mem_alloc; /* no of words allocated (excl CC_HDR) */ /* Heap Profiling by Cost Centre */ @@ -150,6 +121,12 @@ typedef struct cc { } *CostCentre; +#if defined(PROFILING_DETAIL_COUNTS) +#define INIT_CC_STATS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +#else +#define INIT_CC_STATS 0,0,0,0,0,0,0,0 +#endif + #endif /* defined(PROFILING) || defined(CONCURRENT) */ \end{code} diff --git a/ghc/includes/SMClosures.lh b/ghc/includes/SMClosures.lh index 326eaf3..fc20664 100644 --- a/ghc/includes/SMClosures.lh +++ b/ghc/includes/SMClosures.lh @@ -506,71 +506,75 @@ they will hear about it soon enough (WDP 95/05). %************************************************************************ %* * -\subsubsection[MallocPtr-closures]{@MallocPtr@ closure macros} +\subsubsection[ForeignObj-closures]{@ForeignObj@ closure macros} %* * %************************************************************************ -Here's what a MallocPtr looks like: +Here's what a ForeignObj looks like: \begin{verbatim} -+----------+----------+------+------+ -| Info Ptr | Forward | Data | List | -+----------+----------+------+------+ ++----------+----------+------+-------------+------+ +| Info Ptr | Forward | Data | FreeRoutine | List | ++----------+----------+------+-------------+------+ \end{verbatim} -The list is a pointer to the next MallocPtr in the list of all -MallocPtrs. Note that it is essential that the garbage collector {\em +@List@ is a pointer to the next ForeignObj in the list of all +ForeignObjs. Note that it is essential that the garbage collector {\em not\/} follow this link but that the link must get updated with the new address. The optional @Forward@ field is used by copying collectors to insert the forwarding pointer into. (If we overwrite the @Data@ part, we -don't know which MallocPtr has just died; if we overwrite the @List@ part, -we can't traverse the list of all MallocPtrs.) +don't know which ForeignObj has just died; if we overwrite the @List@ part, +we can't traverse the list of all ForeignObjs.) + +The @FreeRoutine@ is a reference to the finalisation routine to call +when the @ForeignObj@ becomes garbage -- SOF 4/96 \begin{code} #if !defined(PAR) # if defined(_INFO_COPYING) -# define MallocPtr_VHS 1 +# define ForeignObj_VHS 1 # else -# define MallocPtr_VHS 0 +# define ForeignObj_VHS 0 # endif -# define MallocPtr_HS (FIXED_HS + MallocPtr_VHS) -# define MallocPtr_SIZE (MallocPtr_VHS + 2) +# define ForeignObj_HS (FIXED_HS + ForeignObj_VHS) +# define ForeignObj_SIZE (ForeignObj_VHS + 3) -# define MallocPtr_CLOSURE_NoPTRS(closure) 0 -# define MallocPtr_CLOSURE_DATA(closure) (((StgMallocPtr *)(closure))[MallocPtr_HS + 0]) -# define MallocPtr_CLOSURE_LINK(closure) (((StgPtrPtr) (closure))[MallocPtr_HS + 1]) +# define ForeignObj_CLOSURE_NoPTRS(closure) 0 +# define ForeignObj_CLOSURE_DATA(closure) (((StgForeignObj *)(closure))[ForeignObj_HS + 0]) +# define ForeignObj_CLOSURE_FINALISER(closure) (((StgForeignObj *)(closure))[ForeignObj_HS + 1]) +# define ForeignObj_CLOSURE_LINK(closure) (((StgPtrPtr) (closure))[ForeignObj_HS + 2]) -# define SET_MallocPtr_HDR(closure,infolbl,cc,size,ptrs) \ +# define SET_ForeignObj_HDR(closure,infolbl,cc,size,ptrs) \ SET_FIXED_HDR(closure,infolbl,cc) \end{code} -And to check that a Malloc ptr closure is valid +And to check that a Foreign ptr closure is valid \begin{code} -EXTDATA_RO(MallocPtr_info); +EXTDATA_RO(ForeignObj_info); # if defined(DEBUG) -# define CHECK_MallocPtr_CLOSURE( closure ) \ +# define CHECK_ForeignObj_CLOSURE( closure ) \ do { \ - CHECK_MallocPtr_InfoTable( closure ); \ + CHECK_ForeignObj_InfoTable( closure ); \ } while (0) -# define CHECK_MallocPtr_InfoTable( closure ) \ - ASSERT( (*((PP_)(closure))) == MallocPtr_info ) +# define CHECK_ForeignObj_InfoTable( closure ) \ + ASSERT( (*((PP_)(closure))) == ForeignObj_info ) -extern void Validate_MallocPtrList( P_ MPlist ); -# define VALIDATE_MallocPtrList( mplist ) Validate_MallocPtrList( mplist ) +extern void Validate_ForeignObjList( P_ MPlist ); +# define VALIDATE_ForeignObjList( mplist ) Validate_ForeignObjList( mplist ) # else /* !DEBUG */ -# define CHECK_MallocPtr_CLOSURE( closure ) /* nothing */ -# define VALIDATE_MallocPtrList( mplist ) /* nothing */ +# define CHECK_ForeignObj_CLOSURE( closure ) /* nothing */ +# define VALIDATE_ForeignObjList( mplist ) /* nothing */ # endif /* !DEBUG */ #endif /* !PAR */ @@ -812,8 +816,8 @@ variable header): #define DATA_CLOSURE_NoPTRS(closure) ((I_)0) #define DATA_CLOSURE_NoNONPTRS(closure) (DATA_CLOSURE_SIZE(closure) - DATA_VHS) -#define SET_DATA_HDR(closure,infolbl,cc,size,ptrs/*==0*/) \ - { SET_FIXED_HDR(closure,infolbl,cc); \ +#define SET_DATA_HDR(closure,infolbl,cc,size,ptrs) \ + { SET_FIXED_HDR(closure,infolbl,cc); \ DATA_CLOSURE_SIZE(closure) = (W_)(size); } \end{code} diff --git a/ghc/includes/SMInfoTables.lh b/ghc/includes/SMInfoTables.lh index 5cbbf06..071bce3 100644 --- a/ghc/includes/SMInfoTables.lh +++ b/ghc/includes/SMInfoTables.lh @@ -96,8 +96,8 @@ It can have the following values (defined in CostCentre.lh): A black hole. \item[@ARR_K@] An array. - \item[@MP_K@] - A Malloc Pointer. + \item[@ForeignObj_K@] + A Foreign object (non-Haskell heap resident). \item[@SPT_K@] The Stable Pointer table. (There should only be one of these but it represents a form of weak space leak since it can't shrink to meet @@ -336,7 +336,7 @@ Otherwise, we add the RBH info table pointer to the end of the normal info table and vice versa. \begin{code} -#ifdef PAR +#if defined(PAR) || defined(GRAN) # define RBH_INFO_OFFSET (GEN_INFO_OFFSET+GEN_INFO_WORDS) # define INCLUDE_SPEC_PADDING \ @@ -363,8 +363,13 @@ info table and vice versa. EXTFUN(RBH_entry); P_ convertToRBH PROTO((P_ closure)); +#if defined(GRAN) +void convertFromRBH PROTO((P_ closure)); +#elif defined(PAR) void convertToFetchMe PROTO((P_ closure, globalAddr *ga)); #endif + +#endif \end{code} %************************************************************************ @@ -711,7 +716,7 @@ MAYBE_DECLARE_RTBL(Spec_S,12,12) CAT2(_ScanMove_,size),CAT2(_PRIn_,ptrs)) \ } -#ifdef PAR +#if defined(PAR) || defined(GRAN) # define SPEC_U_ITBL(infolbl,entry_code,upd_code,liveness,tag,size,ptrs,localness,entry_localness,kind,descr,type) \ entry_localness(CAT2(RBH_,entry_code)); \ localness W_ infolbl[]; \ @@ -873,7 +878,7 @@ Compacting: only the PRStart (marking) routine needs to be special. \begin{code} -#ifdef PAR +#if defined(PAR) || defined(GRAN) # define SELECT_ITBL(infolbl,entry_code,upd_code,liveness,tag,size,ptrs,localness,entry_localness,select_word_i,kind,descr,type) \ entry_localness(CAT2(RBH_,entry_code)); \ localness W_ infolbl[]; \ @@ -1000,7 +1005,7 @@ MAYBE_DECLARE_RTBL(Gen_S,,) INCLUDE_COMPACTING_INFO(_ScanLink_S_N,_PRStart_N,_ScanMove_S,_PRIn_I) \ } -#ifdef PAR +#if defined(PAR) || defined(GRAN) # define GEN_U_ITBL(infolbl,entry_code,upd_code,liveness,tag,size,ptrs,localness,entry_localness,kind,descr,type) \ entry_localness(CAT2(RBH_,entry_code)); \ localness W_ infolbl[]; \ @@ -1274,7 +1279,7 @@ MAYBE_DECLARE_RTBL(Static,,) %************************************************************************ %* * -\subsection[MallocPtr_ITBL]{@MallocPtr_TBL@: @MallocPtr@ info-table} +\subsection[ForeignObj_ITBL]{@ForeignObj_TBL@: @ForeignObj@ info-table} %* * %************************************************************************ @@ -1287,25 +1292,25 @@ I'm assuming @SPEC_N@, so that we don't need to pad out the info table. (JSM) \begin{code} #if !defined(PAR) -# define MallocPtr_ITBL(infolbl,entry_code,upd_code,liveness,tag,size,ptrs,localness,entry_localness,kind,descr,type) /*size,ptrs unused*/ \ +# define ForeignObj_ITBL(infolbl,entry_code,upd_code,liveness,tag,size,ptrs,localness,entry_localness,kind,descr,type) /*size,ptrs unused*/ \ CAT_DECLARE(infolbl,kind,descr,type) \ entry_localness(entry_code); \ localness W_ infolbl[] = { \ (W_) entry_code \ ,(W_) tag \ - ,(W_) MK_REP_REF(MallocPtr,,) \ + ,(W_) MK_REP_REF(ForeignObj,,) \ INCLUDE_PROFILING_INFO(infolbl) \ } -MAYBE_DECLARE_RTBL(MallocPtr,,) +MAYBE_DECLARE_RTBL(ForeignObj,,) -# define MallocPtr_RTBL() \ - const W_ MK_REP_LBL(MallocPtr,,)[] = { \ +# define ForeignObj_RTBL() \ + const W_ MK_REP_LBL(ForeignObj,,)[] = { \ INCLUDE_TYPE_INFO(INTERNAL) \ - INCLUDE_SIZE_INFO(MallocPtr_SIZE, 0L) \ + INCLUDE_SIZE_INFO(ForeignObj_SIZE, 0L) \ INCLUDE_PAR_INFO \ - INCLUDE_COPYING_INFO(_Evacuate_MallocPtr,_Scavenge_MallocPtr) \ - SPEC_COMPACTING_INFO(_ScanLink_MallocPtr,_PRStart_MallocPtr,_ScanMove_MallocPtr,_PRIn_0) \ + INCLUDE_COPYING_INFO(_Evacuate_ForeignObj,_Scavenge_ForeignObj) \ + SPEC_COMPACTING_INFO(_ScanLink_ForeignObj,_PRStart_ForeignObj,_ScanMove_ForeignObj,_PRIn_0) \ } #endif /* !PAR */ @@ -1737,7 +1742,7 @@ during a return. /* Declare the phantom info table vectors (just Bool at the moment) */ #ifndef COMPILING_GHC -EXTDATA_RO(Bool_itblvtbl); +EXTDATA_RO(Prelude_Bool_itblvtbl); #endif \end{code} diff --git a/ghc/includes/SMcompact.lh b/ghc/includes/SMcompact.lh index 9fb25d8..c491b5b 100644 --- a/ghc/includes/SMcompact.lh +++ b/ghc/includes/SMcompact.lh @@ -85,7 +85,7 @@ extern StgScanFun _ScanLink_MuTuple; extern StgScanFun _ScanLink_PI; #endif -#ifdef PAR +#if defined(PAR) || defined(GRAN) extern StgScanFun _ScanLink_RBH_2_1; extern StgScanFun _ScanLink_RBH_3_1; extern StgScanFun _ScanLink_RBH_3_3; @@ -117,10 +117,11 @@ extern StgScanFun _ScanMove_RBH_11; extern StgScanFun _ScanMove_RBH_12; extern StgScanFun _ScanMove_RBH_S; +#endif /* PAR || GRAN */ -#else -extern StgScanFun _ScanLink_MallocPtr; -#endif /* PAR */ +#if !defined(PAR) || defined(GRAN) +extern StgScanFun _ScanLink_ForeignObj; +#endif extern StgScanFun _ScanLink_BH_N; extern StgScanFun _ScanLink_BH_U; @@ -158,7 +159,7 @@ extern StgScanFun _ScanMove_PI; #endif #ifndef PAR -extern StgScanFun _ScanMove_MallocPtr; +extern StgScanFun _ScanMove_ForeignObj; #endif /* !PAR */ extern StgScanFun _ScanMove_ImmuTuple; diff --git a/ghc/includes/SMcopying.lh b/ghc/includes/SMcopying.lh index 252fbfc..7667fb2 100644 --- a/ghc/includes/SMcopying.lh +++ b/ghc/includes/SMcopying.lh @@ -84,7 +84,7 @@ extern StgScavFun _Scavenge_Data; extern StgEvacFun _Evacuate_MuTuple; extern StgScavFun _Scavenge_MuTuple; -#ifdef PAR +#if defined(PAR) || defined(GRAN) extern StgEvacFun _Evacuate_RBH_2; extern StgEvacFun _Evacuate_RBH_3; extern StgEvacFun _Evacuate_RBH_4; @@ -117,11 +117,14 @@ extern StgScavFun _Scavenge_RBH_12_12; extern StgScavFun _Scavenge_RBH_N; extern StgScavFun _Scavenge_FetchMe; extern StgScavFun _Scavenge_BF; -#else -extern StgEvacFun _Evacuate_MallocPtr; -extern StgScavFun _Scavenge_MallocPtr; +#endif /* PAR || GRAN */ + +#if !defined(PAR) || defined(GRAN) +extern StgEvacFun _Evacuate_ForeignObj; +extern StgScavFun _Scavenge_ForeignObj; #endif /* PAR */ + extern StgEvacFun _Evacuate_BH_N; extern StgScavFun _Scavenge_BH_N; diff --git a/ghc/includes/SMinterface.lh b/ghc/includes/SMinterface.lh index 3069989..6b27286 100644 --- a/ghc/includes/SMinterface.lh +++ b/ghc/includes/SMinterface.lh @@ -54,10 +54,10 @@ typedef struct { #endif #ifndef PAR - P_ MallocPtrList; /* List of all Malloc Pointers (in new generation) */ + P_ ForeignObjList; /* List of all Foreign objects (in new generation) */ #if defined(GCap) || defined(GCgn) - P_ OldMallocPtrList; /* List of all Malloc Pointers in old generation */ + P_ OldForeignObjList; /* List of all Foreign objects in old generation */ #endif P_ StablePointerTable; @@ -82,9 +82,8 @@ Answer: They're on the heap in a "Stable Pointer Table". (ADR) #else # ifndef PAR # ifdef GRAN -# define SM_MAXROOTS (10 + (MAX_PROC*4) + 2 + (MAX_PROC*2) + MAX_SPARKS) - /* unthreaded + spark/thread queues + Current/Main TSOs - + events + sparks */ +# define SM_MAXROOTS (10 + (MAX_PROC*2) + 2 ) + /* unthreaded + hd/tl thread queues + Current/Main TSOs */ # else # define SM_MAXROOTS 5 /* See c-as-asm/HpOverflow.lc */ # endif @@ -150,7 +149,7 @@ roots. If we are using Appel's collector it also initialises the @OldLim@ field. In the sequential system, it also initialises the stable pointer table -and the @MallocPtr@ (and @OldMallocPtrList@) fields. +and the @ForeignObjList@ (and @OldForeignObjList@) fields. @collectHeap@ invokes the garbage collector that was requested at compile time. @reqsize@ is the size of the request (in words) that @@ -197,9 +196,9 @@ B stack arising from any update frame ``squeezing'' [sequential only]. \item The elements of @CAFlist@ and the stable pointers will be updated to point to the new locations of the closures they reference. -\item Any members of @MallocPtrList@ which became garbage should have -been reported (by calling @FreeMallocPtr@; and the @(Old)MallocPtrList@ -updated to contain only those Malloc Pointers which are still live. +\item Any members of @ForeignObjList@ which became garbage should have +been reported (by calling their finalising routines; and the @(Old)ForeignObjList@ +updated to contain only those Foreign objects which are still live. \end{itemize} \end{description} @@ -433,7 +432,7 @@ same, but without the saved SuA pointer. We store the following information concerning the stacks in a global structure. (sequential only). \begin{code} -#ifndef CONCURRENT +#if 1 /* ndef CONCURRENT * /? HWL */ typedef struct { PP_ botA; /* Points to bottom-most word of A stack */ @@ -470,7 +469,7 @@ in the info-table. #define _INFO_MARKING #else -/* NO_INFO_SPECIFIED (ToDo: an #error ???) */ +/* NO_INFO_SPECIFIED (ToDo: an #error ?) */ #endif #endif #endif diff --git a/ghc/includes/SMmark.lh b/ghc/includes/SMmark.lh index 2c6cb0b..764f418 100644 --- a/ghc/includes/SMmark.lh +++ b/ghc/includes/SMmark.lh @@ -49,7 +49,7 @@ extern F_ _PRStart_MuTuple(STG_NO_ARGS); extern F_ _PRStart_PI(STG_NO_ARGS); #endif -#ifdef PAR +#if defined(PAR) || defined(GRAN) extern F_ _PRStart_RBH_0(STG_NO_ARGS); extern F_ _PRStart_RBH_1(STG_NO_ARGS); extern F_ _PRStart_RBH_2(STG_NO_ARGS); @@ -66,9 +66,11 @@ extern F_ _PRStart_RBH_12(STG_NO_ARGS); extern F_ _PRStart_RBH_N(STG_NO_ARGS); extern F_ _PRStart_FetchMe(STG_NO_ARGS); extern F_ _PRStart_BF(STG_NO_ARGS); -#else -extern F_ _PRStart_MallocPtr(STG_NO_ARGS); -#endif /* PAR */ +#endif /* PAR || GRAN */ + +#if !defined(PAR) || defined(GRAN) +extern F_ _PRStart_ForeignObj(STG_NO_ARGS); +#endif #if defined(CONCURRENT) extern F_ _PRStart_StkO(STG_NO_ARGS); @@ -117,7 +119,7 @@ extern F_ _PRIn_I_Dyn(STG_NO_ARGS); extern F_ _PRIn_I_Tuple(STG_NO_ARGS); extern F_ _PRIn_I_MuTuple(STG_NO_ARGS); -#ifdef PAR +#if defined(PAR) || defined(GRAN) extern F_ _PRIn_BF(STG_NO_ARGS); extern F_ _PRIn_RBH_0(STG_NO_ARGS); extern F_ _PRIn_RBH_1(STG_NO_ARGS); @@ -133,9 +135,11 @@ extern F_ _PRIn_RBH_10(STG_NO_ARGS); extern F_ _PRIn_RBH_11(STG_NO_ARGS); extern F_ _PRIn_RBH_12(STG_NO_ARGS); extern F_ _PRIn_RBH_I(STG_NO_ARGS); -#else -extern F_ _PRIn_I_MallocPtr(STG_NO_ARGS); -#endif /* PAR */ +#endif /* PAR || GRAN */ + +#if !defined(PAR) || defined(GRAN) +extern F_ _PRIn_I_ForeignObj(STG_NO_ARGS); +#endif extern F_ _PRIn_Error(STG_NO_ARGS); diff --git a/ghc/includes/SMupdate.lh b/ghc/includes/SMupdate.lh index 7da6a10..de1d35c 100644 --- a/ghc/includes/SMupdate.lh +++ b/ghc/includes/SMupdate.lh @@ -348,7 +348,7 @@ EXTFUN(UpdatePAP); (IS_MUTABLE(INFO_PTR(closure)) && MUT_LINK(closure) != MUT_NOT_LINKED) # if defined(GRAN) -extern I_ AwakenBlockingQueue PROTO((P_)); +extern P_ AwakenBlockingQueue PROTO((P_)); # else extern void AwakenBlockingQueue PROTO((P_)); # endif diff --git a/ghc/includes/StgMacros.lh b/ghc/includes/StgMacros.lh index 5435220..baefd80 100644 --- a/ghc/includes/StgMacros.lh +++ b/ghc/includes/StgMacros.lh @@ -54,7 +54,15 @@ Mere abbreviations: General things; note: general-but-``machine-dependent'' macros are given in \tr{StgMachDeps.lh}. \begin{code} -#define STG_MAX(a,b) (((a)>=(b)) ? (a) : (b)) +I_ STG_MAX PROTO((I_, I_)); /* GCC -Wall loves prototypes */ + +extern STG_INLINE +I_ +STG_MAX(I_ a, I_ b) { return((a >= b) ? a : b); } +/* NB: the naive #define macro version of STG_MAX + can lead to exponential CPP explosion, if you + have very-nested STG_MAXes. +*/ /* Macros to combine two short words into a single @@ -1012,10 +1020,10 @@ which uses these anyway.) #if ! defined(__GNUC__) || ! defined(__STG_GCC_REGS__) -extern void ASSIGN_DBL PROTO((W_ [], StgDouble)); -extern StgDouble PK_DBL PROTO((W_ [])); -extern void ASSIGN_FLT PROTO((W_ [], StgFloat)); -extern StgFloat PK_FLT PROTO((W_ [])); +void ASSIGN_DBL PROTO((W_ [], StgDouble)); +StgDouble PK_DBL PROTO((W_ [])); +void ASSIGN_FLT PROTO((W_ [], StgFloat)); +StgFloat PK_FLT PROTO((W_ [])); #else /* yes, its __GNUC__ && we really want them */ @@ -1036,6 +1044,12 @@ extern StgFloat PK_FLT PROTO((W_ [])); #else /* ! sparc */ +/* (not very) forward prototype declarations */ +void ASSIGN_DBL PROTO((W_ [], StgDouble)); +StgDouble PK_DBL PROTO((W_ [])); +void ASSIGN_FLT PROTO((W_ [], StgFloat)); +StgFloat PK_FLT PROTO((W_ [])); + extern STG_INLINE void ASSIGN_DBL(W_ p_dest[], StgDouble src) @@ -1291,14 +1305,14 @@ void newArrZh_init PROTO((P_ result, I_ n, P_ init)); %************************************************************************ \begin{code} -ED_(Nil_closure); +ED_(Prelude_Z91Z93_closure); #define newSynchVarZh(r, hp) \ { \ ALLOC_PRIM(MUTUPLE_HS,3,0,MUTUPLE_HS+3) /* ticky ticky */; \ CC_ALLOC(CCC,MUTUPLE_HS+3,ARR_K); /* cc prof */ \ SET_SVAR_HDR(hp,EmptySVar_info,CCC); \ - SVAR_HEAD(hp) = SVAR_TAIL(hp) = SVAR_VALUE(hp) = Nil_closure; \ + SVAR_HEAD(hp) = SVAR_TAIL(hp) = SVAR_VALUE(hp) = Prelude_Z91Z93_closure; \ r = hp; \ } \end{code} @@ -1311,17 +1325,17 @@ extern void Yield PROTO((W_)); #define takeMVarZh(r, liveness, node) \ { \ while (INFO_PTR(node) != (W_) FullSVar_info) { \ - if (SVAR_HEAD(node) == Nil_closure) \ + if (SVAR_HEAD(node) == Prelude_Z91Z93_closure) \ SVAR_HEAD(node) = CurrentTSO; \ else \ TSO_LINK(SVAR_TAIL(node)) = CurrentTSO; \ - TSO_LINK(CurrentTSO) = (P_) Nil_closure; \ + TSO_LINK(CurrentTSO) = (P_) Prelude_Z91Z93_closure; \ SVAR_TAIL(node) = CurrentTSO; \ DO_YIELD(liveness << 1); \ } \ SET_INFO_PTR(node, EmptySVar_info); \ r = SVAR_VALUE(node); \ - SVAR_VALUE(node) = Nil_closure; \ + SVAR_VALUE(node) = Prelude_Z91Z93_closure; \ } #else @@ -1336,7 +1350,7 @@ extern void Yield PROTO((W_)); } \ SET_INFO_PTR(node, EmptySVar_info); \ r = SVAR_VALUE(node); \ - SVAR_VALUE(node) = Nil_closure; \ + SVAR_VALUE(node) = Prelude_Z91Z93_closure; \ } #endif @@ -1364,18 +1378,18 @@ extern void Yield PROTO((W_)); SET_INFO_PTR(node, FullSVar_info); \ SVAR_VALUE(node) = value; \ tso = SVAR_HEAD(node); \ - if (tso != (P_) Nil_closure) { \ + if (tso != (P_) Prelude_Z91Z93_closure) { \ if (DO_QP_PROF) \ STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \ - if (ThreadQueueHd == Nil_closure) \ + if (ThreadQueueHd == Prelude_Z91Z93_closure) \ ThreadQueueHd = tso; \ else \ TSO_LINK(ThreadQueueTl) = tso; \ ThreadQueueTl = tso; \ SVAR_HEAD(node) = TSO_LINK(tso); \ - TSO_LINK(tso) = (P_) Nil_closure; \ - if(SVAR_HEAD(node) == (P_) Nil_closure) \ - SVAR_TAIL(node) = (P_) Nil_closure; \ + TSO_LINK(tso) = (P_) Prelude_Z91Z93_closure; \ + if(SVAR_HEAD(node) == (P_) Prelude_Z91Z93_closure) \ + SVAR_TAIL(node) = (P_) Prelude_Z91Z93_closure; \ } \ } @@ -1393,18 +1407,18 @@ extern void Yield PROTO((W_)); SET_INFO_PTR(node, FullSVar_info); \ SVAR_VALUE(node) = value; \ tso = SVAR_HEAD(node); \ - if (tso != (P_) Nil_closure) { \ + if (tso != (P_) Prelude_Z91Z93_closure) { \ if (DO_QP_PROF) \ STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \ - if (RunnableThreadsHd == Nil_closure) \ + if (RunnableThreadsHd == Prelude_Z91Z93_closure) \ RunnableThreadsHd = tso; \ else \ TSO_LINK(RunnableThreadsTl) = tso; \ RunnableThreadsTl = tso; \ SVAR_HEAD(node) = TSO_LINK(tso); \ - TSO_LINK(tso) = (P_) Nil_closure; \ - if(SVAR_HEAD(node) == (P_) Nil_closure) \ - SVAR_TAIL(node) = (P_) Nil_closure; \ + TSO_LINK(tso) = (P_) Prelude_Z91Z93_closure; \ + if(SVAR_HEAD(node) == (P_) Prelude_Z91Z93_closure) \ + SVAR_TAIL(node) = (P_) Prelude_Z91Z93_closure; \ } \ } @@ -1434,11 +1448,11 @@ extern void Yield PROTO((W_)); #define readIVarZh(r, liveness, node) \ { \ if (INFO_PTR(node) != (W_) ImMutArrayOfPtrs_info) { \ - if (SVAR_HEAD(node) == Nil_closure) \ + if (SVAR_HEAD(node) == Prelude_Z91Z93_closure) \ SVAR_HEAD(node) = CurrentTSO; \ else \ TSO_LINK(SVAR_TAIL(node)) = CurrentTSO; \ - TSO_LINK(CurrentTSO) = (P_) Nil_closure; \ + TSO_LINK(CurrentTSO) = (P_) Prelude_Z91Z93_closure; \ SVAR_TAIL(node) = CurrentTSO; \ DO_YIELD(liveness << 1); \ } \ @@ -1481,12 +1495,12 @@ extern void Yield PROTO((W_)); EXIT(EXIT_FAILURE); \ } \ tso = SVAR_HEAD(node); \ - if (tso != (P_) Nil_closure) { \ - if (ThreadQueueHd == Nil_closure) \ + if (tso != (P_) Prelude_Z91Z93_closure) { \ + if (ThreadQueueHd == Prelude_Z91Z93_closure) \ ThreadQueueHd = tso; \ else \ TSO_LINK(ThreadQueueTl) = tso; \ - while(TSO_LINK(tso) != Nil_closure) { \ + while(TSO_LINK(tso) != Prelude_Z91Z93_closure) { \ if (DO_QP_PROF) \ STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \ tso = TSO_LINK(tso); \ @@ -1513,12 +1527,12 @@ extern void Yield PROTO((W_)); EXIT(EXIT_FAILURE); \ } \ tso = SVAR_HEAD(node); \ - if (tso != (P_) Nil_closure) { \ - if (RunnableThreadsHd == Nil_closure) \ + if (tso != (P_) Prelude_Z91Z93_closure) { \ + if (RunnableThreadsHd == Prelude_Z91Z93_closure) \ RunnableThreadsHd = tso; \ else \ TSO_LINK(RunnableThreadsTl) = tso; \ - while(TSO_LINK(tso) != Nil_closure) { \ + while(TSO_LINK(tso) != Prelude_Z91Z93_closure) { \ if (DO_QP_PROF) \ STGCALL3(void,(void *, char *, P_, P_),QP_Event2,do_qp_prof > 1 ? "RA" : "RG",tso,CurrentTSO); \ tso = TSO_LINK(tso); \ @@ -1568,12 +1582,12 @@ extern void Yield PROTO((W_)); #define delayZh(liveness, us) \ { \ - if (WaitingThreadsTl == Nil_closure) \ + if (WaitingThreadsTl == Prelude_Z91Z93_closure) \ WaitingThreadsHd = CurrentTSO; \ else \ TSO_LINK(WaitingThreadsTl) = CurrentTSO; \ WaitingThreadsTl = CurrentTSO; \ - TSO_LINK(CurrentTSO) = Nil_closure; \ + TSO_LINK(CurrentTSO) = Prelude_Z91Z93_closure; \ TSO_EVENT(CurrentTSO) = (W_) ((us) < 1 ? 1 : (us)); \ DO_YIELD(liveness << 1); \ } @@ -1593,24 +1607,55 @@ extern void Yield PROTO((W_)); /* ToDo: something for GRAN */ -#define waitZh(liveness, fd) \ +#define waitReadZh(liveness, fd) \ { \ - if (WaitingThreadsTl == Nil_closure) \ + if (WaitingThreadsTl == Prelude_Z91Z93_closure) \ WaitingThreadsHd = CurrentTSO; \ else \ TSO_LINK(WaitingThreadsTl) = CurrentTSO; \ WaitingThreadsTl = CurrentTSO; \ - TSO_LINK(CurrentTSO) = Nil_closure; \ + TSO_LINK(CurrentTSO) = Prelude_Z91Z93_closure; \ TSO_EVENT(CurrentTSO) = (W_) (-(fd)); \ DO_YIELD(liveness << 1); \ } #else -#define waitZh(liveness, fd) \ +#define waitReadZh(liveness, fd) \ + { \ + fflush(stdout); \ + fprintf(stderr, "waitRead#: unthreaded build.\n"); \ + EXIT(EXIT_FAILURE); \ + } + +#endif + +#ifdef CONCURRENT + +/* ToDo: something for GRAN */ + +#ifdef HAVE_SYS_TYPES_H +#include +#endif HAVE_SYS_TYPES_H */ + +#define waitWriteZh(liveness, fd) \ + { \ + if (WaitingThreadsTl == Prelude_Z91Z93_closure) \ + WaitingThreadsHd = CurrentTSO; \ + else \ + TSO_LINK(WaitingThreadsTl) = CurrentTSO; \ + WaitingThreadsTl = CurrentTSO; \ + TSO_LINK(CurrentTSO) = Prelude_Z91Z93_closure; \ + TSO_EVENT(CurrentTSO) = (W_) (-(fd+FD_SETSIZE)); \ + DO_YIELD(liveness << 1); \ + } + +#else + +#define waitWriteZh(liveness, fd) \ { \ fflush(stdout); \ - fprintf(stderr, "wait#: unthreaded build.\n"); \ + fprintf(stderr, "waitWrite#: unthreaded build.\n"); \ EXIT(EXIT_FAILURE); \ } @@ -1806,6 +1851,7 @@ do { \ \ newSP = SPT_POP(StorageMgrInfo.StablePointerTable); \ SPT_SPTR(StorageMgrInfo.StablePointerTable, newSP) = unstablePtr; \ + CHECK_SPT_CLOSURE( StorageMgrInfo.StablePointerTable ); \ stablePtr = newSP; \ } while (0) @@ -1864,53 +1910,100 @@ Anything with tag >= 0 is in WHNF, so we discard it. \begin{code} #ifdef CONCURRENT -ED_(Nil_closure); +ED_(Prelude_Z91Z93_closure); ED_(True_closure); #if defined(GRAN) -#define parZh(r,hp,node,rest) \ - PARZh(r,hp,node,rest,0,0) +#define parZh(r,node) \ + PARZh(r,node,1,0,0,0,0,0) + +#define parAtZh(r,node,where,identifier,gran_info,size_info,par_info,rest) \ + parATZh(r,node,where,identifier,gran_info,size_info,par_info,rest,1) -#define parAtZh(r,hp,node,where,identifier,rest) \ - parATZh(r,hp,node,where,identifier,rest,1) +#define parAtAbsZh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \ + parATZh(r,node,proc,identifier,gran_info,size_info,par_info,rest,2) -#define parAtForNowZh(r,hp,node,where,identifier,rest) \ - parATZh(r,hp,node,where,identifier,rest,0) +#define parAtRelZh(r,node,proc,identifier,gran_info,size_info,par_info,rest) \ + parATZh(r,node,proc,identifier,gran_info,size_info,par_info,rest,3) -#define parATZh(r,hp,node,where,identifier,rest,local) \ +#define parAtForNowZh(r,node,where,identifier,gran_info,size_info,par_info,rest) \ + parATZh(r,node,where,identifier,gran_info,size_info,par_info,rest,0) + +#define parATZh(r,node,where,identifier,gran_info,size_info,par_info,rest,local) \ { \ sparkq result; \ if (SHOULD_SPARK(node)) { \ - result = NewSpark((P_)node,identifier,local); \ - SAFESTGCALL3(void,(W_),GranSimSparkAt,result,where,identifier); \ + SaveAllStgRegs(); \ + { sparkq result; \ + result = NewSpark((P_)node,identifier,gran_info,size_info,par_info,local); \ + if (local==2) { /* special case for parAtAbs */ \ + GranSimSparkAtAbs(result,(I_)where,identifier);\ + } else if (local==3) { /* special case for parAtRel */ \ + GranSimSparkAtAbs(result,(I_)(CurrentProc+where),identifier); \ + } else { \ + GranSimSparkAt(result,where,identifier); \ + } \ + context_switch = 1; \ + } \ + RestoreAllStgRegs(); \ } else if (do_qp_prof) { \ I_ tid = threadId++; \ SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \ } \ - r = (rest); \ + r = 1; /* return code for successful spark -- HWL */ \ } -#define parLocalZh(r,hp,node,identifier,rest) \ - PARZh(r,hp,node,rest,identifier,1) +#define parLocalZh(r,node,identifier,gran_info,size_info,par_info,rest) \ + PARZh(r,node,rest,identifier,gran_info,size_info,par_info,1) + +#define parGlobalZh(r,node,identifier,gran_info,size_info,par_info,rest) \ + PARZh(r,node,rest,identifier,gran_info,size_info,par_info,0) -#define parGlobalZh(r,hp,node,identifier,rest) \ - PARZh(r,hp,node,rest,identifier,0) +#if 1 -#define PARZh(r,hp,node,rest,identifier,local) \ +#define PARZh(r,node,rest,identifier,gran_info,size_info,par_info,local) \ +{ \ + if (SHOULD_SPARK(node)) { \ + SaveAllStgRegs(); \ + { sparkq result; \ + result = NewSpark((P_)node,identifier,gran_info,size_info,par_info,local);\ + add_to_spark_queue(result); \ + GranSimSpark(local,(P_)node); \ + context_switch = 1; \ + } \ + RestoreAllStgRegs(); \ + } else if (do_qp_prof) { \ + I_ tid = threadId++; \ + SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \ + } \ + r = 1; /* return code for successful spark -- HWL */ \ +} + +#else + +#define PARZh(r,node,rest,identifier,gran_info,size_info,par_info,local) \ { \ sparkq result; \ if (SHOULD_SPARK(node)) { \ - result = NewSpark((P_)node,identifier,local); \ + result = NewSpark((P_)node,identifier,gran_info,size_info,par_info,local);\ ADD_TO_SPARK_QUEUE(result); \ SAFESTGCALL2(void,(W_),GranSimSpark,local,(P_)node); \ - /* context_switch = 1; not needed any more -- HWL */ \ + /* context_switch = 1; not needed any more -- HWL */ \ } else if (do_qp_prof) { \ I_ tid = threadId++; \ SAFESTGCALL2(void,(I_, P_),QP_Event0,tid,node); \ } \ - r = (rest); \ + r = 1; /* return code for successful spark -- HWL */ \ } +#endif + +#define copyableZh(r,node) \ + /* copyable not yet implemented!! */ + +#define noFollowZh(r,node) \ + /* noFollow not yet implemented!! */ + #else /* !GRAN */ extern I_ required_thread_count; @@ -1958,6 +2051,7 @@ extern I_ required_thread_count; r = 1; /* Should not be necessary */ \ } +#endif /* GRAN */ \end{code} The following seq# code should only be used in unoptimized code. @@ -1979,8 +2073,8 @@ ED_RO_(vtbl_seq); #define seqZh(r,liveness,node) \ ({ \ __label__ cont; \ - STK_CHK(liveness,0,2,0,0,0,0); \ - SpB -= BREL(2); \ + /* STK_CHK(liveness,0,2,0,0,0,0); */ \ + /* SpB -= BREL(2); */ \ SpB[BREL(0)] = (W_) RetReg; \ SpB[BREL(1)] = (W_) &&cont; \ RetReg = (StgRetAddr) vtbl_seq; \ @@ -1992,23 +2086,27 @@ ED_RO_(vtbl_seq); r = 1; /* Should be unnecessary */ \ }) -#endif /* GRAN */ #endif /* CONCURRENT */ \end{code} %************************************************************************ %* * -\subsubsection[StgMacros-malloc-ptrs]{Malloc Pointers} +\subsubsection[StgMacros-foreign-objects]{Foreign Objects} %* * %************************************************************************ -This macro is used to construct a MallocPtr on the heap after a ccall. -Since MallocPtr's are like arrays in many ways, this is heavily based -on the stuff for arrays above. +[Based on previous MallocPtr comments -- SOF] + +This macro is used to construct a ForeignObj on the heap. What this does is plug the pointer (which will be in a local -variable), into a fresh heap object and then sets a result (which will -be a register) to point to the fresh heap object. +variable) together with its finalising/free routine, into a fresh heap +object and then sets a result (which will be a register) to point +to the fresh heap object. + +To accommodate per-object finalisation, augment the macro with a +finalisation routine argument. Nothing spectacular, just plug the +pointer to the routine into the ForeignObj -- SOF 4/96 Question: what's this "SET_ACTIVITY" stuff - should I be doing this too? (It's if you want to use the SPAT profiling tools to @@ -2016,42 +2114,45 @@ characterize program behavior by ``activity'' -- tail-calling, heap-checking, etc. -- see Ticky.lh. It is quite specialized. WDP 95/1) +(Swapped first two arguments to make it come into line with what appears +to be `standard' format, return register then liveness mask. -- SOF 4/96) + \begin{code} #ifndef PAR -StgInt eqMallocPtr PROTO((StgMallocPtr p1, StgMallocPtr p2)); -void FreeMallocPtr PROTO((StgMallocPtr mp)); +StgInt eqForeignObj PROTO((StgForeignObj p1, StgForeignObj p2)); -#define constructMallocPtr(liveness, r, mptr) \ -do { \ - P_ result; \ - \ - HEAP_CHK(liveness, _FHS + MallocPtr_SIZE,0); \ - CC_ALLOC(CCC,_FHS + MallocPtr_SIZE,MallocPtr_K); /* cc prof */ \ +#define makeForeignObjZh(r, liveness, mptr, finalise) \ +do { \ + P_ result; \ + \ + HEAP_CHK((W_)liveness, _FHS + ForeignObj_SIZE,0); \ + CC_ALLOC(CCC,_FHS + ForeignObj_SIZE,ForeignObj_K); /* cc prof */ \ \ - result = Hp + 1 - (_FHS + MallocPtr_SIZE); \ - SET_MallocPtr_HDR(result,MallocPtr_info,CCC,_FHS + MallocPtr_SIZE,0); \ - MallocPtr_CLOSURE_DATA(result) = mptr; \ - MallocPtr_CLOSURE_LINK(result) = StorageMgrInfo.MallocPtrList; \ - StorageMgrInfo.MallocPtrList = result; \ + result = Hp + 1 - (_FHS + ForeignObj_SIZE); \ + SET_ForeignObj_HDR(result,ForeignObj_info,CCC,_FHS + ForeignObj_SIZE,0); \ + ForeignObj_CLOSURE_DATA(result) = (P_)mptr; \ + ForeignObj_CLOSURE_FINALISER(result) = (P_)finalise; \ + ForeignObj_CLOSURE_LINK(result) = StorageMgrInfo.ForeignObjList; \ + StorageMgrInfo.ForeignObjList = result; \ \ /* \ - printf("DEBUG: MallocPtr(0x%x) = <0x%x, 0x%x, 0x%x, 0x%x>\n", \ + printf("DEBUG: ForeignObj(0x%x) = <0x%x, 0x%x, 0x%x, 0x%x>\n", \ result, \ result[0],result[1], \ result[2],result[3]); \ */ \ - CHECK_MallocPtr_CLOSURE( result ); \ - VALIDATE_MallocPtrList( StorageMgrInfo.MallocPtrList ); \ + CHECK_ForeignObj_CLOSURE( result ); \ + VALIDATE_ForeignObjList( StorageMgrInfo.ForeignObjList ); \ \ (r) = (P_) result; \ } while (0) #else -#define constructMallocPtr(liveness, r, mptr) \ +#define makeForeignObjZh(r, liveness, mptr, finalise) \ do { \ fflush(stdout); \ - fprintf(stderr, "constructMallocPtr: no malloc pointer support.\n");\ + fprintf(stderr, "makeForeignObj#: no foreign object support.\n");\ EXIT(EXIT_FAILURE); \ } while(0) diff --git a/ghc/includes/StgTypes.lh b/ghc/includes/StgTypes.lh index 9a8dda1..24783ae 100644 --- a/ghc/includes/StgTypes.lh +++ b/ghc/includes/StgTypes.lh @@ -25,7 +25,7 @@ StgFloat & float \\ StgDouble & double \\ StgChar & unsigned char \\\hline StgStablePtr & long \\ -StgMallocPtr & (long *) \\ +StgForeignObj & (long *) \\ \end{tabular} %partain:\end{center} @@ -112,8 +112,8 @@ typedef StgChar *StgByteArray; typedef StgByteArray B_; typedef I_ StgStablePtr; /* Index into Stable Pointer Table */ -typedef P_ StgMallocPtr; /* (Probably) Pointer to object in C Heap */ -/* On any architecture, StgMallocPtr should be big enough to hold +typedef P_ StgForeignObj; /* (Probably) Pointer to object in C Heap */ +/* On any architecture, StgForeignObj should be big enough to hold the largest possible pointer. */ /* These are used to pass the do_full_collection flag to RealPerformGC diff --git a/ghc/includes/Threads.lh b/ghc/includes/Threads.lh index 7236d7d..4b9a722 100644 --- a/ghc/includes/Threads.lh +++ b/ghc/includes/Threads.lh @@ -9,18 +9,23 @@ \end{code} \begin{code} -#ifndef GRAN -#define GRAN_ALLOC_HEAP(n,liveness) /* nothing */ -#define GRAN_UNALLOC_HEAP(n,liveness) /* nothing */ -#define GRAN_FETCH() /* nothing */ -#define GRAN_FETCH_AND_RESCHEDULE(liveness) /* nothing */ -#define GRAN_RESCHEDULE(liveness, reenter) /* nothing */ -#define GRAN_EXEC(arith,branch,loads,stores,floats) /* nothing */ -#define GRAN_SPARK() /* nothing */ -#endif -\end{code} +#if defined(GRAN) + +#define sparkq sparkq +#define TYPE_OF_SPARK struct spark +#define TYPE_OF_SPARK_PTR sparkq +#define SIZE_OF_SPARK (sizeof(TYPE_OF_SPARK)) + +typedef struct spark +{ + struct spark *prev, *next; + P_ node; + I_ name, global; + I_ gran_info; +} *sparkq; + +#endif -\begin{code} #ifndef CONCURRENT #define OR_CONTEXT_SWITCH @@ -54,10 +59,15 @@ extern I_ context_switch; /* Flag set by signal handler */ #define ADVISORY_POOL 1 #define SPARK_POOLS 2 -#ifndef GRAN +#if !defined(GRAN) -extern PP_ PendingSparksBase[SPARK_POOLS], PendingSparksLim[SPARK_POOLS]; -extern PP_ PendingSparksHd[SPARK_POOLS], PendingSparksTl[SPARK_POOLS]; +#define TYPE_OF_SPARK PP_ +#define SIZE_OF_SPARK (sizeof(TYPE_OF_SPARK)) + +extern TYPE_OF_SPARK PendingSparksBase[SPARK_POOLS], + PendingSparksLim[SPARK_POOLS]; +extern TYPE_OF_SPARK PendingSparksHd[SPARK_POOLS], + PendingSparksTl[SPARK_POOLS]; extern I_ SparkLimit[SPARK_POOLS]; @@ -70,7 +80,10 @@ IF_RTS(extern void AwaitEvent(I_);) #else /* GRAN */ -extern sparkq PendingSparksHd[][SPARK_POOLS], PendingSparksTl[][SPARK_POOLS]; +extern TYPE_OF_SPARK_PTR PendingSparksBase[][SPARK_POOLS], + PendingSparksLim[][SPARK_POOLS]; +extern TYPE_OF_SPARK_PTR PendingSparksHd[][SPARK_POOLS], + PendingSparksTl[][SPARK_POOLS]; extern P_ RunnableThreadsHd[], RunnableThreadsTl[], WaitThreadsHd[], WaitThreadsTl[]; @@ -85,7 +98,7 @@ extern P_ RunnableThreadsHd[], RunnableThreadsTl[], IF_RTS(extern void PruneSparks(STG_NO_ARGS);) -#ifdef GRAN +#if defined(GRAN) /* Codes that can be used as params for ReSchedule */ /* I distinguish them from the values 0/1 in the -UGRAN setup for security */ @@ -94,177 +107,23 @@ IF_RTS(extern void PruneSparks(STG_NO_ARGS);) #define SAME_THREAD 11 #define NEW_THREAD SAME_THREAD #define CHANGE_THREAD 13 +#define END_OF_WORLD 14 -#define MAX_PROC (BITS_IN(W_)) /* Maximum number of PEs that can be simulated */ -extern W_ max_proc; - -extern W_ IdleProcs, Idlers; - -extern unsigned CurrentProc; -extern W_ CurrentTime[]; extern W_ SparksAvail, SurplusThreads; -/* Processor numbers to bitmasks and vice-versa */ -#define MainProc 0 - -#define PE_NUMBER(n) (1l << (long)n) -#define ThisPE PE_NUMBER(CurrentProc) -#define MainPE PE_NUMBER(MainProc) - -#define IS_LOCAL_TO(ga,proc) ((1l << (long) proc) & ga) - -/* These constants should eventually be program parameters */ - -/* Communication Cost Model (EDS-like), max_proc > 2. */ - -#define LATENCY 1000 /* Latency for single packet */ -#define ADDITIONAL_LATENCY 100 /* Latency for additional packets */ -#define BASICBLOCKTIME 10 -#define FETCHTIME (LATENCY*2+MSGUNPACKTIME) -#define LOCALUNBLOCKTIME 10 -#define GLOBALUNBLOCKTIME (LATENCY+MSGUNPACKTIME) - -extern W_ gran_latency, gran_additional_latency, gran_fetchtime, - gran_lunblocktime, gran_gunblocktime; - -#define MSGPACKTIME 0 /* Cost of creating a packet */ -#define MSGUNPACKTIME 0 /* Cost of receiving a packet */ - -extern W_ gran_mpacktime, gran_mtidytime, gran_munpacktime; - -/* Thread cost model */ -#define THREADCREATETIME (25+THREADSCHEDULETIME) -#define THREADQUEUETIME 12 /* Cost of adding a thread to the running/runnable queue */ -#define THREADDESCHEDULETIME 75 /* Cost of descheduling a thread */ -#define THREADSCHEDULETIME 75 /* Cost of scheduling a thread */ -#define THREADCONTEXTSWITCHTIME (THREADDESCHEDULETIME+THREADSCHEDULETIME) - -extern W_ gran_threadcreatetime, gran_threadqueuetime, - gran_threadscheduletime, gran_threaddescheduletime, - gran_threadcontextswitchtime; - -/* Instruction Cost model (SPARC, including cache misses) */ -#define ARITH_COST 1 -#define BRANCH_COST 2 -#define LOAD_COST 4 -#define STORE_COST 4 -#define FLOAT_COST 1 /* ? */ - -extern W_ gran_arith_cost, gran_branch_cost, - gran_load_cost, gran_store_cost, gran_float_cost, - gran_heapalloc_cost; - -/* Miscellaneous Parameters */ -extern I_ DoFairSchedule; -extern I_ DoReScheduleOnFetch; -extern I_ SimplifiedFetch; -extern I_ DoStealThreadsFirst; -extern I_ DoAlwaysCreateThreads; -extern I_ DoThreadMigration; -extern I_ DoGUMMFetching; -extern I_ FetchStrategy; -extern I_ PreferSparksOfLocalNodes; -/* These come from debug options -bD? */ -extern I_ NoForward; -extern I_ PrintFetchMisses, fetch_misses; -#if defined(COUNT) -extern I_ nUPDs, nUPDs_old, nUPDs_new, nUPDs_BQ, nPAPs, BQ_lens; -#endif - -extern I_ no_gr_profile; -extern I_ do_sp_profile; - -extern I_ NeedToReSchedule; - -extern void GranSimAllocate PROTO((I_, P_, W_)); -extern void GranSimUnAllocate PROTO((I_, P_, W_)); -extern I_ GranSimFetch PROTO((P_)); -extern void GranSimExec PROTO((W_,W_,W_,W_,W_)); -extern void GranSimSpark PROTO((W_,P_)); -extern void GranSimBlock (STG_NO_ARGS); -extern void PerformReschedule PROTO((W_, W_)); - -#if 0 /* 'ngo Dochmey */ - -#define GRAN_ALLOC_HEAP(n,liveness) STGCALL3(void,(),GranSimAllocate,n,0,0) -#define GRAN_UNALLOC_HEAP(n,liveness) STGCALL3(void,(),GranSimUnallocate,n,0,0) - -#define GRAN_FETCH() STGCALL1(I_,(),GranSimFetch,Node) - -#define GRAN_FETCH_AND_RESCHEDULE(liveness_mask) \ - do { if(liveness_mask&LIVENESS_R1) \ - STGCALL1(I_,(),GranSimFetch,Node); \ - GRAN_RESCHEDULE(liveness_mask,1); \ - } while(0) - -#define GRAN_RESCHEDULE(liveness_mask,reenter) \ - STGCALL2_GC(void,(), \ - PerformReschedule,liveness_mask,reenter) - -#define THREAD_CONTEXT_SWITCH(liveness_mask,reenter) \ - do { \ - if (context_switch /* OR_INTERVAL_EXPIRED */) { \ - GRAN_RESCHEDULE(liveness_mask,reenter); \ - } }while(0) - -#define GRAN_EXEC(arith,branch,load,store,floats) \ - STGCALL5(void,(),GranSimExec,arith,branch,load,store,floats) - - -#else /* 1 */ /* chu' Dochmey */ - -#define GRAN_ALLOC_HEAP(n,liveness) \ - SaveAllStgRegs(); \ - GranSimAllocate(n,0,0); \ - RestoreAllStgRegs(); - -#define GRAN_UNALLOC_HEAP(n,liveness) \ - SaveAllStgRegs(); \ - GranSimUnallocate(n,0,0); \ - RestoreAllStgRegs(); - -#define GRAN_FETCH() \ - SaveAllStgRegs(); \ - GranSimFetch(Node); \ - RestoreAllStgRegs(); - -#define GRAN_FETCH_AND_RESCHEDULE(liveness_mask) \ - do { if(liveness_mask&LIVENESS_R1) \ - SaveAllStgRegs(); \ - GranSimFetch(Node); \ - RestoreAllStgRegs(); \ - GRAN_RESCHEDULE(liveness_mask,1); \ - } while(0) - -#define GRAN_RESCHEDULE(liveness_mask,reenter) \ - PerformReschedule_wrapper(liveness_mask,reenter) - -#define THREAD_CONTEXT_SWITCH(liveness_mask,reenter) \ - do { \ - if (context_switch /* OR_INTERVAL_EXPIRED */) { \ - GRAN_RESCHEDULE(liveness_mask,reenter); \ - } }while(0) - -#define GRAN_EXEC(arith,branch,load,store,floats) \ - SaveAllStgRegs(); \ - GranSimExec(arith,branch,load,store,floats); \ - RestoreAllStgRegs(); - -#endif - +extern W_ CurrentTime[]; +extern I_ OutstandingFetches[], OutstandingFishes[]; +extern enum proc_status procStatus[]; -#define ADD_TO_SPARK_QUEUE(spark) \ - SPARK_NEXT(spark) = NULL; \ - SPARK_PREV(spark) = PendingSparksTl[CurrentProc][ADVISORY_POOL]; \ - if (PendingSparksHd[CurrentProc][ADVISORY_POOL] == NULL) \ - PendingSparksHd[CurrentProc][ADVISORY_POOL] = spark; \ - else \ - SPARK_NEXT(PendingSparksTl[CurrentProc][ADVISORY_POOL]) = spark; \ - PendingSparksTl[CurrentProc][ADVISORY_POOL] = spark; \ +# if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */ +# define FETCH_MASK_TSO 0x08000000 /* only bits 0, 1, 2 should be used */ + /* normally */ +extern P_ BlockedOnFetch[]; +# endif #endif /* GRAN */ -extern P_ CurrentTSO; /* thread state object now in use */ +extern P_ CurrentTSO; /* thread state object now in use */ extern P_ AvailableStack; extern P_ AvailableTSO; @@ -272,13 +131,29 @@ extern P_ AvailableTSO; extern I_ threadId; void ScheduleThreads PROTO((P_ topClosure)); + #if defined(GRAN) +#define OLD_SPARKNAME_MASK 0xffff0000 +#define NEW_SPARKNAME_MASK 0x0000ffff + void ReSchedule PROTO((int what_next)) STG_NORETURN; -#else +void add_to_spark_queue PROTO((sparkq)); +int set_sparkname PROTO((P_, int)); +int reset_sparkname PROTO((P_)); +I_ spark_queue_len PROTO((PROC, I_)); +sparkq delete_from_spark_queue PROTO((sparkq, sparkq)); +I_ thread_queue_len PROTO((PROC)); +void DisposeSparkQ PROTO((sparkq)); + +#else /* !GRAN */ + void ReSchedule PROTO((int again)) STG_NORETURN; + #endif + void EndThread(STG_NO_ARGS) STG_NORETURN; +/* ToDo: Check if these are still needed -- HWL */ void QP_Event0 PROTO((I_, P_)); void QP_Event1 PROTO((char *, P_)); void QP_Event2 PROTO((char *, P_, P_)); @@ -331,7 +206,8 @@ table for those values). #endif #if defined(GRAN) || defined(PAR) -#define TSO_GRAN_WORDS 15 + /* do we really need a whole statistics buffer in PAR setup? HWL*/ +#define TSO_GRAN_WORDS 17 #else #define TSO_GRAN_WORDS 0 #endif @@ -385,6 +261,8 @@ table for those values). #define TSO_GLOBALSPARKS_LOCN (TSO_GRAN_START + 12) #define TSO_LOCALSPARKS_LOCN (TSO_GRAN_START + 13) #define TSO_QUEUE_LOCN (TSO_GRAN_START + 14) +#define TSO_PRI_LOCN (TSO_GRAN_START + 15) +#define TSO_CLOCK_LOCN (TSO_GRAN_START + 16) #endif #define TSO_LINK(closure) (((PP_)closure)[TSO_LINK_LOCN]) @@ -416,6 +294,9 @@ table for those values). #define TSO_GLOBALSPARKS(closure) (((P_)closure)[TSO_GLOBALSPARKS_LOCN]) #define TSO_LOCALSPARKS(closure) (((P_)closure)[TSO_LOCALSPARKS_LOCN]) #define TSO_QUEUE(closure) (((P_)closure)[TSO_QUEUE_LOCN]) +#define TSO_PRI(closure) (((P_)closure)[TSO_PRI_LOCN]) +/* TSO_CLOCK is only needed in GrAnSim-Light */ +#define TSO_CLOCK(closure) (((P_)closure)[TSO_CLOCK_LOCN]) #define TSO_INTERNAL_PTR(closure) \ ((STGRegisterTable *)(((W_)(((P_)closure) \ @@ -451,6 +332,7 @@ Here are the various queues for GrAnSim-type events. #define Q_RUNNABLE 'A' #define Q_BLOCKED 'R' #define Q_FETCHING 'Y' +#define Q_MIGRATING 'B' \end{code} %************************************************************************ @@ -472,23 +354,33 @@ rtsBool Spark PROTO((P_ closure, rtsBool required)); #ifdef GRAN /* For GrAnSim sparks are currently mallocated -- HWL */ void DisposeSpark PROTO((sparkq spark)); +sparkq NewSpark PROTO((P_,I_,I_,I_,I_,I_)); + +/* # define MAX_EVENTS 1000 */ /* For GC Roots Purposes */ +# define MAX_SPARKS 0 /* i.e. infinite */ -# define MAX_SPARKS 2000 /* For GC Roots Purposes */ -# if defined(GRAN_TNG) -extern sparkq NewSpark PROTO((P_,I_,I_,I_)); -# else /* !GRAN_TNG */ -extern sparkq NewSpark PROTO((P_,I_,I_)); -# endif /* GRAN_TNG */ +#if defined(GRAN_JSM_SPARKS) +/* spark is a pointer into some sparkq (which is for JSM sparls just an + array of (struct sparks) */ +# define SPARK_PREV(spark) { fprintf(stderr,"Error: SPARK_PREV not supported for JSM sparks") \ + EXIT(EXIT_FAILURE); } +/* NB: SPARK_NEXT may only be used as a rhs but NOT as a lhs */ +# define SPARK_NEXT(spark) (spark++) +# define SPARK_NODE(spark) (P_)(spark->node) +# define SPARK_NAME(spark) (spark->name) +# define SPARK_GRAN_INFO(spark) (spark->gran_info) +# define SPARK_GLOBAL(spark) (spark->global) +# define SPARK_EXPORTED(spark) (SPARK_GLOBAL(spark) > 1) +#else # define SPARK_PREV(spark) (spark->prev) # define SPARK_NEXT(spark) (sparkq)(spark->next) -# define SPARK_NODE(spark) (P_)(spark->node) +# define SPARK_NODE(spark) (spark->node) # define SPARK_NAME(spark) (spark->name) -# if defined(GRAN_TNG) -# define SPARK_GRAN_INFO(spark) (spark->gran_info) -# endif /* GRAN_TNG */ +# define SPARK_GRAN_INFO(spark) (spark->gran_info) # define SPARK_GLOBAL(spark) (spark->global) # define SPARK_EXPORTED(spark) (SPARK_GLOBAL(spark) > 1) +#endif #endif /* GRAN */ \end{code} diff --git a/ghc/includes/config.h.in b/ghc/includes/config.h.in index 37bc54c..3c4c682 100644 --- a/ghc/includes/config.h.in +++ b/ghc/includes/config.h.in @@ -150,7 +150,7 @@ /* Define if you have the header file. */ #undef HAVE_TERMIOS_H -/* Define if you have the header file. */ +/* Define if you have the header file. */ #undef HAVE_TIME_H /* Define if you have the header file. */ diff --git a/ghc/includes/ghcSockets.h b/ghc/includes/ghcSockets.h index 5e7351f..53152cb 100644 --- a/ghc/includes/ghcSockets.h +++ b/ghc/includes/ghcSockets.h @@ -16,4 +16,35 @@ #include #include +/* acceptSocket.lc */ +StgInt acceptSocket PROTO((StgInt, StgAddr, StgAddr)); + +/* bindSocket.lc */ +StgInt bindSocket PROTO((StgInt, StgAddr, StgInt, StgInt)); + +/* connectSocket.lc */ +StgInt connectSocket PROTO((StgInt, StgAddr, StgInt, StgInt)); + +/* createSocket.lc */ +StgInt createSocket PROTO((StgInt, StgInt, StgInt)); + +/* getSockName.lc */ +StgInt getSockName PROTO((StgInt, StgAddr, StgAddr)); + +/* getPeerName.lc */ +StgInt getPeerName PROTO((StgInt, StgAddr, StgAddr)); + +/* listenSocket.lc */ +StgInt listenSocket PROTO((StgInt, StgInt)); + +/* shutdownSocket.lc */ +StgInt shutdownSocket PROTO((StgInt, StgInt)); + +/* readDescriptor.lc */ +StgInt readDescriptor PROTO((StgInt, StgAddr, StgInt)); + +/* writeDescriptor.lc */ +StgInt writeDescriptor PROTO((StgInt, StgAddr, StgInt)); + + #endif /* !GHC_SOCKETS_H */ diff --git a/ghc/includes/libposix.h b/ghc/includes/libposix.h index 4535061..4ce0cea 100644 --- a/ghc/includes/libposix.h +++ b/ghc/includes/libposix.h @@ -1,8 +1,4 @@ #ifndef LIBPOSIX_H -#ifdef HAVE_SYS_TYPES_H -#include -#endif /* HAVE_SYS_TYPES_H */ - #ifdef HAVE_SYS_WAIT_H #include #endif /* HAVE_SYS_WAIT_H */ diff --git a/ghc/includes/mkNativeHdr.lc b/ghc/includes/mkNativeHdr.lc index 2e2ae88..e590043 100644 --- a/ghc/includes/mkNativeHdr.lc +++ b/ghc/includes/mkNativeHdr.lc @@ -42,8 +42,8 @@ #define SM_CAFLIST OFFSET(StorageMgrInfo, StorageMgrInfo.CAFlist) #define SM_OLDMUTABLES OFFSET(StorageMgrInfo, StorageMgrInfo.OldMutables) #define SM_OLDLIM OFFSET(StorageMgrInfo, StorageMgrInfo.OldLim) -#define SM_MALLOCPTRLIST OFFSET(StorageMgrInfo, StorageMgrInfo.MallocPtrList) -#define SM_OLDMALLOCPTRLIST OFFSET(StorageMgrInfo, StorageMgrInfo.OldMallocPtrList) +#define SM_FOREIGNOBJLIST OFFSET(StorageMgrInfo, StorageMgrInfo.ForeignObjList) +#define SM_OLDFOREIGNOBJLIST OFFSET(StorageMgrInfo, StorageMgrInfo.OldForeignObjList) #define SM_STABLEPOINTERTABLE OFFSET(StorageMgrInfo, StorageMgrInfo.StablePointerTable) STGRegisterTable MainRegTable; @@ -98,9 +98,9 @@ main() printf("#define SM_OLDLIM %d\n", SM_OLDLIM); #endif #ifndef PAR - printf("#define SM_MALLOCPTRLIST %d\n", SM_MALLOCPTRLIST); + printf("#define SM_FOREIGNOBJLIST %d\n", SM_FOREIGNOBJLIST); #if defined(GCap) || defined(GCgn) - printf("#define SM_OLDMALLOCPTRLIST %d\n", SM_OLDMALLOCPTRLIST); + printf("#define SM_OLDFOREIGNOBJLIST %d\n", SM_OLDFOREIGNOBJLIST); #endif printf("#define SM_STABLEPOINTERTABLE %d\n", SM_STABLEPOINTERTABLE); #endif diff --git a/ghc/includes/stgdefs.h b/ghc/includes/stgdefs.h index 88b0f40..d6d7f66 100644 --- a/ghc/includes/stgdefs.h +++ b/ghc/includes/stgdefs.h @@ -87,6 +87,22 @@ extern int sscanf PROTO((const char *, const char *, ...)); /* end of hack */ #endif /* STDC_HEADERS */ +/* + * threadWaitWrite# uses FD_SETSIZE to distinguish + * between read file descriptors and write fd's. + * Hence we need to include , but + * is this the best place to do it? + * (the following has been moved from libposix.h) + */ + +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ + +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 +#endif + #if ! defined(EXIT_SUCCESS) || ! defined(EXIT_FAILURE) /* "stdlib.h" should have defined these; but at least on SunOS 4.1.3, this is not so. @@ -188,13 +204,18 @@ extern StgFunPtr returnMain(STG_NO_ARGS); extern StgFunPtr impossible_jump_after_switch(STG_NO_ARGS); /* hooks: user might write some of their own */ -extern void ErrorHdrHook PROTO((FILE *)); -extern void OutOfHeapHook PROTO((W_)); -extern void StackOverflowHook PROTO((I_)); -extern void MallocFailHook PROTO((I_, char *)); -extern void PatErrorHdrHook PROTO((FILE *)); -extern void PreTraceHook PROTO((FILE *)); -extern void PostTraceHook PROTO((FILE *)); +void ErrorHdrHook PROTO((FILE *)); +void OutOfHeapHook PROTO((W_)); +void StackOverflowHook PROTO((I_)); +#ifdef CONCURRENT +void NoRunnableThreadsHook (STG_NO_ARGS); +#endif +void MallocFailHook PROTO((I_, char *)); +void PatErrorHdrHook PROTO((FILE *)); +void PreTraceHook PROTO((FILE *)); +void PostTraceHook PROTO((FILE *)); +void defaultsHook (STG_NO_ARGS); +void initEachPEHook (STG_NO_ARGS); EXTFUN(startStgWorld); #ifdef CONCURRENT diff --git a/ghc/includes/stgio.h b/ghc/includes/stgio.h index 972b96e..26f09ee 100644 --- a/ghc/includes/stgio.h +++ b/ghc/includes/stgio.h @@ -17,7 +17,7 @@ StgInt createDirectory PROTO((StgByteArray)); char * strDup PROTO((const char *)); int setenviron PROTO((char **)); int copyenv (STG_NO_ARGS); -int setenv PROTO((char *)); +int _setenv PROTO((char *)); int delenv PROTO((char *)); /* errno.lc */ @@ -122,4 +122,39 @@ StgAddr toClockSec PROTO((StgInt, StgInt, StgInt, StgInt, StgInt, StgInt, StgInt /* writeFile.lc */ StgInt writeFile PROTO((StgAddr, StgAddr, StgInt)); +/* SOCKET THINGS ALL TOGETHER: */ + +#if 0 +LATER +/* acceptSocket.lc */ +StgInt acceptSocket(I_ sockfd, A_ peer, A_ addrlen); + +/* bindSocket.lc */ +StgInt bindSocket(I_ sockfd, A_ myaddr, I_ addrlen, I_ isUnixDomain); + +/* connectSocket.lc */ +StgInt connectSocket(I_ sockfd, A_ servaddr, I_ addrlen, I_ isUnixDomain); + +/* createSocket.lc */ +StgInt createSocket(I_ family, I_ type, I_ protocol); + +/* getPeerName.lc */ +StgInt getPeerName(int sockfd, struct sockaddr *peer, int *namelen); + +/* getSockName.lc */ +StgInt getSockName(int sockfd, struct sockaddr *peer, int *namelen); + +/* listenSocket.lc */ +StgInt listenSocket(int sockfd, int backlog); + +/* readDescriptor.lc */ +StgInt readDescriptor(int fd, char *buf, int nbytes); + +/* shutdownSocket.lc */ +StgInt shutdownSocket(int sockfd, int how); + +/* writeDescriptor.lc */ +StgInt writeDescriptor(int fd, char *buf, int nbytes); +#endif /* 0 */ + #endif /* ! STGIO_H */ diff --git a/ghc/includes/timezone.h b/ghc/includes/timezone.h index 75a287f..bedafdf 100644 --- a/ghc/includes/timezone.h +++ b/ghc/includes/timezone.h @@ -21,8 +21,8 @@ #else #if HAVE_TZNAME extern time_t timezone, altzone; -extern char *tmzone[2]; -#define ZONE(x) (((struct tm *)x)->tm_isdst ? tmzone[1] : tmzone[0]) +extern char *tzname[2]; +#define ZONE(x) (((struct tm *)x)->tm_isdst ? tzname[1] : tzname[0]) #define SETZONE(x,z) #define GMTOFF(x) (((struct tm *)x)->tm_isdst ? altzone : timezone) #endif