Clean import of pcc.
authorDavid Given <dg@cowlark.com>
Tue, 15 Mar 2016 20:13:07 +0000 (21:13 +0100)
committerDavid Given <dg@cowlark.com>
Tue, 15 Mar 2016 20:13:07 +0000 (21:13 +0100)
--HG--
branch : default-branch

261 files changed:
lang/pcc/UPSTREAM_VERSION [new file with mode: 0644]
lang/pcc/pcc/DATESTAMP [new file with mode: 0644]
lang/pcc/pcc/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/arch/amd64/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/amd64/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/amd64/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/amd64/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/amd64/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/amd64/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/arm/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/arm/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/arm/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/arm/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/arm/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/arm/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/hppa/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/hppa/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/hppa/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/hppa/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/hppa/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/hppa/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/i386/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/i386/flocal.c [new file with mode: 0644]
lang/pcc/pcc/arch/i386/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/i386/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/i386/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/i386/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/i386/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/i86/TODO [new file with mode: 0644]
lang/pcc/pcc/arch/i86/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/i86/flocal.c [new file with mode: 0644]
lang/pcc/pcc/arch/i86/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/i86/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/i86/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/i86/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/i86/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/TODO [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/m16c/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/m68k/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/m68k/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/m68k/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/m68k/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/m68k/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/m68k/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/mips/TODO [new file with mode: 0644]
lang/pcc/pcc/arch/mips/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/mips/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/mips/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/mips/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/mips/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/mips/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/nova/README [new file with mode: 0644]
lang/pcc/pcc/arch/nova/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/nova/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/nova/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/nova/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/nova/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/nova/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/README [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp10/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp11/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp11/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp11/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp11/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/pdp11/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/pdp11/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/README [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/powerpc/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/sparc64/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/sparc64/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/sparc64/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/sparc64/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/sparc64/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/sparc64/table.c [new file with mode: 0644]
lang/pcc/pcc/arch/vax/code.c [new file with mode: 0644]
lang/pcc/pcc/arch/vax/local.c [new file with mode: 0644]
lang/pcc/pcc/arch/vax/local2.c [new file with mode: 0644]
lang/pcc/pcc/arch/vax/macdefs.h [new file with mode: 0644]
lang/pcc/pcc/arch/vax/order.c [new file with mode: 0644]
lang/pcc/pcc/arch/vax/table.c [new file with mode: 0644]
lang/pcc/pcc/cc/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/cc/cc/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/cc/cc/cc.1 [new file with mode: 0644]
lang/pcc/pcc/cc/cc/cc.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/builtins.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/ccom.1 [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/cgram.y [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/dwarf.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/dwarf.h [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/gcc_compat.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/init.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/inline.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/main.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/optim.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/pass1.h [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/pftn.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/scan.l [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/softfloat.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/stabs.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/symtabs.c [new file with mode: 0644]
lang/pcc/pcc/cc/ccom/trees.c [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/cpc.c [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/cpp.1 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/cpp.c [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/cpp.h [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/cpy.y [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/scanner.l [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res1 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res10 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res11 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res12 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res13 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res14 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res15 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res15C [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res16 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res16C [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res17 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res18 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res2 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res3 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res4 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res5 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res6 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res7 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res8 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/res9 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test1 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test10 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test11 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test12 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test13 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test14 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test15 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test16 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test17 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test18 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test19 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test2 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test3 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test4 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test5 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test6 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test7 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test8 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/tests/test9 [new file with mode: 0644]
lang/pcc/pcc/cc/cpp/token.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/builtins.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/cgram.y [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/cxxcode.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/cxxdefs.h [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/gcc_compat.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/init.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/inline.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/main.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/optim.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/pass1.h [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/pftn.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/scan.l [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/softfloat.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/stabs.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/symtabs.c [new file with mode: 0644]
lang/pcc/pcc/cc/cxxcom/trees.c [new file with mode: 0644]
lang/pcc/pcc/cc/driver/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/cc/driver/driver.c [new file with mode: 0644]
lang/pcc/pcc/cc/driver/driver.h [new file with mode: 0644]
lang/pcc/pcc/cc/driver/platform.c [new file with mode: 0644]
lang/pcc/pcc/cc/driver/strlist.c [new file with mode: 0644]
lang/pcc/pcc/cc/driver/strlist.h [new file with mode: 0644]
lang/pcc/pcc/cc/driver/xalloc.c [new file with mode: 0644]
lang/pcc/pcc/cc/driver/xalloc.h [new file with mode: 0644]
lang/pcc/pcc/common/compat.c [new file with mode: 0644]
lang/pcc/pcc/common/compat.h [new file with mode: 0644]
lang/pcc/pcc/common/softfloat.h [new file with mode: 0644]
lang/pcc/pcc/common/unicode.c [new file with mode: 0644]
lang/pcc/pcc/common/unicode.h [new file with mode: 0644]
lang/pcc/pcc/config.guess [new file with mode: 0644]
lang/pcc/pcc/config.h.in [new file with mode: 0644]
lang/pcc/pcc/config.sub [new file with mode: 0644]
lang/pcc/pcc/configure [new file with mode: 0755]
lang/pcc/pcc/configure.ac [new file with mode: 0644]
lang/pcc/pcc/f77/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/f77/f77/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/f77/f77/f77.1 [new file with mode: 0644]
lang/pcc/pcc/f77/f77/f77.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/Makefile.in [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/data.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/defines.h [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/defs.h [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/equiv.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/error.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/exec.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/expr.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/ftypes.h [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/gram.dcl [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/gram.exec [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/gram.expr [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/gram.head [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/gram.io [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/init.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/intr.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/io.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/lex.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/main.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/misc.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/proc.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/put.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/putscj.c [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/scjdefs.h [new file with mode: 0644]
lang/pcc/pcc/f77/fcom/tokens [new file with mode: 0644]
lang/pcc/pcc/install-sh [new file with mode: 0755]
lang/pcc/pcc/mip/common.c [new file with mode: 0644]
lang/pcc/pcc/mip/manifest.h [new file with mode: 0644]
lang/pcc/pcc/mip/match.c [new file with mode: 0644]
lang/pcc/pcc/mip/mkext.c [new file with mode: 0644]
lang/pcc/pcc/mip/node.h [new file with mode: 0644]
lang/pcc/pcc/mip/optim2.c [new file with mode: 0644]
lang/pcc/pcc/mip/pass2.h [new file with mode: 0644]
lang/pcc/pcc/mip/reader.c [new file with mode: 0644]
lang/pcc/pcc/mip/regs.c [new file with mode: 0644]
lang/pcc/pcc/os/android/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/bsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/darwin/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/dragonfly/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/freebsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/inc/amd64.h [new file with mode: 0644]
lang/pcc/pcc/os/linux/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/litebsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/midnightbsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/minix/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/mirbsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/netbsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/nextstep/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/none/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/openbsd/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/openbsd/f77config.h [new file with mode: 0644]
lang/pcc/pcc/os/sunos/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/sysv4/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/win32/build.bat [new file with mode: 0644]
lang/pcc/pcc/os/win32/build_installer.bat [new file with mode: 0755]
lang/pcc/pcc/os/win32/ccconfig.h [new file with mode: 0644]
lang/pcc/pcc/os/win32/config.h [new file with mode: 0644]
lang/pcc/pcc/os/win32/pcc.iss [new file with mode: 0644]

diff --git a/lang/pcc/UPSTREAM_VERSION b/lang/pcc/UPSTREAM_VERSION
new file mode 100644 (file)
index 0000000..df6ac44
--- /dev/null
@@ -0,0 +1,2 @@
+ftp://pcc.ludd.ltu.se/pub/pcc/pcc-20160315.tgz
+
diff --git a/lang/pcc/pcc/DATESTAMP b/lang/pcc/pcc/DATESTAMP
new file mode 100644 (file)
index 0000000..4ed5216
--- /dev/null
@@ -0,0 +1 @@
+20160315
diff --git a/lang/pcc/pcc/Makefile.in b/lang/pcc/pcc/Makefile.in
new file mode 100644 (file)
index 0000000..1123e1a
--- /dev/null
@@ -0,0 +1,29 @@
+#      $Id: Makefile.in,v 1.9 2011/06/07 13:56:05 plunky Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+@SET_MAKE@
+
+ALL_SUBDIRS=   cc
+DIST_SUBDIRS=  $(ALL_SUBDIRS) f77
+
+all install clean:
+       @for subdir in $(ALL_SUBDIRS); do \
+               _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \
+               echo "===> $$_nextdir_"; \
+               (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \
+                   exec $(MAKE) $(MFLAGS) $@) || exit $$?; \
+               echo "<=== $$_nextdir_"; \
+       done
+
+distclean:
+       @for subdir in $(DIST_SUBDIRS); do \
+               _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \
+               echo "===> $$_nextdir_"; \
+               (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \
+                   exec $(MAKE) $(MFLAGS) $@) || exit $$?; \
+               echo "<=== $$_nextdir_"; \
+       done
+       rm -rf Makefile config.log stamp-h1 config.status \
+           configure.lineno config.h autom4te.cache
diff --git a/lang/pcc/pcc/arch/amd64/code.c b/lang/pcc/pcc/arch/amd64/code.c
new file mode 100644 (file)
index 0000000..673b750
--- /dev/null
@@ -0,0 +1,1253 @@
+/*     $Id: code.c,v 1.85 2015/12/13 09:00:04 ragge Exp $      */
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+#ifndef LANG_CXX
+#undef NIL
+#define        NIL NULL
+#define        NODE P1ND
+#define        nfree p1nfree
+#define        ccopy p1tcopy
+#define        tfree p1tfree
+#endif
+
+static int nsse, ngpr, nrsp, rsaoff;
+static int thissse, thisgpr, thisrsp;
+enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87,
+       STRREG, STRMEM, STRSSE, STRIF, STRFI, STRX87 };
+static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
+/*
+ * The Register Save Area looks something like this.
+ * It is put first on stack with fixed offsets.
+ * struct {
+ *     long regs[6];
+ *     double xmm[8][2]; // 16 byte in width
+ * };
+ */
+#define        RSASZ           (6*SZLONG+8*2*SZDOUBLE)
+#define        RSALONGOFF(x)   (RSASZ-(x)*SZLONG)
+#define        RSADBLOFF(x)    ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
+/* va_list */
+#define        VAARGSZ         (SZINT*2+SZPOINT(CHAR)*2)
+#define        VAGPOFF(x)      (x)
+#define        VAFPOFF(x)      (x-SZINT)
+#define        VAOFA(x)        (x-SZINT-SZINT)
+#define        VARSA(x)        (x-SZINT-SZINT-SZPOINT(0))
+
+static int stroffset;
+
+static int varneeds;
+#define        NEED_1FPREF      001
+#define        NEED_2FPREF      002
+#define        NEED_1REGREF     004
+#define        NEED_2REGREF     010
+#define        NEED_MEMREF      020
+#define        NEED_STRFI       040
+#define        NEED_STRIF      0100
+
+static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
+static NODE *movtomem(NODE *p, int off, int reg);
+static NODE *movtoreg(NODE *p, int rno);
+void varattrib(char *name, struct attr *sap);
+
+/*
+ * Print out assembler segment name.
+ */
+#ifdef MACHOABI
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case RDATA: name = ".const"; break;
+       case STRNG: name = ".cstring"; break;
+       case UDATA: break;
+       case CTORS: name = ".mod_init_func"; break;
+       case DTORS: name = ".mod_term_func"; break;
+       default:
+               cerror("unknown seg %d", seg);
+       }
+       printf("\t%s\n", name);
+}
+
+#else
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+       case UDATA: break;
+       case PICLDATA:
+       case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
+       case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
+       case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+#endif
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       name = getexname(sp);
+
+       if (sp->sclass == EXTDEF) {
+               printf("\t.globl %s\n", name);
+#ifndef MACHOABI
+               if (ISFTN(sp->stype)) {
+                       printf("\t.type %s,@function\n", name);
+               } else {
+                       printf("\t.type %s,@object\n", name);
+                       printf("\t.size %s,%d\n", name,
+                           (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
+               }
+#endif
+       }
+       if (sp->slevel == 0)
+               printf("%s:\n", name);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ * The return value is in (or pointed to by) RETREG.
+ */
+void
+efcode(void)
+{
+       struct symtab *sp;
+       extern int gotnr;
+       TWORD t;
+       NODE *p, *r, *l;
+       int typ;
+
+       gotnr = 0;      /* new number for next fun */
+       sp = cftnsp;
+       t = DECREF(sp->stype);
+       if (t != STRTY && t != UNIONTY)
+               return;
+
+       /* XXX should have one routine for this */
+       ngpr = nsse = 0;
+       typ = argtyp(t, sp->sdf, sp->sap);
+       if (typ == STRMEM) {
+               r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
+               regno(r) = RAX;
+               r = buildtree(UMUL, r, NIL);
+               l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
+               l = buildtree(UMUL, l, NIL);
+               ecomp(buildtree(ASSIGN, l, r));
+               l = block(REG, NIL, NIL, LONG, 0, 0);
+               regno(l) = RAX;
+               r = tempnode(stroffset, LONG, 0, 0);
+               ecomp(buildtree(ASSIGN, l, r));
+       } else if (typ == STRX87) {
+               p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
+               regno(p) = RAX;
+               p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
+               ecomp(movtoreg(p, 041));
+               p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
+               regno(p) = RAX;
+               p = buildtree(UMUL, p, NIL);
+               ecomp(movtoreg(p, 040));
+       } else {
+               TWORD t1, t2;
+               int r1, r2;
+               if (typ == STRSSE || typ == STRFI)
+                       r1 = XMM0, t1 = DOUBLE;
+               else
+                       r1 = RAX, t1 = LONG;
+               if (typ == STRSSE)
+                       r2 = XMM1, t2 = DOUBLE;
+               else if (typ == STRFI)
+                       r2 = RAX, t2 = LONG;
+               else if (typ == STRIF)
+                       r2 = XMM0, t2 = DOUBLE;
+               else /* if (typ == STRREG) */
+                       r2 = RDX, t2 = LONG;
+
+               if (tsize(t, sp->sdf, sp->sap) > SZLONG) {
+                       p = block(REG, NIL, NIL, INCREF(t2), 0, 0);
+                       regno(p) = RAX;
+                       p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
+                       ecomp(movtoreg(p, r2));
+               }
+               p = block(REG, NIL, NIL, INCREF(t1), 0, 0);
+               regno(p) = RAX;
+               p = buildtree(UMUL, p, NIL);
+               ecomp(movtoreg(p, r1));
+       }
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **s, int cnt)
+{
+       union arglist *al;
+       struct symtab *sp;
+       NODE *p, *r;
+       TWORD t;
+       int i, rno, typ, ssz;
+
+       /* recalculate the arg offset and create TEMP moves */
+       /* Always do this for reg, even if not optimizing, to free arg regs */
+       nsse = ngpr = 0;
+       nrsp = ARGINIT;
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               sp = cftnsp;
+               if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
+                       r = block(REG, NIL, NIL, LONG, 0, 0);
+                       regno(r) = argregsi[ngpr++];
+                       p = tempnode(0, r->n_type, r->n_df, r->n_ap);
+                       stroffset = regno(p);
+                       ecomp(buildtree(ASSIGN, p, r));
+               }
+       }
+
+       for (i = 0; i < cnt; i++) {
+               sp = s[i];
+
+               if (sp == NULL)
+                       continue; /* XXX when happens this? */
+
+               ssz = tsize(sp->stype, sp->sdf, sp->sap);
+               switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
+               case INTEGER:
+               case SSE:
+                       if (typ == SSE)
+                               rno = XMM0 + nsse++;
+                       else
+                               rno = argregsi[ngpr++];
+                       r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+                       regno(r) = rno;
+                       p = tempnode(0, sp->stype, sp->sdf, sp->sap);
+                       sp->soffset = regno(p);
+                       sp->sflags |= STNODE;
+                       ecomp(buildtree(ASSIGN, p, r));
+                       break;
+
+               case SSEMEM:
+                       sp->soffset = nrsp;
+                       nrsp += SZDOUBLE;
+                       if (xtemps) {
+                               p = tempnode(0, sp->stype, sp->sdf, sp->sap);
+                               p = buildtree(ASSIGN, p, nametree(sp));
+                               sp->soffset = regno(p->n_left);
+                               sp->sflags |= STNODE;
+                               ecomp(p);
+                       }
+                       break;
+
+               case INTMEM:
+                       sp->soffset = nrsp;
+                       nrsp += SZLONG;
+                       if (xtemps) {
+                               p = tempnode(0, sp->stype, sp->sdf, sp->sap);
+                               p = buildtree(ASSIGN, p, nametree(sp));
+                               sp->soffset = regno(p->n_left);
+                               sp->sflags |= STNODE;
+                               ecomp(p);
+                       }
+                       break;
+
+               case STRX87:
+               case STRMEM: /* Struct in memory */
+                       sp->soffset = nrsp;
+                       nrsp += ssz;
+                       break;
+
+               case X87: /* long double args */
+                       sp->soffset = nrsp;
+                       nrsp += SZLDOUBLE;
+                       break;
+
+               case STRFI:
+               case STRIF:
+               case STRSSE:
+               case STRREG: /* Struct in register */
+                       autooff += (2*SZLONG);
+
+                       if (typ == STRSSE || typ == STRFI) {
+                               rno = XMM0 + nsse++;
+                               t = DOUBLE;
+                       } else {
+                               rno = argregsi[ngpr++];
+                               t = LONG;
+                       }
+                       r = block(REG, NIL, NIL, t, 0, 0);
+                       regno(r) = rno;
+                       ecomp(movtomem(r, -autooff, FPREG));
+
+                       if (ssz > SZLONG) {
+                               if (typ == STRSSE || typ == STRIF) {
+                                       rno = XMM0 + nsse++;
+                                       t = DOUBLE;
+                               } else {
+                                       rno = argregsi[ngpr++];
+                                       t = LONG;
+                               }
+                               r = block(REG, NIL, NIL, t, 0, 0);
+                               regno(r) = rno;
+                               ecomp(movtomem(r, -autooff+SZLONG, FPREG));
+                       }
+                       sp->soffset = -autooff;
+                       break;
+
+               default:
+                       cerror("bfcode: %d", typ);
+               }
+       }
+
+       /* Check if there are varargs */
+       if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
+               return; /* no prototype */
+       al = cftnsp->sdf->dfun;
+
+       for (; al->type != TELLIPSIS; al++) {
+               t = al->type;
+               if (t == TNULL)
+                       return;
+               if (ISSOU(BTYPE(t)))
+                       al++;
+               for (i = 0; t > BTMASK; t = DECREF(t))
+                       if (ISARY(t) || ISFTN(t))
+                               i++;
+               if (i)
+                       al++;
+       }
+
+       /* fix stack offset */
+       SETOFF(autooff, ALMAX);
+
+       /* Save reg arguments in the reg save area */
+       p = NIL;
+       for (i = ngpr; i < 6; i++) {
+               r = block(REG, NIL, NIL, LONG, 0, 0);
+               regno(r) = argregsi[i];
+               r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
+               p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
+       }
+       for (i = nsse; i < 8; i++) {
+               r = block(REG, NIL, NIL, DOUBLE, 0, 0);
+               regno(r) = i + XMM0;
+               r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
+               p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
+       }
+       autooff += RSASZ;
+       rsaoff = autooff;
+       thissse = nsse;
+       thisgpr = ngpr;
+       thisrsp = nrsp;
+
+       ecomp(p);
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+       if (flag)
+               return;
+
+#ifdef MACHOABI
+#define PT(x)
+#else
+#define        PT(x) printf(".type __pcc_" x ",@function\n")
+#endif
+
+#define        P(x) printf(x "\n")
+       /* printout varargs routines if used */
+       if (varneeds & NEED_STRFI) {    /* struct with one float and then int */
+               P(".text\n.align 4");
+               PT("strif");
+               P("__pcc_strif:");
+               P("cmpl $176,4(%%rdi)\njae .Ladd16");
+               P("cmpl $48,(%%rdi)\njae .Ladd16\n");
+               P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
+               P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
+               P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
+               P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
+               P("leaq 24(%%rdi),%%rax\nret");
+       }
+       if (varneeds & NEED_STRIF) {    /* struct with one int and one float */
+               P(".text\n.align 4");
+               PT("strif");
+               P("__pcc_strif:");
+               P("cmpl $176,4(%%rdi)\njae .Ladd16");
+               P("cmpl $48,(%%rdi)\njae .Ladd16\n");
+               P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
+               P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
+               P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
+               P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
+               P("leaq 24(%%rdi),%%rax\nret");
+       }
+       if (varneeds & NEED_2FPREF) {   /* struct with two float regs */
+               P(".text\n.align 4");
+               PT("2fpref");
+               P("__pcc_2fpref:");
+               P("cmpl $160,4(%%rdi)\njae .Ladd16");
+               P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
+               P("addl $32,4(%%rdi)");
+               P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
+               P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
+               P("leaq 24(%%rdi),%%rax\nret");
+       }
+       if (varneeds & NEED_1FPREF) {
+               printf(".text\n.align 4\n");
+               PT("1fpref");
+               printf("__pcc_1fpref:\n");
+               printf("cmpl $176,4(%%rdi)\njae .Ladd8\n");
+               printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+               printf("addl $16,4(%%rdi)\nret\n");
+       }
+       if (varneeds & NEED_1REGREF) {
+               printf(".text\n.align 4\n");
+               PT("1regref");
+               printf("__pcc_1regref:\n");
+               printf("cmpl $48,(%%rdi)\njae .Ladd8\n");
+               printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+               printf("addl $8,(%%rdi)\nret\n");
+       }
+       if (varneeds & NEED_2REGREF) {
+               printf(".text\n.align 4\n");
+               PT("2regref");
+               printf("__pcc_2regref:\n");
+               printf("cmpl $40,(%%rdi)\njae .Ladd16\n");
+               printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+               printf("addl $16,(%%rdi)\nret\n");
+       }
+       if (varneeds & NEED_MEMREF) {
+               printf(".text\n.align 4\n");
+               PT("memref");
+               printf("__pcc_memref:\n");
+               printf("movq 8(%%rdi),%%rax\n");
+               printf("addq %%rsi,8(%%rdi)\nret\n");
+       }
+
+       if (varneeds & (NEED_1FPREF|NEED_1REGREF)) {
+               P(".Ladd8:");
+               P("movq 8(%%rdi),%%rax");
+               P("addq $8,8(%%rdi)");
+               P("ret");
+       }
+       if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) {
+               P(".Ladd16:");
+               P("movq 8(%%rdi),%%rax");
+               P("addq $16,8(%%rdi)");
+               P("ret");
+       }
+
+#ifdef MACHOABI
+       printf("\t.ident \"PCC: %s\"\n", VERSSTR);
+#else
+       printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR);
+#endif
+}
+
+/*
+ * Varargs stuff:
+ * The ABI says that va_list should be declared as this typedef.
+ * We handcraft it here and then just reference it.
+ *
+ * typedef struct {
+ *     unsigned int gp_offset;
+ *     unsigned int fp_offset;
+ *     void *overflow_arg_area;
+ *     void *reg_save_area;
+ * } __builtin_va_list[1];
+ *
+ * ...actually, we allocate two of them and use the second one as 
+ * bounce buffers for floating point structs...
+ *
+ * There are a number of asm routines printed out if varargs are used:
+ *     long __pcc_gpnext(va)   - get a gpreg value
+ *     long __pcc_fpnext(va)   - get a fpreg value
+ *     void *__pcc_1regref(va) - get reference to a onereg struct 
+ *     void *__pcc_2regref(va) - get reference to a tworeg struct 
+ *     void *__pcc_memref(va,sz)       - get reference to a large struct 
+ */
+
+static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
+static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref;
+static char *strif, *strfi;
+
+void
+bjobcode(void)
+{
+       struct symtab *sp;
+       struct rstack *rp;
+       NODE *p, *q;
+       char *c;
+
+#if defined(__GNUC__) || defined(__PCC__)
+       /* Be sure that the compiler uses full x87 */
+       /* XXX cross-compiling will fail here */
+       int fcw = 0;
+       __asm("fstcw (%0)" : : "r"(&fcw));
+       fcw |= 0x33f;
+       __asm("fldcw (%0)" : : "r"(&fcw));
+#endif
+
+       /* amd64 names for some asm constant printouts */
+       astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
+       astypnames[LONG] = astypnames[ULONG] = "\t.quad";
+
+       gp_offset = addname("gp_offset");
+       fp_offset = addname("fp_offset");
+       overflow_arg_area = addname("overflow_arg_area");
+       reg_save_area = addname("reg_save_area");
+
+       rp = bstruct(NULL, STNAME, NULL);
+       p = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
+       soumemb(p, gp_offset, 0);
+       soumemb(p, fp_offset, 0);
+       p->n_type = VOID+PTR;
+       p->n_ap = NULL;
+       soumemb(p, overflow_arg_area, 0);
+       soumemb(p, reg_save_area, 0);
+       nfree(p);
+       q = dclstruct(rp);
+       c = addname("__builtin_va_list");
+       p = block(LB, bdty(NAME, c), bcon(2), INT, 0, 0);
+       p = tymerge(q, p);
+       p->n_sp = lookup(c, 0);
+       defid(p, TYPEDEF);
+       nfree(q);
+       nfree(p);
+
+       /* for the static varargs functions */
+#define        MKN(vn, rn) \
+       { vn = addname(rn); sp = lookup(vn, SNORMAL); \
+         sp->sclass = USTATIC; sp->stype = FTN|VOID|(PTR<<TSHIFT); }
+
+       MKN(strfi, "__pcc_strfi");
+       MKN(strif, "__pcc_strif");
+       MKN(_1fpref, "__pcc_1fpref");
+       MKN(_2fpref, "__pcc_2fpref");
+       MKN(_1regref, "__pcc_1regref");
+       MKN(_2regref, "__pcc_2regref");
+       MKN(memref, "__pcc_memref");
+}
+
+static NODE *
+mkstkref(int off, TWORD typ)
+{
+       NODE *p;
+
+       p = block(REG, NIL, NIL, PTR|typ, 0, 0);
+       regno(p) = FPREG;
+       return buildtree(PLUS, p, bcon(off/SZCHAR));
+}
+
+NODE *
+amd64_builtin_stdarg_start(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *r;
+
+       /* use the values from the function header */
+       p = a->n_left;
+       r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
+           mkstkref(-rsaoff, VOID));
+       r = buildtree(COMOP, r,
+           buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
+           mkstkref(thisrsp, VOID)));
+       r = buildtree(COMOP, r,
+           buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
+           bcon(thisgpr*(SZLONG/SZCHAR))));
+       r = buildtree(COMOP, r,
+           buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
+           bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
+
+       tfree(a);
+       return r;
+}
+
+static NODE *
+mkvacall(char *fun, NODE *a, int typ)
+{
+       NODE *r, *f = block(NAME, NIL, NIL, INT, 0, 0);
+       NODE *ap = a->n_left;
+       NODE *dp = a->n_right;
+       int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
+
+       f->n_sp = lookup(fun, SNORMAL);
+       varneeds |= typ;
+       f->n_type = f->n_sp->stype;
+       f = clocal(f);
+       SETOFF(sz, ALLONG);
+       r = buildtree(CALL, f,
+           buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
+       r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
+       r = buildtree(UMUL, r, NIL);
+       return r;
+}
+
+NODE *
+amd64_builtin_va_arg(const struct bitable *bt, NODE *a)
+{
+       NODE *r, *dp;
+       int typ, sz;
+
+       dp = a->n_right;
+
+       nsse = ngpr = 0;
+       sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
+       switch (typ = argtyp(dp->n_type, dp->n_df, dp->n_ap)) {
+       case INTEGER:
+               r = mkvacall(_1regref, a, NEED_1REGREF);
+               break;
+
+       case SSE:
+               r = mkvacall(_1fpref, a, NEED_1FPREF);
+               break;
+
+       default:
+               cerror("va_arg: bad type %d", typ);
+
+       case X87:
+       case STRX87:
+       case STRMEM: /* stored in memory */
+               r = mkvacall(memref, a, NEED_MEMREF);
+               break;
+
+       case STRREG: /* struct in general regs */
+               if (sz <= SZLONG)
+                       r = mkvacall(_1regref, a, NEED_1REGREF);
+               else
+                       r = mkvacall(_2regref, a, NEED_2REGREF);
+               break;
+
+       case STRSSE:
+               if (sz <= SZLONG)
+                       r = mkvacall(_1fpref, a, NEED_1FPREF);
+               else
+                       r = mkvacall(_2fpref, a, NEED_2FPREF);
+               break;
+
+       case STRIF:
+               r = mkvacall(strif, a, NEED_STRIF);
+               break;
+
+       case STRFI:
+               r = mkvacall(strfi, a, NEED_STRFI);
+               break;
+       }
+
+       tfree(a);
+       return r;
+}
+
+NODE *
+amd64_builtin_va_end(const struct bitable *bt, NODE *a)
+{
+       tfree(a);
+       return bcon(0); /* nothing */
+}
+
+NODE *
+amd64_builtin_va_copy(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+
+       f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
+           buildtree(UMUL, a->n_right, NIL));
+       nfree(a);
+       return f;
+}
+
+static NODE *
+movtoreg(NODE *p, int rno)
+{
+       NODE *r;
+
+       r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       regno(r) = rno;
+       return clocal(buildtree(ASSIGN, r, p));
+}  
+
+static NODE *
+movtomem(NODE *p, int off, int reg)
+{
+       struct symtab s;
+       NODE *r, *l;
+
+       s.stype = p->n_type;
+       s.squal = 0;
+       s.sdf = p->n_df;
+       s.sap = p->n_ap;
+       s.soffset = off;
+       s.sclass = AUTO;
+
+       l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+       slval(l, 0);
+       regno(l) = reg;
+
+       r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       r->n_sp = &s;
+       r = stref(block(STREF, l, r, 0, 0, 0));
+
+       return clocal(buildtree(ASSIGN, r, p));
+}  
+
+/*
+ * Check what to do with a struct.  We traverse down in the struct to 
+ * find which types it is and where the struct really should be.
+ * The return vals we may end up with are:
+ *     STRREG - The whole struct is saved in general registers.
+ *     STRMEM - the struct is saved in memory.
+ *     STRSSE - the whole struct is saved in SSE registers.
+ *     STRIF  - First word of struct is saved in general reg, other SSE.
+ *     STRFI  - First word of struct is saved in SSE, next in general reg.
+ *
+ * - If size > 16 bytes or there are packed fields, use memory.
+ * - If any part of an eight-byte should be in a general register,
+ *    the eight-byte is stored in a general register
+ * - If the eight-byte only contains float or double, use a SSE register
+ * - Otherwise use memory.
+ *
+ * Arrays must be broken up as separate elements, since the elements
+ * are classified separately. For example;
+ *     struct s { short s; float f[3]; } S;
+ * will have the first 64 bits passed in general reg and the second in SSE.
+ *
+ * sp below is a pointer to a member list.
+ * off tells whether is is the first or second eight-byte to check.
+ */
+static int
+classifystruct(struct symtab *sp, int off)
+{
+       struct symtab sps[16];
+       union dimfun *df;
+       TWORD t;
+       int cl, cl2, sz, i;
+
+
+       for (cl = 0; sp; sp = sp->snext) {
+               t = sp->stype;
+
+               /* fake a linked list of all array members */
+               if (ISARY(t)) {
+                       sz = 1;
+                       df = sp->sdf;
+                       do {
+                               sz *= df->ddim;
+                               t = DECREF(t);
+                               df++;
+                       } while (ISARY(t));
+                       for (i = 0; i < sz; i++) {
+                               sps[i] = *sp;
+                               sps[i].stype = t;
+                               sps[i].sdf = df;
+                               sps[i].snext = &sps[i+1];
+                               sps[i].soffset = i * tsize(t, df, sp->sap);
+                               sps[i].soffset += sp->soffset;
+                       }
+                       sps[i-1].snext = sp->snext;
+                       sp = &sps[0];
+               }
+
+               if (off == 0) {
+                       if (sp->soffset >= SZLONG)
+                               continue;
+               } else {
+                       if (sp->soffset < SZLONG)
+                               continue;
+               }
+
+               if (t <= ULONGLONG || ISPTR(t)) {
+                       if (cl == 0 || cl == STRSSE)
+                               cl = STRREG;
+               } else if (t <= DOUBLE) {
+                       if (cl == 0)
+                               cl = STRSSE;
+               } else if (t == LDOUBLE) {
+                       return STRMEM;
+               } else if (ISSOU(t)) {
+#ifdef GCC_COMPAT
+                       if (attr_find(sp->sap, GCC_ATYP_PACKED)) {
+                               cl = STRMEM;
+                       } else
+#endif
+                       {
+                               cl2 = classifystruct(strmemb(sp->sap), off);
+                               if (cl2 == STRMEM) {
+                                       cl = STRMEM;
+                               } else if (cl2 == STRREG) {
+                                       if (cl == 0 || cl == STRSSE)
+                                               cl = STRREG;
+                               } else if (cl2 == STRSSE) {
+                                       if (cl == 0)
+                                               cl = STRSSE;
+                               }
+                       }
+               } else
+                       cerror("classifystruct: unknown type %x", t);
+               if (cl == STRMEM)
+                       break;
+       }
+       if (cl == 0)
+               cerror("classifystruct: failed classify");
+       return cl;
+}
+
+/*
+ * Check for long double complex structs.
+ */
+static int
+iscplx87(struct symtab *sp)
+{
+       if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE &&
+           sp->snext->snext == NULL)
+               return STRX87;
+       return 0;
+}
+
+/*
+ * AMD64 parameter classification.
+ */
+static int
+argtyp(TWORD t, union dimfun *df, struct attr *ap)
+{
+       int cl2, cl = 0;
+
+       if (t <= ULONG || ISPTR(t) || t == BOOL) {
+               cl = ngpr < 6 ? INTEGER : INTMEM;
+       } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
+               cl = nsse < 8 ? SSE : SSEMEM;
+       } else if (t == LDOUBLE || t == LIMAG) {
+               cl = X87; /* XXX */
+       } else if (t == STRTY || t == UNIONTY) {
+               int sz = tsize(t, df, ap);
+
+#ifdef GCC_COMPAT
+               if (attr_find(ap, GCC_ATYP_PACKED)) {
+                       cl = STRMEM;
+               } else
+#endif
+               if (iscplx87(strmemb(ap)) == STRX87) {
+                       cl = STRX87;
+               } else if (sz > 2*SZLONG) {
+                       cl = STRMEM;
+               } else if (sz <= SZLONG) {
+                       /* only one member to check */
+                       cl = classifystruct(strmemb(ap), 0);
+                       if (cl == STRREG && ngpr > 5)
+                               cl = STRMEM;
+                       else if (cl == STRSSE && nsse > 7)
+                               cl = STRMEM;
+               } else {
+                       cl = classifystruct(strmemb(ap), 0);
+                       cl2 = classifystruct(strmemb(ap), 1);
+                       if (cl == STRMEM || cl2 == STRMEM)
+                               cl = STRMEM;
+                       else if (cl == STRREG && cl2 == STRSSE)
+                               cl = STRIF;
+                       else if (cl2 == STRREG && cl == STRSSE)
+                               cl = STRFI;
+
+                       if (cl == STRREG && ngpr > 4)
+                               cl = STRMEM;
+                       else if (cl == STRSSE && nsse > 6)
+                               cl = STRMEM;
+                       else if ((cl == STRIF || cl == STRFI) &&
+                           (ngpr > 5 || nsse > 7))
+                               cl = STRMEM;
+               }
+       } else
+               cerror("FIXME: classify");
+       return cl;
+}
+
+/*
+ * Do the "hard work" in assigning correct destination for arguments.
+ * Also convert arguments < INT to inte (default argument promotions).
+ * XXX - should be dome elsewhere.
+ */
+static NODE *
+argput(NODE *p)
+{
+       NODE *q, *ql;
+       TWORD ty;
+       int typ, r, ssz, rn;
+
+       if (p->n_op == CM) {
+               p->n_left = argput(p->n_left);
+               p->n_right = argput(p->n_right);
+               return p;
+       }
+
+       /* first arg may be struct return pointer */
+       /* XXX - check if varargs; setup al */
+       switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
+       case INTEGER:
+       case SSE:
+               if (typ == SSE)
+                       r = XMM0 + nsse++;
+               else
+                       r = argregsi[ngpr++];
+               if (p->n_type < INT || p->n_type == BOOL)
+                       p = cast(p, INT, 0);
+               p = movtoreg(p, r);
+               break;
+
+       case X87:
+               r = nrsp;
+               nrsp += SZLDOUBLE;
+               p = movtomem(p, r, STKREG);
+               break;
+
+       case SSEMEM:
+               r = nrsp;
+               nrsp += SZDOUBLE;
+               p = movtomem(p, r, STKREG);
+               break;
+
+       case INTMEM:
+               r = nrsp;
+               nrsp += SZLONG;
+               if (p->n_type < INT || p->n_type == BOOL)
+                       p = cast(p, INT, 0);
+               p = movtomem(p, r, STKREG);
+               break;
+
+       case STRFI:
+       case STRIF:
+       case STRSSE:
+       case STRREG: /* Struct in registers */
+               /* Cast to long/sse pointer and move to the registers */
+               /* XXX can overrun struct size */
+               ssz = tsize(p->n_type, p->n_df, p->n_ap);
+
+               if (typ == STRSSE || typ == STRFI) {
+                       r = XMM0 + nsse++;
+                       ty = DOUBLE;
+               } else {
+                       r = argregsi[ngpr++];
+                       ty = LONG;
+               }
+
+               p = nfree(p);   /* remove STARG */
+               p = makety(p, PTR|ty, 0, 0, 0);
+               ql = tempnode(0, PTR|ty, 0, 0);
+               rn = regno(ql);
+               p = buildtree(ASSIGN, ql, p);
+               ql = tempnode(rn, PTR|ty, 0, 0);
+               ql = movtoreg(buildtree(UMUL, ql, NIL), r);
+               p = buildtree(COMOP, p, ql);
+
+               if (ssz > SZLONG) {
+                       if (typ == STRSSE || typ == STRIF) {
+                               r = XMM0 + nsse++;
+                               ty = DOUBLE;
+                       } else {
+                               r = argregsi[ngpr++];
+                               ty = LONG;
+                       }
+
+                       ql = tempnode(rn, PTR|ty, 0, 0);
+                       ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
+                       ql = movtoreg(ql, r);
+
+                       p = buildtree(CM, p, ql);
+               }
+               break;
+
+       case STRX87:
+       case STRMEM: {
+               struct symtab s;
+               NODE *l, *t;
+
+               q = buildtree(UMUL, p->n_left, NIL);
+
+               s.stype = p->n_type;
+               s.squal = 0;
+               s.sdf = p->n_df;
+               s.sap = p->n_ap;
+               s.soffset = nrsp;
+               s.sclass = AUTO;
+
+               nrsp += tsize(p->n_type, p->n_df, p->n_ap);
+
+               l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+               slval(l, 0);
+               regno(l) = STKREG;
+
+               t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+               t->n_sp = &s;
+               t = stref(block(STREF, l, t, 0, 0, 0));
+
+               t = (buildtree(ASSIGN, t, q));
+               nfree(p);
+               p = t->n_left;
+               nfree(t);
+               break;
+               }
+
+       default:
+               cerror("argument %d", typ);
+       }
+       return p;
+}
+
+/*
+ * Sort arglist so that register assignments ends up last.
+ */
+static int
+argsort(NODE *p)
+{
+       NODE *q, *r;
+       int rv = 0;
+
+       if (p->n_op != CM) {
+               if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
+                   coptype(p->n_right->n_op) != LTYPE) {
+                       q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+                       r = ccopy(q);
+                       p->n_right = buildtree(COMOP,
+                           buildtree(ASSIGN, q, p->n_right), r);
+               }
+               return rv;
+       }
+       if (p->n_right->n_op == CM) {
+               /* fixup for small structs in regs */
+               q = p->n_right->n_left;
+               p->n_right->n_left = p->n_left;
+               p->n_left = p->n_right;
+               p->n_right = p->n_left->n_right;
+               p->n_left->n_right = q;
+       }
+       if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
+           coptype(p->n_right->n_right->n_op) != LTYPE) {
+               /* move before everything to avoid reg trashing */
+               q = tempnode(0, p->n_right->n_type,
+                   p->n_right->n_df, p->n_right->n_ap);
+               r = ccopy(q);
+               p->n_right->n_right = buildtree(COMOP,
+                   buildtree(ASSIGN, q, p->n_right->n_right), r);
+       }
+       if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
+               if (p->n_left->n_op == CM &&
+                   p->n_left->n_right->n_op == STASG) {
+                       q = p->n_left->n_right;
+                       p->n_left->n_right = p->n_right;
+                       p->n_right = q;
+                       rv = 1;
+               } else if (p->n_left->n_op == STASG) {
+                       q = p->n_left;
+                       p->n_left = p->n_right;
+                       p->n_right = q;
+                       rv = 1;
+               }
+       }
+       return rv | argsort(p->n_left);
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
+ */
+NODE *
+funcode(NODE *p)
+{
+       NODE *l, *r;
+       TWORD t;
+       int i;
+
+       nsse = ngpr = nrsp = 0;
+       /* Check if hidden arg needed */
+       /* If so, add it in pass2 */
+       if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
+           l->n_type == INCREF(FTN)+UNIONTY) {
+               int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
+               struct symtab *sp = strmemb(l->n_ap);
+               if (ssz == 2*SZLDOUBLE && sp->stype == LDOUBLE &&
+                   sp->snext->stype == LDOUBLE)
+                       ; /* long complex struct */
+               else if (ssz > 2*SZLONG)
+                       ngpr++;
+       }
+
+       /* Convert just regs to assign insn's */
+       p->n_right = argput(p->n_right);
+
+       /* Must sort arglist so that STASG ends up first */
+       /* This avoids registers being clobbered */
+       while (argsort(p->n_right))
+               ;
+       /* Check if there are varargs */
+       if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
+               ; /* Need RAX */
+       } else {
+               union arglist *al = l->n_df->dfun;
+
+               for (; al->type != TELLIPSIS; al++) {
+                       if ((t = al->type) == TNULL)
+                               return p; /* No need */
+                       if (ISSOU(BTYPE(t)))
+                               al++;
+                       for (i = 0; t > BTMASK; t = DECREF(t))
+                               if (ISARY(t) || ISFTN(t))
+                                       i++;
+                       if (i)
+                               al++;
+               }
+       }
+
+       /* Always emit number of SSE regs used */
+       l = movtoreg(bcon(nsse), RAX);
+       if (p->n_right->n_op != CM) {
+               p->n_right = block(CM, l, p->n_right, INT, 0, 0);
+       } else {
+               for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
+                       ;
+               r->n_left = block(CM, l, r->n_left, INT, 0, 0);
+       }
+       return p;
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+/*
+ * Return return as given by a.
+ */
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+       nframes = glval(a);
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+
+       f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
+       f = buildtree(UMUL, f, NIL);
+
+       return f;
+}
+
+/*
+ * Return frame as given by a.
+ */
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+       nframes = glval(a);
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+
+       return f;
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+       return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0);
+}
+
+int codeatyp(NODE *);
+int
+codeatyp(NODE *p)
+{
+       TWORD t;
+       int typ;
+
+       ngpr = nsse = 0;
+       t = DECREF(p->n_type);
+       if (ISSOU(t) == 0) {
+               p = p->n_left;
+               t = DECREF(DECREF(p->n_type));
+       }
+       if (ISSOU(t) == 0)
+               cerror("codeatyp");
+       typ = argtyp(t, p->n_df, p->n_ap);
+       return typ;
+}
diff --git a/lang/pcc/pcc/arch/amd64/local.c b/lang/pcc/pcc/arch/amd64/local.c
new file mode 100644 (file)
index 0000000..b0cb31e
--- /dev/null
@@ -0,0 +1,945 @@
+/*     $Id: local.c,v 1.96 2016/03/05 15:49:36 ragge Exp $     */
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#ifndef LANG_CXX
+#define        NODE P1ND
+#define        ccopy p1tcopy
+#define        tfree p1tfree
+#define        nfree p1nfree
+#define        fwalk p1fwalk
+#define        talloc p1alloc
+#endif
+
+/*     this file contains code which is dependent on the target machine */
+
+/*
+ * Check if a constant is too large for a type.
+ */
+#ifdef notyet
+static int
+toolarge(TWORD t, CONSZ con)
+{
+       U_CONSZ ucon = con;
+
+       switch (t) {
+       case ULONG:
+       case LONG:
+       case ULONGLONG:
+       case LONGLONG:
+               break; /* cannot be too large */
+#define        SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break
+#define        UCHK(i) case i: if (ucon > MAX_##i) return 1; break
+       SCHK(INT);
+       SCHK(SHORT);
+       case BOOL:
+       SCHK(CHAR);
+       UCHK(UNSIGNED);
+       UCHK(USHORT);
+       UCHK(UCHAR);
+       default:
+               cerror("toolarge");
+       }
+       return 0;
+}
+#endif
+
+static char *
+getsoname(struct symtab *sp)
+{
+       struct attr *ap;
+       return (ap = attr_find(sp->sap, ATTR_SONAME)) ?
+           ap->sarg(0) : sp->sname;
+}
+
+
+#define IALLOC(sz)     (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+       struct symtab *sp = IALLOC(sizeof(struct symtab));
+       size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+
+       sp->sname = IALLOC(len);
+       strlcpy(sp->sname, p, len);
+       strlcat(sp->sname, s, len);
+       strlcat(sp->sname, s2, len);
+       sp->sap = attr_new(ATTR_SONAME, 1);
+       sp->sap->sarg(0) = sp->sname;
+       sp->sclass = EXTERN;
+       sp->sflags = sp->slevel = 0;
+       return sp;
+}
+
+int gotnr; /* tempnum for GOT register */
+int argstacksize;
+
+/*
+ * Create a reference for an extern variable or function.
+ */
+static NODE *
+picext(NODE *p)
+{
+#if defined(ELFABI)
+
+       NODE *q;
+       struct symtab *sp;
+       char *c;
+
+       if (p->n_sp->sflags & SBEENHERE)
+               return p;
+#ifdef GCC_COMPAT
+       struct attr *ga;
+       if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) &&
+           strcmp(ga->sarg(0), "hidden") == 0)
+               return p; /* no GOT reference */
+#endif
+
+       c = getexname(p->n_sp);
+       sp = picsymtab("", c, "@GOTPCREL");
+       sp->sflags |= SBEENHERE;
+       q = block(NAME, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap);
+       q->n_sp = sp;
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = sp;
+       nfree(p);
+       return q;
+
+#elif defined(MACHOABI)
+
+       return p;
+
+#endif
+}
+
+static NODE *
+cmop(NODE *l, NODE *r)
+{
+       return block(CM, l, r, INT, 0, 0);
+}
+
+static NODE *
+mkx(char *s, NODE *p)
+{
+       p = block(XARG, p, NIL, INT, 0, 0);
+       p->n_name = s;
+       return p;
+}
+
+static char *
+mk3str(char *s1, char *s2, char *s3)
+{
+       int len = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+       char *sd;
+
+       sd = tmpalloc(len);
+       strlcpy(sd, s1, len);
+       strlcat(sd, s2, len);
+       strlcat(sd, s3, len);
+       return sd;
+}
+
+/*
+ * Create a reference for a TLS variable.
+ * This is the "General dynamic" version.
+ */
+static NODE *
+tlspic(NODE *p)
+{
+       NODE *q, *r, *s;
+       char *s1, *s2;
+
+       /*
+        * .byte   0x66
+        * leaq x@TLSGD(%rip),%rdi
+        * .word   0x6666
+        * rex64
+        * call __tls_get_addr@PLT
+        */
+
+       /* Need the .byte stuff around.  Why? */
+       /* Use inline assembler */
+       q = mkx("%rdx", bcon(0));
+       q = cmop(q, mkx("%rcx", bcon(0)));
+       q = cmop(q, mkx("%rsi", bcon(0)));
+       q = cmop(q, mkx("%rdi", bcon(0)));
+       q = cmop(q, mkx("%r8", bcon(0)));
+       q = cmop(q, mkx("%r9", bcon(0)));
+       q = cmop(q, mkx("%r10", bcon(0)));
+       q = cmop(q, mkx("%r11", bcon(0)));
+
+       s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap));
+       r = mkx("=a", r);
+       r = block(XASM, r, q, INT, 0, 0);
+
+       /* Create the magic string */
+       s1 = ".byte 0x66\n\tleaq ";
+       s2 = "@TLSGD(%%rip),%%rdi\n"
+           "\t.word 0x6666\n\trex64\n\tcall __tls_get_addr@PLT";
+       if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) {
+               p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1));
+               p->n_sp->sap->sarg(0) = p->n_sp->sname;
+       }
+       r->n_name = addstring(mk3str(s1,
+           attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2));
+
+       r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap);
+       r = buildtree(UMUL, r, NIL);
+       tfree(p);
+       return r;
+}
+
+#ifdef GCC_COMPAT
+/*
+ * The "initial exec" tls model.
+ */
+static NODE *
+tlsinitialexec(NODE *p)
+{
+       NODE *q, *r, *s;
+       char *s1, *s2;
+
+       /*
+        * movq %fs:0,%rax
+        * addq x@GOTTPOFF(%rip),%rax
+        */
+
+       q = bcon(0);
+       q->n_type = STRTY;
+
+       s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap));
+       r = mkx("=r", r);
+       r = block(XASM, r, q, INT, 0, 0);
+
+       s1 = "movq %%fs:0,%0\n\taddq ";
+       s2 = "@GOTTPOFF(%%rip),%0";
+       if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) {
+               p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1));
+               p->n_sp->sap->sarg(0) = p->n_sp->sname;
+       }
+       r->n_name = mk3str(s1,
+           attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2);
+
+       r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap);
+       r = buildtree(UMUL, r, NIL);
+       tfree(p);
+       return r;
+}
+#endif
+
+static NODE *
+tlsref(NODE *p)
+{
+#ifdef GCC_COMPAT
+       struct symtab *sp = p->n_sp;
+       struct attr *ga;
+       char *c;
+
+       if ((ga = attr_find(sp->sap, GCC_ATYP_TLSMODEL)) != NULL) {
+               c = ga->sarg(0);
+               if (strcmp(c, "initial-exec") == 0)
+                       return tlsinitialexec(p);
+               else if (strcmp(c, "global-dynamic") == 0)
+                       ;
+               else
+                       werror("unsupported tls model '%s'", c);
+       }
+#endif
+       return tlspic(p);
+}
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+       register struct symtab *q;
+       register NODE *r, *l;
+       register int o;
+       register int m;
+       TWORD t;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       slval(r, 0);
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case USTATIC:
+                       if (kflag == 0)
+                               break;
+                       /* FALLTHROUGH */
+               case STATIC:
+#ifdef TLS
+                       if (q->sflags & STLS) {
+                               p = tlsref(p);
+                               break;
+                       }
+#endif
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       slval(p, 0);
+                       p->n_rval = q->soffset;
+                       break;
+
+               case EXTERN:
+               case EXTDEF:
+                       if (q->sflags & STLS) {
+                               p = tlsref(p);
+                               break;
+                       }
+                       if (kflag == 0 || statinit)
+                               break;
+                       if (blevel > 0)
+                               p = picext(p);
+                       break;
+               }
+               break;
+
+       case UCALL:
+       case USTCALL:
+               /* For now, always clear eax */
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               regno(l) = RAX;
+               p->n_right = clocal(buildtree(ASSIGN, l, bcon(0)));
+               p->n_op -= (UCALL-CALL);
+               break;
+
+       case SCONV:
+               /* Special-case shifts */
+               if (p->n_type == LONG && (l = p->n_left)->n_op == LS && 
+                   l->n_type == INT && l->n_right->n_op == ICON) {
+                       p->n_left = l->n_left;
+                       p = buildtree(LS, p, l->n_right);
+                       nfree(l);
+                       break;
+               }
+
+               l = p->n_left;
+
+               /* Float conversions may need extra casts */
+               if (p->n_type == FLOAT || p->n_type == DOUBLE ||
+                   p->n_type == LDOUBLE) {
+                       if (l->n_type < INT || l->n_type == BOOL) {
+                               p->n_left = block(SCONV, l, NIL,
+                                   ISUNSIGNED(l->n_type) ? UNSIGNED : INT,
+                                   l->n_df, l->n_ap);
+                               break;
+                       }
+               }
+
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       return l;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) ==
+                   tsize(l->n_type, l->n_df, l->n_ap)) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       return l;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
+                   l->n_op != QUEST && l->n_op != ASSIGN) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       return l;
+               }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       CONSZ val = glval(l);
+
+                       /* if named constant and pointer, allow cast 
+                          to long/ulong */
+                       if (!nncon(l) && (l->n_type & TMASK) &&
+                           (m == LONG || m == ULONG)) {
+                               l->n_type = m;
+                               l->n_ap = 0;
+                               return nfree(p);
+                       }
+
+                       if (ISPTR(l->n_type) && !nncon(l))
+                               break; /* cannot convert named pointers */
+
+                       if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+                           switch (m) {
+                       case BOOL:
+                               val = nncon(l) ? (val != 0) : 1;
+                               slval(l, val);
+                               l->n_sp = NULL;
+                               break;
+                       case CHAR:
+                               slval(l, (char)val);
+                               break;
+                       case UCHAR:
+                               slval(l, val & 0377);
+                               break;
+                       case SHORT:
+                               slval(l, (short)val);
+                               break;
+                       case USHORT:
+                               slval(l, val & 0177777);
+                               break;
+                       case UNSIGNED:
+                               slval(l, val & 0xffffffff);
+                               break;
+                       case INT:
+                               slval(l, (int)val);
+                               break;
+                       case LONG:
+                       case LONGLONG:
+                               slval(l, (long long)val);
+                               break;
+                       case ULONG:
+                       case ULONGLONG:
+                               slval(l, val);
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = fltallo();
+                               FCAST(l->n_dcon)->fp = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", m);
+                       }
+                       l->n_type = m;
+                       l->n_ap = NULL;
+                       nfree(p);
+                       return l;
+               } else if (l->n_op == FCON) {
+                       CONSZ lv;
+                       if (p->n_type == BOOL)
+                               lv = !FLOAT_ISZERO(FCAST(l->n_dcon));
+                       else {
+                               FLOAT_FP2INT(lv, FCAST(l->n_dcon), m);
+                       }
+                       slval(l, lv);
+                       l->n_sp = NULL;
+                       l->n_op = ICON;
+                       l->n_type = m;
+                       l->n_ap = NULL;
+                       nfree(p);
+                       return clocal(l);
+               }
+               if ((p->n_type == CHAR || p->n_type == UCHAR ||
+                   p->n_type == SHORT || p->n_type == USHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = makety(p->n_left, INT, 0, 0, 0);
+               p->n_right = makety(p->n_right, INT, 0, 0, 0);
+               p = makety(p, p->n_type, 0, 0, 0);
+               p->n_left->n_type = INT;
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               t = p->n_type;
+               if (ISITY(t))
+                       t = t - (FIMAG-FLOAT);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(CHAR) : RETREG(t);
+               break;
+
+       case LS:
+       case RS:
+               /* shift count must be in a char */
+               if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+                       break;
+               p->n_right = makety(p->n_right, CHAR, 0, 0, 0);
+               break;
+       }
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct attr *ap;
+       struct symtab *sp, sps;
+       static int dblxor, fltxor;
+       int codeatyp(NODE *);
+
+       if (p->n_op == STCALL || p->n_op == USTCALL) {
+               /* save struct encoding */
+               p->n_ap = attr_add(p->n_ap,
+                   ap = attr_new(ATTR_AMD64_CMPLRET, 1));
+               ap->iarg(0) = codeatyp(p);
+       }
+
+       if (p->n_op == UMINUS && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
+               /* Store xor code for sign change */
+               if (dblxor == 0) {
+                       dblxor = getlab();
+                       fltxor = getlab();
+                       sps.stype = LDOUBLE;
+                       sps.squal = CON >> TSHIFT;
+                       sps.sflags = sps.sclass = 0;
+                       sps.sname = "";
+                       sps.slevel = 1;
+                       sps.sap = NULL;
+                       sps.soffset = dblxor;
+                       locctr(DATA, &sps);
+                       defloc(&sps);
+                       printf("\t.long 0,0x80000000,0,0\n");
+                       printf(LABFMT ":\n", fltxor);
+                       printf("\t.long 0x80000000,0,0,0\n");
+               }
+               p->n_ap = attr_add(p->n_ap,
+                   ap = attr_new(ATTR_AMD64_XORLBL, 1));
+               ap->iarg(0) = p->n_type == FLOAT ? fltxor : dblxor;
+               return;
+       }
+       if (kflag && (cdope(p->n_op) & CALLFLG) && p->n_left->n_op == NAME) {
+               /* Convert @GOTPCREL to @PLT */
+               char *s;
+
+               sp = p->n_left->n_sp;
+               if ((s = strstr(sp->sname, "@GOTPCREL")) != NULL) {
+                       memcpy(s, "@PLT", sizeof("@PLT"));
+                       p->n_left->n_op = ICON;
+               }
+               return;
+       }
+       if (p->n_op != FCON)
+               return;
+
+#ifdef mach_amd64
+       {
+               /* Do not lose negative zeros */
+               long long ll[2];
+               short ss;
+               memcpy(ll, &p->n_dcon, sizeof(ll));
+               memcpy(&ss, &ll[1], sizeof(ss));
+               if (ll[0] == 0 && ss == 0)
+                       return;
+       }
+#else
+#error fixme
+#endif
+
+       /* XXX should let float constants follow */
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = NULL;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+       sp->sname = NULL;
+
+       locctr(DATA, sp);
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       slval(p, 0);
+       p->n_sp = sp;
+}
+
+/*
+ * Convert ADDROF NAME to ICON?
+ */
+int
+andable(NODE *p)
+{
+#ifdef notdef
+       /* shared libraries cannot have direct referenced static syms */
+       if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC)
+               return 1;
+#endif
+       return !kflag;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == LDOUBLE)
+               return 0;
+       return 1;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR));
+       p = buildtree(PLUS, p, bcon(30));
+       p = buildtree(AND, p, xbcon(-16, NULL, LONG));
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       slval(sp, 0);
+       sp->n_rval = STKREG;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+LONG, t->n_df, t->n_ap);
+       slval(sp, 0);
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+
+       switch (p->n_type) {
+       case LDOUBLE:
+               u.i[2] = 0;
+               u.l = (long double)FCAST(p->n_dcon)->fp;
+#if defined(HOST_BIG_ENDIAN)
+               /* XXX probably broken on most hosts */
+               printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[2], u.i[1], u.i[0]);
+#else
+               printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[0], u.i[1],
+                   u.i[2] & 0xffff);
+#endif
+               break;
+       case DOUBLE:
+               u.d = (double)FCAST(p->n_dcon)->fp;
+#if defined(HOST_BIG_ENDIAN)
+               printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
+               printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+#endif
+               break;
+       case FLOAT:
+               u.f = (float)FCAST(p->n_dcon)->fp;
+               printf("\t.long\t0x%x\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#ifdef MACHOABI
+
+#define NCHNAM 256
+       static char text[NCHNAM+1];
+       int i;
+
+       if (p == NULL)
+               return "";
+
+       text[0] = '_';
+       for (i=1; *p && i<NCHNAM; ++i)
+               text[i] = *p++;
+
+       text[i] = '\0';
+       text[NCHNAM] = '\0';  /* truncate */
+
+       return (text);
+#else
+       return (p == NULL ? "" : p);
+#endif
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONGLONG:
+               MODTYPE(type,LONG);
+               break;
+
+       case ULONGLONG:
+               MODTYPE(type,ULONG);
+
+       }
+       return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off, al;
+       char *name;
+
+       name = getexname(sp);
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+       al = talign(sp->stype, sp->sap)/SZCHAR;
+
+#ifdef MACHOABI
+       if (sp->sclass == STATIC) {
+               al = ispow2(al);
+               printf("\t.zerofill __DATA,__bss,");
+               if (sp->slevel == 0) {
+                       printf("%s", name);
+               } else
+                       printf(LABFMT, sp->soffset);
+               printf(",%d,%d\n", off, al);
+       } else {
+               printf("\t.comm %s,0%o,%d\n", name, off, al);
+       }
+#else
+       if (sp->sclass == STATIC) {
+               if (sp->slevel == 0) {
+                       printf("\t.local %s\n", name);
+               } else
+                       printf("\t.local " LABFMT "\n", sp->soffset);
+       }
+       if (sp->slevel == 0) {
+               printf("\t.comm %s,0%o,%d\n", name, off, al);
+       } else
+               printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+#endif
+}
+
+static char *
+section2string(char *name)
+{
+       int len = strlen(name);
+
+       if (strncmp(name, "link_set", 8) == 0) {
+               const char postfix[] = ",\"aw\",@progbits";
+               char *s;
+
+               s = IALLOC(len + sizeof(postfix));
+               memcpy(s, name, len);
+               memcpy(s + len, postfix, sizeof(postfix));
+               return s;
+       }
+
+       return newstring(name, len);
+}
+
+char *nextsect;
+static int gottls;
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       char *a2 = pragtok(NULL);
+
+       if (strcmp(str, "tls") == 0 && a2 == NULL) {
+               gottls = 1;
+               return 1;
+       }
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "section") == 0 && a2 != NULL) {
+               nextsect = section2string(a2);
+               return 1;
+       }
+       if (strcmp(str, "alias") == 0 && a2 != NULL) {
+               alias = tmpstrdup(a2);
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+       /* may have sanity checks here */
+       if (gottls)
+               sp->sflags |= STLS;
+       gottls = 0;
+
+#ifdef GCC_COMPAT
+       struct attr *ga;
+
+#ifdef HAVE_WEAKREF
+       /* not many as'es have this directive */
+       if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
+               char *wr = ga->sarg(0);
+               char *sn = getsoname(sp);
+               if (wr == NULL) {
+                       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) {
+                               wr = ga->sarg(0);
+                       }
+               }
+               if (wr == NULL)
+                       printf("\t.weak %s\n", sn);
+               else
+                       printf("\t.weakref %s,%s\n", sn, wr);
+       } else
+#endif
+              if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
+               char *an = ga->sarg(0);
+               char *sn = getsoname(sp);
+               char *v;
+
+               v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
+               printf("\t.%s %s\n", v, sn);
+               printf("\t.set %s,%s\n", sn, an);
+       }
+#endif
+       if (alias != NULL && (sp->sclass != PARAM)) {
+               printf("\t.globl %s\n", getexname(sp));
+               printf("%s = ", getexname(sp));
+               printf("%s\n", exname(alias));
+               alias = NULL;
+       }
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+               NODE *p = talloc();
+
+               p->n_op = NAME;
+               p->n_sp =
+                 (struct symtab *)(constructor ? "constructor" : "destructor");
+#ifdef GCC_COMPAT
+               sp->sap = attr_add(sp->sap, gcc_attr_parse(p));
+#endif
+               constructor = destructor = 0;
+       }
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+
diff --git a/lang/pcc/pcc/arch/amd64/local2.c b/lang/pcc/pcc/arch/amd64/local2.c
new file mode 100644 (file)
index 0000000..3f5f93a
--- /dev/null
@@ -0,0 +1,1245 @@
+/*     $Id: local2.c,v 1.62 2015/12/13 09:00:04 ragge Exp $    */
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+static int stkpos;
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static int regoff[MAXREGS];
+static TWORD ftype;
+char *rbyte[], *rshort[], *rlong[];
+static int needframe;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+       int i;
+
+       printf("\tpushq %%rbp\n");
+       printf("\tmovq %%rsp,%%rbp\n");
+       addto = (addto+15) & ~15; /* 16-byte aligned */
+       if (addto)
+               printf("\tsubq $%d,%%rsp\n", addto);
+
+       /* save permanent registers */
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i))
+                       printf("\tmovq %s,-%d(%s)\n",
+                           rnames[i], regoff[i], rnames[FPREG]);
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+       int i, addto;
+
+       addto = p2maxautooff;
+       if (addto >= AUTOINIT/SZCHAR)
+               addto -= AUTOINIT/SZCHAR;
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       addto += SZLONG/SZCHAR;
+                       regoff[i] = addto;
+               }
+       return addto;
+}
+
+/*
+ * Traverse a tree to check if we need to emit a frame at all.
+ * We emit it if:
+ * - any function call
+ * - rsp or rbp referenced
+ * Return 1 if frame is needed, 0 otherwise.
+ */
+static int
+chkf(NODE *p)
+{
+       int o = p->n_op;
+
+       if ((o == REG || o == OREG) && (regno(p) == RBP || regno(p) == RSP))
+               return 1;
+       if (callop(o))
+               return 1;
+       if (optype(o) == UTYPE)
+               return chkf(p->n_left);
+       else if (optype(o) == BITYPE)
+               return chkf(p->n_left) || chkf(p->n_right);
+       return 0;
+}
+
+static int
+chkframe(struct interpass_prolog *ipp)
+{
+       struct interpass *ip;
+
+       DLIST_FOREACH(ip, &ipp->ipp_ip, qelem) {
+               if (ip->type == IP_EPILOG)
+                       break;
+               if (ip->type == IP_NODE) {
+                       if (chkf(ip->ip_node))
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+
+       ftype = ipp->ipp_type;
+
+       if (xdeljumps)
+               needframe = chkframe(ipp);
+       else
+               needframe = 1;
+
+#ifdef LANG_F77
+       if (ipp->ipp_vis)
+               printf("        .globl %s\n", ipp->ipp_name);
+       printf("        .align 16\n");
+       printf("%s:\n", ipp->ipp_name);
+#endif
+       /*
+        * We here know what register to save and how much to 
+        * add to the stack.
+        */
+       addto = offcalc(ipp);
+       if (addto)
+               needframe = 1;
+       if (needframe)
+               prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       int i;
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       if (needframe) {
+               /* return from function code */
+               for (i = 0; i < MAXREGS; i++)
+                       if (TESTBIT(ipp->ipp_regs, i))
+                               printf("        movq -%d(%s),%s\n",
+                                   regoff[i], rnames[FPREG], rnames[i]);
+
+               /* struct return needs special treatment */
+               if (ftype == STRTY || ftype == UNIONTY) {
+                       printf("        movl 8(%%ebp),%%eax\n");
+                       printf("        leave\n");
+                       printf("        ret $%d\n", 4);
+               } else {
+                       printf("        leave\n");
+                       printf("        ret\n");
+               }
+       } else
+               printf("\tret\n");
+
+#ifndef MACHOABI
+       printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
+#endif
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+                       return(SZINT/SZCHAR);
+
+               case LONG:
+               case ULONG:
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p) 
+{
+
+       if (p->n_left->n_op != REG)
+               comperr("bad compare %p\n", p);
+       if ((p->n_su & DORIGHT) == 0)
+               expand(p, 0, "\tfxch\n");
+       expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn  */
+       expand(p, 0, "\tfstp %st(0)\n");        /* pop fromstack */
+       zzzcode(p, 'U');
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       comperr("fldexpand");
+       return 0;
+}
+
+static void
+stasg(NODE *p)
+{
+       struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+       expand(p, INAREG, "     leaq AL,%rdi\n");
+       if (ap->iarg(0) >= 8)
+               printf("\tmovl $%d,%%ecx\n\trep movsq\n", ap->iarg(0) >> 3);
+       if (ap->iarg(0) & 4)
+               printf("\tmovsl\n");
+       if (ap->iarg(0) & 2)
+               printf("\tmovsw\n");
+       if (ap->iarg(0) & 1)
+               printf("\tmovsb\n");
+}
+
+#define        E(x)    expand(p, 0, x)
+/*
+ * Generate code to convert an unsigned long to xmm float/double.
+ */
+static void
+ultofd(NODE *p)
+{
+
+       E("     movq AL,A1\n");
+       E("     testq A1,A1\n");
+       E("     js 2f\n");
+       E("     cvtsi2sZfq A1,A3\n");
+       E("     jmp 3f\n");
+       E("2:\n");
+       E("     movq A1,A2\n");
+       E("     shrq A2\n");
+       E("     andq $1,A1\n");
+       E("     orq A1,A2\n");
+       E("     cvtsi2sZfq A2,A3\n");
+       E("     addsZf A3,A3\n");
+       E("3:\n");
+}
+
+/*
+ * Generate code to convert an x87 long double to an unsigned long.
+ * This is ugly :-/
+ */
+static void
+ldtoul(NODE *p)
+{
+
+       E("     subq $16,%rsp\n");
+       E("     movl $0x5f000000,(%rsp)\n"); /* More than long can have */
+       E("     flds (%rsp)\n");
+       if (p->n_left->n_op == REG) {
+               E("     fxch\n");
+       } else
+               E("     fldt AL\n");
+       E("     fucomi %st(1), %st\n");
+       E("     jae 2f\n");
+
+       E("     fstp %st(1)\n");         /* Pop huge val from stack */
+       E("     fnstcw (%rsp)\n");       /* store cw */
+       E("     movw $0x0f3f,4(%rsp)\n");/* round towards 0 */
+       E("     fldcw 4(%rsp)\n");       /* new cw */
+       E("     fistpll 8(%rsp)\n");     /* save val */
+       E("     fldcw (%rsp)\n");        /* fetch old cw */
+       E("     movq 8(%rsp),A1\n");
+
+       E("     jmp 3f\n");
+
+       E("2:\n");
+
+       E("     fsubp %st, %st(1)\n");
+       E("     fnstcw (%rsp)\n");      
+       E("     movw $0x0f3f,4(%rsp)\n");
+       E("     fldcw 4(%rsp)\n");
+       E("     fistpll 8(%rsp)\n");
+       E("     fldcw (%rsp)\n");
+       E("     movabsq $0x8000000000000000,A1\n");
+       E("     xorq 8(%rsp),A1\n");
+
+       E("3:   addq $16,%rsp\n");
+}
+
+/*
+ * Generate code to convert an SSE float/double to an unsigned long.
+ */     
+static void     
+fdtoul(NODE *p) 
+{
+       if (p->n_left->n_type == FLOAT)
+               E("     movabsq $0x5f000000,A1\n");
+       else
+               E("     movabsq $0x43e0000000000000,A1\n");
+       E("     movd A1,A3\n");
+       E("     ucomisZg A3,AL\n");
+       E("     jae 2f\n");
+       E("     cvttsZg2siq AL,A1\n");
+       E("     jmp 3f\n");
+       E("2:\n");
+       E("     subsZg A3,AL\n");
+       E("     cvttsZg2siq AL,A1\n");
+       E("     movabsq $0x8000000000000000,A2\n");
+       E("     xorq A2,A1\n");
+       E("3:\n");
+}
+#undef E
+
+void
+zzzcode(NODE *p, int c)
+{
+       struct attr *ap, *ap2;
+       NODE *l;
+       int pr, lr, s;
+       char **rt;
+
+       switch (c) {
+       case 'A': /* swap st0 and st1 if right is evaluated second */
+               if ((p->n_su & DORIGHT) == 0) {
+                       if (logop(p->n_op))
+                               printf("        fxch\n");
+                       else
+                               printf("r");
+               }
+               break;
+
+       case 'B': /* ldouble to unsigned long cast */
+               ldtoul(p);
+               break;
+
+       case 'b': /* float/double to unsigned long cast */
+               fdtoul(p);
+               break;
+
+       case 'C':  /* remove from stack after subroutine call */
+               pr = p->n_qual;
+               if (p->n_op == UCALL)
+                       return; /* XXX remove ZC from UCALL */
+               if (pr)
+                       printf("        addq $%d, %s\n", pr, rnames[RSP]);
+#define        STRREG 6
+#define        STRSSE 8
+#define        STRIF  9
+#define        STRFI  10
+#define        STRX87 11
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET);
+               if ((p->n_op == STCALL || p->n_op == USTCALL) &&
+                   ap->iarg(0) == 32 && ap2->iarg(0) == STRX87) {
+                       printf("\tfstpt -%d(%%rbp)\n", stkpos);
+                       printf("\tfstpt -%d(%%rbp)\n", stkpos-16);
+                       printf("\tleaq -%d(%%rbp),%%rax\n", stkpos);
+               }
+               if ((p->n_op == STCALL || p->n_op == USTCALL) &&
+                   ap->iarg(0) <= 16) {
+                       /* store reg-passed structs on stack */
+                       if (ap2->iarg(0) == STRREG || ap2->iarg(0) == STRIF)
+                               printf("\tmovq %%rax,-%d(%%rbp)\n", stkpos);
+                       else
+                               printf("\tmovsd %%xmm0,-%d(%%rbp)\n", stkpos);
+                       if (ap->iarg(0) > 8) {
+                               if (ap2->iarg(0) == STRREG)
+                                       printf("\tmovq %%rdx");
+                               else if (ap2->iarg(0) == STRFI)
+                                       printf("\tmovq %%rax");
+                               else if (ap2->iarg(0) == STRIF)
+                                       printf("\tmovsd %%xmm0");
+                               else
+                                       printf("\tmovsd %%xmm1");
+                               printf(",-%d(%%rbp)\n", stkpos-8);
+                       }
+                       printf("\tleaq -%d(%%rbp),%%rax\n", stkpos);
+               }
+               break;
+
+       case 'c': /* xor label */
+               if ((ap = attr_find(p->n_ap, ATTR_AMD64_XORLBL)) == NULL)
+                       comperr("missing xor label");
+               printf(LABFMT, ap->iarg(0));
+               break;
+
+       case 'F': /* Structure argument */
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               printf("        subq $%d,%%rsp\n", ap->iarg(0));
+               printf("        movq %%rsp,%%rsi\n");
+               stasg(p);
+               break;
+
+       case 'G': /* Floating point compare */
+               fcomp(p);
+               break;
+
+       case 'j': /* convert unsigned long to f/d */
+               ultofd(p);
+               break;
+
+       case 'M': /* Output sconv move, if needed */
+               l = getlr(p, 'L');
+               /* XXX fixneed: regnum */
+               pr = DECRA(p->n_reg, 0);
+               lr = DECRA(l->n_reg, 0);
+               if (pr == lr)
+                       break;
+               printf("        movb %s,%s\n", rbyte[lr], rbyte[pr]);
+               l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
+               break;
+
+       case 'N': /* output long reg name */
+               printf("%s", rlong[getlr(p, '1')->n_rval]);
+               break;
+
+       case 'P': /* Put hidden argument in rdi */
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET);
+               if (ap->iarg(0) > 16 && ap2->iarg(0) != STRX87)
+                       printf("\tleaq -%d(%%rbp),%%rdi\n", stkpos);
+               break;
+
+        case 'Q': /* emit struct assign */
+               stasg(p);
+               break;
+
+       case 'R': /* print opname based on right type */
+       case 'L': /* print opname based on left type */
+               switch (getlr(p, c)->n_type) {
+               case CHAR: case UCHAR: s = 'b'; break;
+               case SHORT: case USHORT: s = 'w'; break;
+               case INT: case UNSIGNED: s = 'l'; break;
+               default: s = 'q'; break;
+               printf("%c", s);
+               }
+               break;
+
+       case 'U': { /* output branch insn for ucomi */
+               static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
+               if (p->n_op < EQ || p->n_op > GT)
+                       comperr("bad fp branch");
+               if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
+                       expand(p, 0, "  jp LC\n");
+               else if (p->n_op == EQ)
+                       printf("\tjp 1f\n");
+               printf("        %s ", fpcb[p->n_op - EQ]);
+               expand(p, 0, "LC\n");
+               if (p->n_op == EQ)
+                       printf("1:\n");
+               break;
+               }
+
+       case '8': /* special reg name printout (64-bit) */
+       case '1': /* special reg name printout (32-bit) */
+               l = getlr(p, '1');
+               rt = c == '8' ? rnames : rlong;
+               printf("%s", rt[l->n_rval]);
+               break;
+
+       case 'g':
+               p = p->n_left;
+               /* FALLTHROUGH */
+       case 'f': /* float or double */
+               printf("%c", p->n_type == FLOAT ? 's' : 'd');
+               break;
+
+       case 'q': /* int or long */
+               printf("%c", p->n_left->n_type == LONG ? 'q' : ' ');
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       comperr("flshape");
+       return(0);
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       long val = getlval(p);
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+%ld", val);
+               } else
+                       fprintf(fp, "%ld", val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ * XXX - not needed on amd64
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%%%s", &rnames[p->n_rval][3]);
+               break;
+
+       case NAME:
+       case OREG:
+               setlval(p, getlval(p) + size);
+               adrput(stdout, p);
+               setlval(p, getlval(p) - size);
+               break;
+       case ICON:
+               printf("$" CONFMT, getlval(p) >> 32);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       int r;
+       char **rc;
+       /* output an address, with offsets, from p */
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       if (getlval(p) != 0)
+                               fprintf(io, CONFMT "+", getlval(p));
+                       fprintf(io, "%s(%%rip)", p->n_name);
+               } else
+                       fprintf(io, CONFMT, getlval(p));
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               if (p->n_name[0])
+                       printf("%s%s", p->n_name, getlval(p) ? "+" : "");
+               if (getlval(p))
+                       fprintf(io, "%lld", getlval(p));
+               if (R2TEST(r)) {
+                       int r1 = R2UPK1(r);
+                       int r2 = R2UPK2(r);
+                       int sh = R2UPK3(r);
+
+                       fprintf(io, "(%s,%s,%d)", 
+                           r1 == MAXREGS ? "" : rnames[r1],
+                           r2 == MAXREGS ? "" : rnames[r2], sh);
+               } else
+                       fprintf(io, "(%s)", rnames[p->n_rval]);
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               fputc('$', io);
+               conput(io, p);
+               return;
+
+       case REG:
+               switch (p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       rc = rbyte;
+                       break;
+               case SHORT:
+               case USHORT:
+                       rc = rshort;
+                       break;
+               case INT:
+               case UNSIGNED:
+                       rc = rlong;
+                       break;
+               default:
+                       rc = rnames;
+                       break;
+               }
+               fprintf(io, "%s", rc[p->n_rval]);
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+static char *
+ccbranches[] = {
+       "je",           /* jumpe */
+       "jne",          /* jumpn */
+       "jle",          /* jumple */
+       "jl",           /* jumpl */
+       "jge",          /* jumpge */
+       "jg",           /* jumpg */
+       "jbe",          /* jumple (jlequ) */
+       "jb",           /* jumpl (jlssu) */
+       "jae",          /* jumpge (jgequ) */
+       "ja",           /* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("        %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+/*
+ * gcc xasm has the ability to generate different asm types
+ * via some magic.
+ *
+ * Only support AT&T asm for now.
+ */
+static char *
+adjustname(char *s)
+{
+       int len = strlen(s);
+       char *d = tmpalloc(len+1);
+       int i, j, flvl, tlvl;
+
+       flvl = tlvl = 0;
+       for (i = j = 0; i < len; i++) {
+               switch (s[i]) {
+               case '{': tlvl++; break;
+               case '}': if (tlvl)tlvl--; else flvl--; break;
+               case '|': tlvl--; flvl++; break;
+               default:
+                       if (flvl == 0)
+                               d[j++] = s[i];
+                       break;
+               }
+       }
+       d[j] = 0;
+       return d;
+}
+
+static void
+fixcalls(NODE *p, void *arg)
+{
+       int ps;
+
+       /* Prepare for struct return by allocating bounce space on stack */
+       switch (p->n_op) {
+       case STCALL:
+       case USTCALL:
+               ps = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+               if (ps < 16)
+                       ps = 16;
+               if (ps+p2autooff > stkpos)
+                       stkpos = ps+p2autooff;
+               break;
+       case XASM:
+               p->n_name = adjustname(p->n_name);
+               break;
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       stkpos = p2autooff;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, fixcalls, 0);
+       }
+       if (stkpos > p2autooff)
+               p2autooff = stkpos;
+       if (stkpos > p2maxautooff)
+               p2maxautooff = stkpos;
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+
+       switch (t) {
+       case INT:
+       case UNSIGNED:
+               printf("        movl %s,%s\n", rlong[s], rlong[d]);
+               break;
+       case CHAR:
+       case UCHAR:
+               printf("        movb %s,%s\n", rbyte[s], rbyte[d]);
+               break;
+       case SHORT:
+       case USHORT:
+               printf("        movw %s,%s\n", rshort[s], rshort[d]);
+               break;
+       case FLOAT:
+               printf("        movss %s,%s\n", rnames[s], rnames[d]);
+               break;
+       case DOUBLE:
+               printf("        movsd %s,%s\n", rnames[s], rnames[d]);
+               break;
+       case LDOUBLE:
+#ifdef notdef
+               /* a=b()*c(); will generate this */
+               /* XXX can it fail anyway? */
+               comperr("bad float rmove: %d %d", s, d);
+#endif
+               break;
+       default:
+               printf("        movq %s,%s\n", rnames[s], rnames[d]);
+               break;
+       }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+
+       switch (c) {
+       case CLASSA:
+               return r[CLASSA] < 14;
+       case CLASSB:
+               return r[CLASSB] < 16;
+       case CLASSC:
+               return r[CLASSC] < CREGCNT;
+       }
+       return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+       "%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
+       "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+       "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
+       "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14",
+       "%xmm15",
+};
+
+/* register names for shorter sizes */
+char *rbyte[] = {
+       "%al", "%dl", "%cl", "%bl", "%sil", "%dil", "%bpl", "%spl",
+       "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b", 
+};
+char *rshort[] = {
+       "%ax", "%dx", "%cx", "%bx", "%si", "%di", "%bp", "%sp",
+       "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w", 
+};
+char *rlong[] = {
+       "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
+       "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d", 
+};
+
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == LDOUBLE)
+               return CLASSC;
+       if (t == FLOAT || t == DOUBLE)
+               return CLASSB;
+       return CLASSA;
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (p->n_left->n_op == REG)
+               return 0; /* not on stack */
+       if (t == LDOUBLE)
+               return 16;
+       if (p->n_op == STASG)
+               return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       return 8;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               size += argsiz(p->n_right);
+       size += argsiz(p);
+       size = (size+15) & ~15;
+       if (size)
+               printf("        subq $%d,%s\n", size, rnames[RSP]);
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       int o = p->n_op;
+
+       switch (shape) {
+       case SFUNCALL:
+               if (o == STCALL || o == USTCALL)
+                       return SRREG;
+               break;
+       case SPCON:
+               if (o != ICON || p->n_name[0] ||
+                   getlval(p) < 0 || getlval(p) > 0x7fffffff)
+                       break;
+               return SRDIR;
+       case SMIXOR:
+               return tshape(p, SZERO);
+       case SMILWXOR:
+               if (o != ICON || p->n_name[0] ||
+                   getlval(p) == 0 || getlval(p) & 0xffffffff)
+                       break;
+               return SRDIR;
+       case SMIHWXOR:
+               if (o != ICON || p->n_name[0] ||
+                    getlval(p) == 0 || (getlval(p) >> 32) != 0)
+                       break;
+               return SRDIR;
+       case SCON32:
+               if (o != ICON || p->n_name[0])
+                       break;
+               if (getlval(p) < MIN_INT || getlval(p) > MAX_INT)
+                       break;
+               return SRDIR;
+       default:
+               cerror("special: %x\n", shape);
+       }
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       struct interpass *ip2;
+       int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
+       NODE *in = 0, *ut = 0;
+       TWORD t;
+       char *w;
+       int reg;
+       int c, cw, v;
+
+       cw = xasmcode(p->n_name);
+       if (cw & (XASMASG|XASMINOUT))
+               ut = p->n_left;
+       if ((cw & XASMASG) == 0)
+               in = p->n_left;
+
+       c = XASMVAL(cw);
+retry: switch (c) {
+       case 'D': reg = RDI; break;
+       case 'S': reg = RSI; break;
+       case 'A': 
+       case 'a': reg = RAX; break;
+       case 'b': reg = RBX; break;
+       case 'c': reg = RCX; break;
+       case 'd': reg = RDX; break;
+
+       case 'Q': reg = RDX; break; /* Always dx for now */
+
+       case 'x':
+       case 'q':
+       case 't':
+       case 'u':
+               p->n_name = tmpstrdup(p->n_name);
+               w = strchr(p->n_name, c);
+               *w = 'r'; /* now reg */
+               return c == 'q' || c == 'x' || c == 't' ? 0 : 1;
+
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+               if (p->n_left->n_op != ICON) {
+                       if ((c = XASMVAL1(cw))) {
+                               if (c == 'r') {
+                                       p->n_name++;
+                                       return 0;
+                               }
+                               goto retry;
+                       }
+                       uerror("xasm arg not constant");
+               }
+               v = getlval(p->n_left);
+               if ((c == 'K' && v < -128) ||
+                   (c == 'L' && v != 0xff && v != 0xffff) ||
+                   (c != 'K' && v < 0) ||
+                   (v > Cmax[c-'I']))
+                       uerror("xasm val out of range");
+               p->n_name = "i";
+               return 1;
+
+       default:
+               return 0;
+       }
+       /* If there are requested either memory or register, delete memory */
+       w = p->n_name = tmpstrdup(p->n_name);
+       if (*w == '=')
+               w++;
+       *w++ = 'r';
+       *w = 0;
+
+       t = p->n_left->n_type;
+
+       if (t == FLOAT || t == DOUBLE) {
+               reg += 16;
+       } else if (t == LDOUBLE) {
+               reg += 32;
+       }
+
+       if (in && ut)
+               in = tcopy(in);
+       p->n_left = mklnode(REG, 0, reg, t);
+       if (ut) {
+               ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+               DLIST_INSERT_AFTER(ip, ip2, qelem);
+       }
+       if (in) {
+               ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+               DLIST_INSERT_BEFORE(ip, ip2, qelem);
+       }
+
+       return 1;
+}
+
+void
+targarg(char *w, void *arg, int n)
+{
+       NODE **ary = arg;
+       NODE *p, *q;
+
+       if (w[1] < '0' || w[1] > (n + '0'))
+               uerror("bad xasm arg number %c", w[1]);
+       if (w[1] == (n + '0'))
+               p = ary[(int)w[1]-'0' - 1]; /* XXX */
+       else
+               p = ary[(int)w[1]-'0'];
+       p = p->n_left;
+
+       if (optype(p->n_op) != LTYPE)
+               comperr("bad xarg op %d", p->n_op);
+       q = tcopy(p);
+       if (q->n_op == REG) {
+               if (*w == 'k') {
+                       q->n_type = INT;
+               } else if (*w == 'q') {
+                       q->n_type = LONG;
+               } else if (*w == 'h' || *w == 'b') {
+                       /* Can do this only because we know dx is used */
+                       printf("%%d%c", *w == 'h' ? 'h' : 'l');
+                       tfree(q);
+                       return;
+               } else if (*w != 'w') {
+                       cerror("targarg"); /* XXX ??? */
+                       if (q->n_type > UCHAR) {
+                               regno(q) = regno(q)*2+8;
+                               if (*w == 'h')
+                                       regno(q)++;
+                       }
+                       q->n_type = INT;
+               } else
+                       q->n_type = SHORT;
+       }
+       adrput(stdout, q);
+       tfree(q);
+}
+
+/*
+ * target-specific conversion of numeric arguments.
+ */
+int
+numconv(void *ip, void *p1, void *q1)
+{
+       NODE *p = p1, *q = q1;
+       int cw = xasmcode(q->n_name);
+
+       switch (XASMVAL(cw)) {
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+               p->n_name = tmpcalloc(2);
+               p->n_name[0] = XASMVAL(cw);
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static struct {
+       char *name; int num;
+} xcr[] = {
+       { "rax", RAX },
+       { "rbx", RBX },
+       { "rcx", RCX },
+       { "rdx", RDX },
+       { "rsi", RSI },
+       { "rdi", RDI },
+       { "r8", R08 },
+       { "r9", R09 },
+       { "r10", R10 },
+       { "r11", R11 },
+       { "r12", R12 },
+       { "r13", R13 },
+       { "r14", R14 },
+       { "r15", R15 },
+       { "st", 040 },
+       { "st(0)", 040 },
+       { "st(1)", 041 },
+       { "st(2)", 042 },
+       { "st(3)", 043 },
+       { "st(4)", 044 },
+       { "st(5)", 045 },
+       { "st(6)", 046 },
+       { "st(7)", 047 },
+       { NULL, 0 },
+};
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+int xasmconstregs(char *s)
+{
+       int i;
+
+       for (i = 0; xcr[i].name; i++)
+               if (strcmp(xcr[i].name, s) == 0)
+                       return xcr[i].num;
+       return -1;
+}
+
diff --git a/lang/pcc/pcc/arch/amd64/macdefs.h b/lang/pcc/pcc/arch/amd64/macdefs.h
new file mode 100644 (file)
index 0000000..5548303
--- /dev/null
@@ -0,0 +1,295 @@
+/*     $Id: macdefs.h,v 1.36 2016/03/05 15:49:36 ragge Exp $   */
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT                128     /* # bits above fp where arguments start */
+#define AUTOINIT       0       /* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         8
+#define SZSHORT                16
+#define SZINT          32
+#define SZLONG         64
+#define SZPOINT(t)     64
+#define SZLONGLONG     64
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      128
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         8
+#define ALSHORT                16
+#define ALINT          32
+#define ALLONG         64
+#define ALPOINT                64
+#define ALLONGLONG     64
+#define ALFLOAT                32
+#define ALDOUBLE       64
+#define ALLDOUBLE      128
+/* #undef ALSTRUCT     amd64 struct alignment is member defined */
+#define ALSTACK                64
+#define ALMAX          128 
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         (-0x7fffffff-1)
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffffU
+#define        MIN_LONG        0x8000000000000000LL
+#define        MAX_LONG        0x7fffffffffffffffLL
+#define        MAX_ULONG       0xffffffffffffffffULL
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+/* Default char is signed */
+#undef CHAR_UNSIGNED
+#define        BOOL_TYPE       UCHAR   /* what used to store _Bool */
+
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#define LABFMT ".L%d"          /* format for printing labels */
+#define        STABLBL ".LL%d"         /* format for stab (debugging) labels */
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define        AUTOREG EBP
+#define        ARGREG  EBP
+#define ARGOFFSET 8
+#endif
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define        TARGET_ENDIAN TARGET_LE /* little-endian only */
+
+#define FINDMOPS       /* i386 has instructions that modifies memory */
+
+#define        CC_DIV_0        /* division by zero is safe in the compiler */
+
+#ifdef MACHOABI
+#define        HASP2ALIGN
+#endif
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&07)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)  gencall(a,b)
+
+/* How many integer registers are needed? (used for stack allocation) */
+#define        szty(t) (t < LONG || t == FLOAT ? 1 : t == LDOUBLE ? 4 : 2)
+
+/*
+ * The amd64 architecture has a much cleaner interface to its registers
+ * than the x86, even though a part of the register block comes from 
+ * the x86 architecture.  Therefore currently only two non-overlapping 
+ * register classes are used; integer and xmm registers.
+ *
+ * All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ *
+ * The classes used on amd64 are:
+ *     A - integer registers
+ *     B - xmm registers
+ *     C - x87 registers
+ */
+#define        RAX     000
+#define        RDX     001
+#define        RCX     002
+#define        RBX     003
+#define        RSI     004
+#define        RDI     005
+#define        RBP     006
+#define        RSP     007
+#define        R08     010
+#define        R09     011
+#define        R10     012
+#define        R11     013
+#define        R12     014
+#define        R13     015
+#define        R14     016
+#define        R15     017
+
+#define        XMM0    020
+#define        XMM1    021
+#define        XMM2    022
+#define        XMM3    023
+#define        XMM4    024
+#define        XMM5    025
+#define        XMM6    026
+#define        XMM7    027
+#define        XMM8    030
+#define        XMM9    031
+#define        XMM10   032
+#define        XMM11   033
+#define        XMM12   034
+#define        XMM13   035
+#define        XMM14   036
+#define        XMM15   037
+
+#define        MAXREGS 050     /* 40 registers */
+
+#define        RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG,     \
+       SAREG|TEMPREG, SAREG|TEMPREG, 0, 0,                             \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,     \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,     \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,     \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,     \
+       SCREG, SCREG, SCREG, SCREG,  SCREG, SCREG, SCREG, SCREG,
+
+
+/* no overlapping registers at all */
+#define        ROVERLAP \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },
+
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (p->n_type == FLOAT || p->n_type == DOUBLE ? SBREG : \
+                  p->n_type == LDOUBLE ? SCREG : SAREG)
+
+#define        NUMCLASS        3       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define        GCLASS(x) (x < 16 ? CLASSA : x < 32 ? CLASSB : CLASSC)
+#define DECRA(x,y)     (((x) >> (y*8)) & 255)  /* decode encoded regs */
+#define        ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 8)      /* A1 */
+#define ENCRA2(x)      ((x) << 16)     /* A2 */
+#define ENCRA(x,y)     ((x) << (8+y*8))        /* encode regs in int */
+
+#define        RETREG(x)       (x == FLOAT || x == DOUBLE ? XMM0 : \
+                        x == LDOUBLE ? 32 : RAX)
+
+/* XXX - to die */
+#define FPREG  RBP     /* frame pointer */
+#define STKREG RSP     /* stack pointer */
+
+#define        SHSTR           (MAXSPECIAL+1)  /* short struct */
+#define        SFUNCALL        (MAXSPECIAL+2)  /* struct assign after function call */
+#define        SPCON           (MAXSPECIAL+3)  /* positive nonnamed constant */
+
+/*
+ * Specials that indicate the applicability of machine idioms.
+ */
+#define SMIXOR         (MAXSPECIAL+4)
+#define SMILWXOR       (MAXSPECIAL+5)
+#define SMIHWXOR       (MAXSPECIAL+6)
+#define SCON32         (MAXSPECIAL+7)  /* 32-bit constant */
+
+/*
+ * i386-specific symbol table flags.
+ */
+#define SBEENHERE      SLOCAL1
+
+/*
+ * Extended assembler macros.
+ */
+int xasmconstregs(char *);
+void targarg(char *w, void *arg, int n);
+#define        XASM_TARGARG(w, ary)    \
+       (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' || \
+        w[1] == 'q' ? w++, targarg(w, ary, n), 1 : 0)
+int numconv(void *ip, void *p, void *q);
+#define        XASM_NUMCONV(ip, p, q)  numconv(ip, p, q)
+#define        XASMCONSTREGS(x)        xasmconstregs(x)
+
+#define        HAVE_WEAKREF
+#define TARGET_FLT_EVAL_METHOD 0       /* all as their type */
+/*
+ * builtins.
+ */
+#define TARGET_VALIST
+#define TARGET_STDARGS
+#define TARGET_BUILTINS                                                        \
+       { "__builtin_stdarg_start", amd64_builtin_stdarg_start,         \
+                                               0, 2, 0, VOID },        \
+       { "__builtin_va_start", amd64_builtin_stdarg_start,             \
+                                               0, 2, 0, VOID },        \
+       { "__builtin_va_arg", amd64_builtin_va_arg, BTNORVAL|BTNOPROTO, \
+                                                       2, 0, 0 },      \
+       { "__builtin_va_end", amd64_builtin_va_end, 0, 1, 0, VOID },    \
+       { "__builtin_va_copy", amd64_builtin_va_copy, 0, 2, 0, VOID },
+
+#ifdef LANG_CXX
+#define P1ND struct node
+#else
+#define P1ND struct p1node
+#endif
+struct node;
+struct bitable;
+P1ND *amd64_builtin_stdarg_start(const struct bitable *, P1ND *a);
+P1ND *amd64_builtin_va_arg(const struct bitable *, P1ND *a);
+P1ND *amd64_builtin_va_end(const struct bitable *, P1ND *a);
+P1ND *amd64_builtin_va_copy(const struct bitable *, P1ND *a);
+#undef P1ND
+
+/* target specific attributes */
+#define ATTR_MI_TARGET  ATTR_AMD64_CMPLRET, ATTR_AMD64_XORLBL
diff --git a/lang/pcc/pcc/arch/amd64/order.c b/lang/pcc/pcc/arch/amd64/order.c
new file mode 100644 (file)
index 0000000..ac43cda
--- /dev/null
@@ -0,0 +1,363 @@
+/*     $Id: order.c,v 1.18 2015/12/13 09:00:04 ragge Exp $     */
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       if (off > MAX_INT || off < MIN_INT)
+               return 1; /* max signed 32-bit offset */
+       return(0);  /* YES */
+}
+
+/*
+ * Check if LS and try to make it indexable.
+ * Ignore SCONV to long.
+ * Return 0 if failed.
+ */
+static int
+findls(NODE *p, int check)
+{
+       CONSZ c;
+
+       if (p->n_op == SCONV && p->n_type == LONG && p->n_left->n_type == INT)
+               p = p->n_left; /* Ignore pointless SCONVs here */
+       if (p->n_op != LS || p->n_right->n_op != ICON)
+               return 0;
+       if ((c = getlval(p->n_right)) != 1 && c != 2 && c != 3)
+               return 0;
+       if (check == 1 && p->n_left->n_op != REG)
+               return 0;
+       if (!isreg(p->n_left))
+               (void)geninsn(p->n_left, INAREG);
+       return 1;
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ *
+ * AMD64 (and i386) have a quite powerful addressing scheme:
+ *     :       4(%rax)         4 + %rax
+ *     :       4(%rbx,%rax,8)  4 + %rbx + %rax * 8
+ *     :       4(,%rax)        4 + %rax * 8
+ * The 8 above can be 1,2,4 or 8.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *l;
+
+       if (x2debug) {
+               printf("offstar(%p)\n", p);
+               fwalk(p, e2print, 0);
+       }
+
+       if (isreg(p))
+               return; /* Matched (%rax) */
+
+       if (findls(p, 0))
+               return; /* Matched (,%rax,8) */
+
+       if ((p->n_op == PLUS || p->n_op == MINUS) &&
+           p->n_left->n_op == ICON &&
+           p->n_left->n_name[0] == '\0' &&
+           notoff(0, 0,  getlval(p->n_left), 0) == 0) {
+               l = p->n_right;
+               if (isreg(l))
+                       return; /* Matched 4(%rax) */
+               if (findls(l, 0))
+                       return; /* Matched 4(,%rax,8) */
+               if (l->n_op == PLUS && isreg(l->n_right)) {
+                       if (findls(l->n_left, 0))
+                               return; /* Matched 4(%rbx,%rax,8) */
+                       (void)geninsn(l->n_left, INAREG);
+                       return; /* Generate 4(%rbx,%rax) */
+               }
+               (void)geninsn(l, INAREG);
+               return; /* Generate 4(%rbx) */
+       }
+
+       if (p->n_op == PLUS) {
+               if (!isreg(p->n_left)) /* ensure right is REG */
+                       (void)geninsn(p->n_left, INAREG);
+               if (isreg(p->n_right))
+                       return; /* Matched (%rax,%rbx) */
+               if (findls(p->n_right, 0))
+                       return; /* Matched (%rax,%rbx,4) */
+               (void)geninsn(p->n_right, INAREG);
+               return; /* Generate (%rbx,%rax) */
+       }
+               
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ * For simple OREGs conversion should already be done.
+ */
+void
+myormake(NODE *q)
+{
+       static int shtbl[] = { 1,2,4,8 };
+       NODE *p, *r;
+       CONSZ c = 0;
+       int r1, r2, sh;
+       int mkconv = 0;
+       char *n = "";
+
+#define        risreg(p)       (p->n_op == REG)
+       if (x2debug) {
+               printf("myormake(%p)\n", q);
+               fwalk(q, e2print, 0);
+       }
+       r1 = r2 = MAXREGS;
+       sh = 1;
+
+       r = p = q->n_left;
+
+       if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON) {
+               c = getlval(p->n_left);
+               n = p->n_left->n_name;
+               p = p->n_right;
+       }
+
+       if (p->n_op == PLUS && risreg(p->n_left)) {
+               r1 = regno(p->n_left);
+               p = p->n_right;
+       }
+
+       if (findls(p, 1)) {
+               if (p->n_op == SCONV)
+                       p = p->n_left;
+               sh = shtbl[(int)getlval(p->n_right)];
+               r2 = regno(p->n_left);
+               mkconv = 1;
+       } else if (risreg(p)) {
+               r2 = regno(p);
+               mkconv = 1;
+       } //else
+       //      comperr("bad myormake tree");
+
+       if (mkconv == 0)
+               return;
+
+       q->n_op = OREG;
+       setlval(q, c);
+       q->n_rval = R2PACK(r1, r2, sh);
+       q->n_name = n;
+       tfree(r);
+       if (x2debug) {
+               printf("myormake converted %p\n", q);
+               fwalk(q, e2print, 0);
+       }
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on x86 */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case SCONV:
+               if ((q->ltype & TINT) &&
+                   q->rtype == (TLONGLONG|TULONGLONG|TLONG|TULONG)) {
+                       static struct rspecial s[] = { 
+                               { NLEFT, RAX }, { NRES, RAX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case DIV:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, RAX }, { NEVER, RDX },
+                               { NLEFT, RAX }, { NRES, RAX },
+                               { NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case MOD:
+               if (q->ltype & TUCHAR) {
+                       static struct rspecial s[] = {
+                               { NEVER, RAX },
+                               { NLEFT, RAX }, { NRES, RAX },
+                               { NORIGHT, RAX }, { 0 } };
+                       return s;
+               } else {
+                       static struct rspecial s[] = {
+                               { NEVER, RAX }, { NEVER, RDX },
+                               { NLEFT, RAX }, { NRES, RDX },
+                               { NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case STARG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, RDI }, 
+                               { NLEFT, RSI },
+                               { NEVER, RCX }, { 0 } };
+                       return s;
+               }
+
+       case STASG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, RDI }, 
+                               { NRIGHT, RSI }, { NOLEFT, RSI },
+                               { NOLEFT, RCX }, { NORIGHT, RCX },
+                               { NEVER, RCX }, { 0 } };
+                       return s;
+               }
+
+       case MUL:
+               if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, RAX },
+                               { NLEFT, RAX }, { NRES, RAX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case LS:
+       case RS:
+               {
+                       static struct rspecial s[] = {
+                               { NRIGHT, RCX }, { NOLEFT, RCX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       default:
+               break;
+       }
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on x86 */
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[NTEMPREG+1];
+       NODE *q;
+       int cr = 0;
+
+       if (optype(p->n_op) != BITYPE)
+               return r[0] = -1, r;
+
+       for (q = p->n_right; q->n_op == CM; q = q->n_left) {
+               if (q->n_right->n_op == ASSIGN &&
+                   q->n_right->n_left->n_op == REG)
+                       r[cr++] = regno(q->n_right->n_left);
+       }
+       if (q->n_op == ASSIGN && q->n_left->n_op == REG)
+               r[cr++] = regno(q->n_left);
+       r[cr++] = -1;
+       return r;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/amd64/table.c b/lang/pcc/pcc/arch/amd64/table.c
new file mode 100644 (file)
index 0000000..332cadc
--- /dev/null
@@ -0,0 +1,1594 @@
+/*     $Id: table.c,v 1.55 2015/02/07 08:47:54 ragge Exp $     */
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2008 Anders Magnusson (ragge@ludd.ltu.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#define TLL TLONG|TULONG
+# define ANYSIGNED TINT|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED
+# define TSWORD TINT
+# define TWORD TUWORD|TSWORD
+#define        TANYINT TLL|ANYFIXED
+#define         SHINT  SAREG   /* Any integer */
+#define         ININT  INAREG
+#define         SHFL   SCREG   /* shape for long double */
+#define         INFL   INCREG  /* shape for long double */
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TLL|TPOINT,
+       SAREG,  TLL|TPOINT,
+               0,      RLEFT,
+               "", },
+
+{ PCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TWORD,
+       SAREG,  TPOINT,
+               NASL|NAREG,     RESC1,
+               "       movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */
+
+{ PCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TCHAR,
+       SAREG,                  TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movsbq AL,A1\n", },
+
+{ PCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TUCHAR,
+       SAREG,                  TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movsbq AL,A1\n", },
+
+/* short to ptr */
+{ PCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SAREG,                  TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movswq AL,A1\n", },
+
+/* ushort to ptr */
+{ PCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SAREG,                  TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movzwq AL,A1\n", },
+
+
+/*
+ * On amd64 casts from larger to smaller integer type in register do nothing.
+ */
+/* 64-bit to smaller */
+{ SCONV,       INAREG,
+       SAREG,  TLL|TPOINT,
+       SAREG,  TANYINT,
+               0,      RLEFT,
+               "", },
+
+/* 32-bit to smaller */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  ANYFIXED,
+               0,      RLEFT,
+               "", },
+
+/* 16-bit to smaller */
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TUSHORT|TUCHAR|TSHORT|TCHAR,
+               0,      RLEFT,
+               "", },
+
+/* 8-bit to 8-bit */
+{ SCONV,       INAREG,
+       SAREG,  TCHAR|TUCHAR,
+       SAREG,  TUCHAR|TCHAR,
+               0,      RLEFT,
+               "", },
+
+/*
+ * Casts from memory to same or smaller register is equally simple.
+ */
+/* 64-bit to smaller */
+{ SCONV,       INAREG,
+       SNAME|SOREG,    TLL|TPOINT,
+       SAREG,          TANYINT,
+               NAREG,  RESC1,
+               "       movZR AL,A1\n", },
+
+/* 32-bit to smaller */
+{ SCONV,       INAREG,
+       SNAME|SOREG,    TWORD,
+       SAREG,          ANYFIXED,
+               NAREG,  RESC1,
+               "       movZR AL,A1\n", },
+
+/* 16-bit to smaller */
+{ SCONV,       INAREG,
+       SNAME|SOREG,    TSHORT|TUSHORT,
+       SAREG,          TUSHORT|TUCHAR|TSHORT|TCHAR,
+               NAREG,  RESC1,
+               "       movZR AL,A1\n", },
+
+/* 8-bit to 8-bit */
+{ SCONV,       INAREG,
+       SNAME|SOREG,    TCHAR|TUCHAR,
+       SAREG,          TUCHAR|TCHAR,
+               NAREG,  RESC1,
+               "       movZR AL,A1\n", },
+
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TCHAR,
+       SAREG,  TSHORT|TUSHORT,
+               NASL|NAREG,     RESC1,
+               "       movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TUCHAR,
+       SAREG,  TSHORT|TUSHORT,
+               NASL|NAREG,     RESC1,
+               "       movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TCHAR,
+       SAREG,  TWORD|TPOINT,
+               NASL|NAREG,     RESC1,
+               "       movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TUCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TCHAR,
+       SANY,   TLL,
+               NAREG|NASL,     RESC1,
+               "       movsbq AL,A1\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TUCHAR,
+       SANY,                   TLL,
+               NAREG|NASL,     RESC1,
+               "       movzbq AL,A1\n", },
+
+/* short to something */
+
+/* convert short to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SAREG,                  TLL,
+               NAREG|NASL,     RESC1,
+               "       movswq AL,A1\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SAREG,                  TLL,
+               NAREG|NASL,     RESC1,
+               "       movzwq AL,A1\n", },
+
+/* int to something */
+
+/* convert signed int to (u)long long */
+{ SCONV,       INAREG,
+       SAREG,  TSWORD,
+       SAREG,  TLL,
+               NASL|NAREG,     RESC1,
+               "       movslq AL,A1\n", },
+
+/* convert unsigned int to (u)long long */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TUWORD,
+       SAREG,  TLL,
+               NASL|NAREG,     RESC1,
+               "       movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */
+
+/*
+ * Floating point casts.  amd64 uses xmm for float/double and x87
+ * for long double calculations.
+ *
+ * Types smaller than int are casted to int/(unsigned).
+ */
+/* no casts */
+{ SCONV,       INBREG,
+       SBREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               0,      RLEFT,
+               "", },
+
+{ SCONV,       INBREG,
+       SBREG,  TDOUBLE,
+       SBREG,  TDOUBLE,
+               0,      RLEFT,
+               "", },
+
+{ SCONV,       INCREG,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               0,      RLEFT,
+               "", },
+
+
+/* convert int/long to float/double */
+{ SCONV,       INBREG,
+       SAREG|SOREG|SNAME,      TINT|TLONG,
+       SBREG,                  TFLOAT|TDOUBLE,
+               NBREG,  RESC1,
+               "       cvtsi2sZfZq AL,A1\n", },
+
+/* convert unsigned int to float/double */
+{ SCONV,       INBREG,
+       SAREG|SOREG|SNAME,      TUNSIGNED,
+       SBREG,                  TFLOAT|TDOUBLE,
+               NAREG|NBREG,    RESC2,
+               "       movl AL,Z1\n    cvtsi2sZfq A1,A2\n", },
+
+/* convert unsigned long to float/double */
+{ SCONV,       INBREG,
+       SAREG|SOREG|SNAME,      TULONG,
+       SBREG,                  TFLOAT|TDOUBLE,
+               NAREG*2|NASL|NBREG,     RESC3,
+               "Zj", },
+
+/* convert float/double to (u)char/(u)short/int */
+{ SCONV,       INAREG,
+       SBREG|SOREG|SNAME,      TFLOAT|TDOUBLE,
+       SAREG,                  TCHAR|TUCHAR|TSHORT|TUSHORT|INT,
+               NAREG,          RESC1,
+               "       cvttsZg2si AL,A1\n", },
+
+/* convert float/double to  unsigned int/long */
+{ SCONV,       INAREG,
+       SBREG|SOREG|SNAME,      TFLOAT|TDOUBLE,
+       SAREG,                  TUNSIGNED|TLONG,
+               NAREG,          RESC1,
+               "       cvttsZg2siq AL,Z8\n", },
+
+/* convert float to double */
+{ SCONV,       INBREG,
+       SBREG|SNAME|SOREG,      TFLOAT,
+       SBREG,  TDOUBLE,
+               NBREG|NBSL,     RESC1,
+               "       cvtss2sd AL,A1\n", },
+
+/* convert double to float */
+{ SCONV,       INBREG,
+       SBREG|SNAME|SOREG,      TDOUBLE,
+       SBREG,  TFLOAT,
+               NBREG|NBSL,     RESC1,
+               "       cvtsd2ss AL,A1\n", },
+
+/* x87 conversions */
+/* float -> ldouble */
+{ SCONV,       INCREG,
+       SBREG,  TFLOAT,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               "\tsubq $4,%rsp\n\tmovss AL,(%rsp)\n"
+               "\tflds (%rsp)\n\taddq $4,%rsp\n", },
+
+/* double -> ldouble */
+{ SCONV,       INCREG,
+       SBREG,  TDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               "\tsubq $8,%rsp\n\tmovsd AL,(%rsp)\n"
+               "\tfldl (%rsp)\n\taddq $8,%rsp\n", },
+
+/* ldouble -> double */
+{ SCONV,       INBREG,
+       SCREG,  TLDOUBLE,
+       SBREG,  TDOUBLE,
+               NBREG,          RESC1,
+               "\tsubq $8,%rsp\n\tfstpl (%rsp)\n"
+               "\tmovsd (%rsp),A1\n\taddq $8,%rsp\n", },
+
+/* ldouble -> float */
+{ SCONV,       INBREG,
+       SCREG,  TLDOUBLE,
+       SBREG,  TFLOAT,
+               NBREG,          RESC1,
+               "\tsubq $4,%rsp\n\tfstps (%rsp)\n"
+               "\tmovss (%rsp),A1\n\taddq $4,%rsp\n", },
+
+/* convert int (in memory) to long double */
+{ SCONV,       INCREG,
+       SOREG|SNAME,    TSWORD,
+       SCREG,   TLDOUBLE,
+               NCREG,  RESC1,
+               "       fildl AL\n", },
+
+/* convert unsigned int to long double */
+{ SCONV,       INCREG,
+       SAREG,  TUWORD,
+       SCREG,  TLDOUBLE,
+               NAREG|NASL|NCREG,       RESC2,
+               "       subq $16,%rsp\n"
+               "       movl AL,Z1\n"
+               "       movq A1,(%rsp)\n"
+               "       fildll (%rsp)\n"
+               "       addq $16,%rsp\n", },
+
+/* convert int (in register) to long double */
+{ SCONV,       INCREG,
+       SAREG,  TSWORD,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       subq $4,%rsp\n"
+               "       movl AL,(%rsp)\n"
+               "       fildl (%rsp)\n"
+               "       addq $4,%rsp\n", },
+
+/* unsigned long (in reg) to long double */
+{ SCONV,       INCREG,
+       SAREG,          TULONG,
+       SCREG,          TLDOUBLE,
+               NCREG,  RESC1,
+               "       subq $16,%rsp\n"
+               "       movq AL,(%rsp)\n"
+               "       fildll (%rsp)\n"
+               "       cmpq $0,AL\n"
+               "       jns 1f\n"
+               "       movl $1602224128,(%rsp)\n"
+               "       fadds (%rsp)\n"
+               "       addq $16,%rsp\n"
+               "1:\n", },
+
+/* unsigned long (in mem) to long double */
+{ SCONV,       INCREG,
+       SNAME|SOREG,    TULONG,
+       SCREG,          TLDOUBLE,
+               NCREG,  RESC1,
+               "       fildll AL\n"
+               "       cmpq $0,AL\n"
+               "       jns 1f\n"
+               "       push $1602224128\n"
+               "       fadds (%rsp)\n"
+               "       addq $8,%rsp\n"
+               "1:\n", },
+
+/* convert float/double to  unsigned long */
+{ SCONV,       INAREG,
+       SBREG,          TFLOAT|TDOUBLE,
+       SAREG,          TULONG,
+               (NAREG*2)|NBREG,        RESC1,
+               "Zb\n", },
+
+/* long double to unsigned long */
+{ SCONV,       INAREG,
+       SCREG|SNAME|SOREG,      TLDOUBLE,
+       SAREG,                  TULONG,
+               NAREG,  RESC1,
+               "ZB", },
+
+/* ldouble -> long  XXX merge with int */
+{ SCONV,       INAREG,
+       SCREG,  TLDOUBLE,
+       SAREG,  TLONG,
+               NAREG,  RESC1,
+               "       subq $16,%rsp\n"
+               "       fnstcw (%rsp)\n"
+               "       fnstcw 4(%rsp)\n"
+               "       movb $12,1(%rsp)\n"
+               "       fldcw (%rsp)\n"
+               "       fistpll 8(%rsp)\n"
+               "       movq 8(%rsp),A1\n"
+               "       fldcw 4(%rsp)\n"
+               "       addq $16,%rsp\n", },
+
+/* ldouble -> (u)int */
+{ SCONV,       INAREG,
+       SCREG,  TLDOUBLE,
+       SAREG,  TINT|TUNSIGNED,
+               NAREG,  RESC1,
+               "       subq $16,%rsp\n"
+               "       fnstcw (%rsp)\n"
+               "       fnstcw 4(%rsp)\n"
+               "       movb $12,1(%rsp)\n"
+               "       fldcw (%rsp)\n"
+               "       fistpq 8(%rsp)\n"
+               "       movl 8(%rsp),A1\n"
+               "       fldcw 4(%rsp)\n"
+               "       addq $16,%rsp\n", },
+
+/* long (in mem) -> ldouble */
+{ SCONV,       INCREG,
+       SNAME|SOREG,    TLONG,
+       SCREG,          TLDOUBLE,
+               NCREG,  RESC1,
+               "       fildll AL\n", },
+
+/* long (in reg) -> ldouble */
+{ SCONV,       INCREG,
+       SAREG,          TLONG,
+       SCREG,          TLDOUBLE,
+               NCREG,  RESC1,
+               "       subq $16,%rsp\n"
+               "       movq AL,(%rsp)\n"
+               "       fildll (%rsp)\n"
+               "       addq $16,%rsp\n", },
+
+
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call CL\nZC", },
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call CL\n", },
+
+{ CALL,        INAREG,
+       SCON,   TANY,
+       SAREG,  TLL|ANYFIXED|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SAREG,  TLL|ANYFIXED|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\n", },
+
+{ CALL,        INBREG,
+       SCON,   TANY,
+       SBREG,  TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL, INCREG,
+       SCON,   TANY,
+       SCREG,  TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INCREG,
+       SCON,   TANY,
+       SCREG,  TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INCREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INCREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+/* struct return */
+{ USTCALL,     FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     0,
+               "ZP     call CL\nZC", },
+
+{ USTCALL,     INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call CL\nZC", },
+
+{ USTCALL,     INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call *AL\nZC", },
+
+{ STCALL,      FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     0,
+               "ZP     call CL\nZC", },
+
+{ STCALL,      INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call CL\nZC", },
+
+{ STCALL,      FOREFF,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     0,      /* should be 0 */
+               "ZP     call *AL\nZC", },
+
+{ STCALL,      INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* floating point add */
+{ PLUS,                INBREG,
+       SBREG,                  TFLOAT|TDOUBLE,
+       SBREG|SNAME|SOREG,      TFLOAT|TDOUBLE,
+               0,      RLEFT,
+               "       addsZf AR,AL\n", },
+
+{ PLUS,                INCREG|FOREFF,
+       SHFL,   TLDOUBLE,
+       SHFL,   TLDOUBLE,
+               0,      RLEFT,
+               "       faddp\n", },
+
+
+{ PLUS,                INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incq AL\n", },
+
+{ PLUS,                INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incl AL\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TLL|TPOINT,
+       SCON,   TWORD,
+               NAREG|NASL,     RESC1,
+               "       leaq CR(AL),A1\n", },
+
+#ifdef notdef
+/* older binutils are missing leal */
+{ PLUS,                INAREG,
+       SAREG,  TWORD,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       leal CR(AL),A1\n", },
+#endif
+
+{ PLUS,                INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incw AL\n", },
+
+{ PLUS,                INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incb AL\n", },
+
+#ifdef notdef
+/* older binutils are missing leal */
+{ PLUS,                INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               NAREG|NASL|NASR,        RESC1,
+               "       leal (AL,AR),A1\n", },
+#endif
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+       SONE,                   TANY,
+               0,      RLEFT,
+               "       decq AL\n", },
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SONE,                   TANY,
+               0,      RLEFT,
+               "       decl AL\n", },
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SONE,                   TANY,
+               0,      RLEFT,
+               "       decw AL\n", },
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       decb AL\n", },
+
+/* address as register offset, negative */
+{ MINUS,       INAREG,
+       SAREG,  TLL|TPOINT,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       leaq -CR(AL),A1\n", },
+
+{ MINUS,       INBREG|FOREFF,
+       SBREG,                  TDOUBLE|TFLOAT,
+       SBREG|SNAME|SOREG,      TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       subsZf AR,AL\n", },
+
+{ MINUS,       INCREG|FOREFF,
+       SHFL,   TLDOUBLE,
+       SHFL,   TLDOUBLE,
+               0,      RLEFT,
+               "       fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+/* m/r |= r */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+       SAREG,                  TLL|TPOINT,
+               0,      RLEFT|RESCC,
+               "       Oq AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,                  TLL|TPOINT,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+               0,      RLEFT|RESCC,
+               "       Oq AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TWORD,
+       SAREG,                  TWORD,
+               0,      RLEFT|RESCC,
+               "       Ol AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,                  TWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               0,      RLEFT|RESCC,
+               "       Ol AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+       SHINT,          TSHORT|TUSHORT,
+               0,      RLEFT|RESCC,
+               "       Ow AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SHINT,          TSHORT|TUSHORT,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+               0,      RLEFT|RESCC,
+               "       Ow AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,          TCHAR|TUCHAR,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "       Ob AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,          TCHAR|TUCHAR,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "       Ob AR,AL\n", },
+
+/* m/r |= const */
+#ifdef notdef  /* amd64 lacks immediate 64-bit simple ops */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+       SCON,   TANY,
+               0,      RLEFT|RESCC,
+               "       Oq AR,AL\n", },
+#endif
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TWORD,
+       SCON,   TANY,
+               0,      RLEFT|RESCC,
+               "       Ol AR,AL\n", },
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,   TANY,
+               0,      RLEFT|RESCC,
+               "       Ow AR,AL\n", },
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SCON,   TANY,
+               0,      RLEFT|RESCC,
+               "       Ob AR,AL\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* r/m <<= r */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TLL,
+       SAREG,          TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       salq AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TLL,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       salq AR,AL\n", },
+
+/* r/m <<= r */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SAREG,          TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sall AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       sall AR,AL\n", },
+
+/* r/m <<= r */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shlw AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       shlw AR,AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       salb AR,AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SCON,                   TANY,
+               0,      RLEFT,
+               "       salb AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TLONG|TLONGLONG,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarq AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TLONG|TLONGLONG,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarq AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TULONG|TULONGLONG,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrq AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TULONG|TULONGLONG,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrq AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSWORD,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSWORD,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUWORD,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUWORD,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarb AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarb AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUCHAR,
+       SAREG,                  TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrb AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUCHAR,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN,      FORCC|FOREFF|INAREG,
+       SAREG,          TLL|TPOINT,
+       SMIXOR,         TANY,
+               0,      RDEST,
+               "       xorq AL,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TLL|TPOINT,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movabs AR,AL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INAREG,
+       SAREG,          TWORD,
+       SMIXOR,         TANY,
+               0,      RDEST,
+               "       xorl AL,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SCON,           TANY,
+               0,      0,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SMIXOR,         TANY,
+               0,      RDEST,
+               "       xorw AL,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,           TANY,
+               0,      0,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      0,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+       SAREG,                  TLL|TPOINT,
+               0,      RDEST,
+               "       movq AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TWORD,
+       SAREG,          TWORD,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,                  TWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,                  TPOINT,
+       SAREG|SNAME|SOREG,      TPOINT,
+               0,      RDEST,
+               "       movq AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RDEST,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SAREG,          TCHAR|TUCHAR|TWORD,
+               0,      RDEST,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      INBREG|FOREFF,
+       SBREG,                  TFLOAT|TDOUBLE,
+       SBREG|SOREG|SNAME,      TFLOAT|TDOUBLE,
+               0,      RDEST,
+               "       movsZf AR,AL\n", },
+
+{ ASSIGN,      INBREG|FOREFF,
+       SBREG|SOREG|SNAME,      TFLOAT|TDOUBLE,
+       SBREG,                  TFLOAT|TDOUBLE,
+               0,      RDEST,
+               "       movsZf AR,AL\n", },
+
+/* x87 entries */
+{ ASSIGN,      INDREG|FOREFF,
+       SHFL,   TLDOUBLE,
+       SHFL,   TLDOUBLE,
+               0,      RDEST,
+               "", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TLDOUBLE,
+       SHFL,   TLDOUBLE,
+               0,      RDEST,
+               "       fstpt AL\n      fldt AL\n", }, /* XXX */
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TLDOUBLE,
+       SHFL,   TLDOUBLE,
+               0,      0,
+               "       fstpt AL\n", },
+
+/* end very important order */
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TLDOUBLE,
+       SHFL|SOREG|SNAME,       TLDOUBLE,
+               0,      RDEST,
+               "       fldt AR\n", },
+
+/* end x87 */
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME|SAREG,      TPTRTO|TSTRUCT,
+       SFUNCALL,       TPTRTO|TSTRUCT,
+               0,      RRIGHT,
+               "", },
+#endif
+
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SAREG,          TPTRTO|TANY,
+               NSPECIAL|NAREG, RDEST,
+               "F      movq AR,A1\nZQF movq A1,AR\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+{ DIV, INAREG,
+       SAREG,                  TLONG,
+       SAREG|SNAME|SOREG,      TLL,
+               NSPECIAL,       RDEST,
+               "       cqto\n  idivq AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TULONG|TPOINT,
+       SAREG|SNAME|SOREG,      TLL|TPOINT,
+               NSPECIAL,       RDEST,
+               "       xorq %rdx,%rdx\n        divq AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TSWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               NSPECIAL,       RDEST,
+               "       cltd\n  idivl AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               NSPECIAL,       RDEST,
+               "       xorl %edx,%edx\n        divl AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUSHORT,
+       SAREG|SNAME|SOREG,      TUSHORT,
+               NSPECIAL,       RDEST,
+               "       xorl %edx,%edx\n        divw AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUCHAR,
+       SAREG|SNAME|SOREG,      TUCHAR,
+               NSPECIAL,       RDEST,
+               "       xorb %ah,%ah\n  divb AR\n", },
+
+{ DIV, INBREG,
+       SBREG,                  TFLOAT|TDOUBLE,
+       SBREG|SNAME|SOREG,      TFLOAT|TDOUBLE,
+               0,      RLEFT,
+               "       divsZf AR,AL\n", },
+
+{ DIV, INCREG,
+       SHFL,           TLDOUBLE,
+       SHFL,           TLDOUBLE,
+               0,      RLEFT,
+               "       fdivZAp\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TLONG,
+       SAREG|SNAME|SOREG,      TLONG,
+               NAREG|NSPECIAL, RESC1,
+               "       cqto\n  idivq AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TLL|TPOINT,
+       SAREG|SNAME|SOREG,      TULONG|TPOINT,
+               NAREG|NSPECIAL, RESC1,
+               "       xorq %rdx,%rdx\n        divq AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TSWORD,
+       SAREG|SNAME|SOREG,      TSWORD,
+               NAREG|NSPECIAL, RESC1,
+               "       cltd\n  idivl AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TWORD,
+       SAREG|SNAME|SOREG,      TUWORD,
+               NAREG|NSPECIAL, RESC1,
+               "       xorl %edx,%edx\n        divl AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TUSHORT,
+       SAREG|SNAME|SOREG,      TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       xorl %edx,%edx\n        divw AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TUCHAR,
+       SAREG|SNAME|SOREG,      TUCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       xorb %ah,%ah\n  divb AR\n       movb %ah,%al\n", },
+
+{ MUL, INAREG,
+       SAREG,                          TLL|TPOINT,
+       SAREG|SNAME|SOREG,              TLL|TPOINT,
+               0,      RLEFT,
+               "       imulq AR,AL\n", },
+
+{ MUL, INAREG,
+       SAREG,                          TWORD,
+       SAREG|SNAME|SOREG|SCON,         TWORD,
+               0,      RLEFT,
+               "       imull AR,AL\n", },
+
+{ MUL, INAREG,
+       SAREG,                  TSHORT|TUSHORT,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       imulw AR,AL\n", },
+
+{ MUL, INAREG,
+       SAREG,                  TCHAR|TUCHAR,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       imulb AR\n", },
+
+{ MUL, INBREG,
+       SBREG,                  TFLOAT|TDOUBLE,
+       SBREG|SNAME|SOREG,      TFLOAT|TDOUBLE,
+               0,      RLEFT,
+               "       mulsZf AR,AL\n", },
+
+{ MUL, INCREG,
+       SHFL,           TLDOUBLE,
+       SHFL,           TLDOUBLE,
+               0,      RLEFT,
+               "       fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SOREG,  TLL|TPOINT,
+               NAREG,  RESC1,
+               "       movq AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TWORD,
+       SOREG,  TWORD,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SOREG,  TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       movb AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SOREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       movw AL,A1\n", },
+
+{ UMUL,        INBREG,
+       SANY,   TANY,
+       SOREG,  TFLOAT|TDOUBLE,
+               NBREG|NBSL,     RESC1,
+               "       movsZf AL,A1\n", },
+
+{ UMUL,        INCREG,
+       SANY,   TANY,
+       SOREG,  TLDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       fldt AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+
+{ OPLOG,       FORCC,
+       SAREG,                  TLL|TPOINT,
+       SAREG|SOREG|SNAME,      TLL|TPOINT,
+               0,      RESCC,
+               "       cmpq AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TLL|TPOINT,
+       SAREG,                  TLL|TPOINT,
+               0,      RESCC,
+               "       cmpq AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TLL|TPOINT,
+       SCON32,                 TANY,
+               0,      RESCC,
+               "       cmpq AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TWORD,
+       SCON|SAREG,     TWORD,
+               0,      RESCC,
+               "       cmpl AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       /* SCON| XXX fix switch in tree of L/R */ SAREG,        TWORD,
+       SAREG|SOREG|SNAME,      TWORD,
+               0,      RESCC,
+               "       cmpl AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+       SCON|SAREG,     TANY,
+               0,      RESCC,
+               "       cmpw AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       SCON|SAREG,     TANY,
+               0,      RESCC,
+               "       cmpb AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SBREG,                  TDOUBLE|TFLOAT,
+       SBREG|SNAME|SOREG,      TDOUBLE|TFLOAT,
+               0,              RNOP,
+               "       ucomisZg AR,AL\nZU\n", },
+
+/* x87 */
+{ OPLOG,       FORCC,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               0,      RNOP,
+               "ZG", },
+
+{ OPLOG,       FORCC,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND, INAREG|FOREFF,
+       SAREG|SOREG|SNAME,      TLL,
+       SCON,                   TWORD,
+               0,      RLEFT,
+               "       andq AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG|SOREG|SNAME,      TLL,
+       SAREG,                  TLL,
+               0,      RLEFT,
+               "       andq AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG,                  TLL,
+       SAREG|SOREG|SNAME,      TLL,
+               0,      RLEFT,
+               "       andq AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG|SOREG|SNAME,      TWORD,
+       SCON|SAREG,             TWORD,
+               0,      RLEFT,
+               "       andl AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG,                  TWORD,
+       SAREG|SOREG|SNAME,      TWORD,
+               0,      RLEFT,
+               "       andl AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+       SCON|SAREG,             TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       andw AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+       SAREG,                  TSHORT|TUSHORT,
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       andw AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       SCON|SAREG,             TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       andb AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG,                  TCHAR|TUCHAR,
+       SAREG|SOREG|SNAME,      TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp LL\n", },
+
+#if defined(GCC_COMPAT) || defined(LANG_F77)
+{ GOTO,        FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,     FORCC|INAREG,
+       SAREG,  TLL|TPOINT,
+       SMIXOR, TANY,
+               NAREG,  RESC1,
+               "       xorq A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON,   TLL|TPOINT,
+               NAREG,  RESC1,
+               "       movabsq AL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TLL|TPOINT,
+               NAREG,  RESC1,
+               "       movq AL,A1\n", },
+
+{ OPLTYPE,     FORCC|INAREG,
+       SAREG,  TWORD,
+       SMIXOR, TANY,
+               NAREG|NASL,     RESC1,
+               "       xorl A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TWORD,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+               NAREG,  RESC1,
+               "       movb AL,A1\n", },
+
+{ OPLTYPE,     FORCC|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SMIXOR, TANY,
+               NAREG,  RESC1,
+               "       xorw A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT,
+               NAREG,  RESC1,
+               "       movw AL,A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TFLOAT|TDOUBLE,
+       SOREG|SNAME|SBREG,      TFLOAT|TDOUBLE,
+               NBREG,  RESC1,
+               "       movsZf AL,A1\n", },
+
+/* x87 entry */
+{ OPLTYPE,     INCREG,
+       SANY,           TLDOUBLE,
+       SOREG|SNAME,    TLDOUBLE,
+               NCREG,  RESC1,
+               "       fldt AL\n", },
+
+/* load float 0.0 */
+{ FCON,                INBREG,
+       SANY,           TFLOAT|TDOUBLE,
+       SANY,           TFLOAT|TDOUBLE,
+               NBREG,  RESC1,
+               "       xorpZf A1,A1\n", },
+
+{ FCON,                INCREG,
+       SANY,           TLDOUBLE,
+       SANY,           TLDOUBLE,
+               NCREG,  RESC1,
+               "       fldz\n", },
+
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TLL|TPOINT,
+       SAREG,  TLL|TPOINT,
+               0,      RLEFT,
+               "       negq AL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "       negl AL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       negw AL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       negb AL\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,          TDOUBLE|TFLOAT,
+       SBREG,          TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       xorpZf Zc(%rip),AL\n", },
+
+{ UMINUS,      INCREG,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               0,      RLEFT,
+               "       fchs\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TLL,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notq AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notl AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notw AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TCHAR|TUCHAR,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notb AL\n", },
+
+{ STARG,       FOREFF,
+       SAREG|SOREG|SNAME|SCON, TANY,
+       SANY,   TSTRUCT,
+               NSPECIAL, 0,
+               "ZF", },
+
+{ ADDROF,      INAREG,
+       SNAME,  TANY,
+       SANY,   TANY,
+               NAREG, RESC1,
+               "       leaq AL,A1\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/arm/code.c b/lang/pcc/pcc/arch/arm/code.c
new file mode 100644 (file)
index 0000000..cdd41fd
--- /dev/null
@@ -0,0 +1,897 @@
+/*      $Id: code.c,v 1.30 2016/03/09 18:19:56 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  Stuff for pass1.
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+#ifdef LANG_CXX
+#define p1listf listf
+#define p1tfree tfree
+#else
+#define NODE P1ND
+#define talloc p1alloc
+#define tcopy p1tcopy
+#define nfree p1nfree
+#endif
+
+static int rvnr;
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case UDATA: break;
+       case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break;
+       case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+       case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
+       case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *n;
+
+       n = getexname(sp);
+#ifdef USE_GAS
+       if (ISFTN(t))
+               printf("\t.type %s,%%function\n", n);
+#endif
+       if (sp->sclass == EXTDEF)
+               printf("\t.global %s\n", n);
+       if (sp->slevel == 0)
+               printf("%s:\n", n);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers
+ */
+static void
+putintemp(struct symtab *sym)
+{
+       NODE *p;
+
+       p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+       p = buildtree(ASSIGN, p, nametree(sym));
+       sym->soffset = regno(p->n_left);
+       sym->sflags |= STNODE;
+       ecomp(p);
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+       int argofs = *argofsp;
+       NODE *p, *q;
+       int navail;
+
+#if ALLONGLONG == 64
+       /* alignment */
+       ++argofs;
+       argofs &= ~1;
+       *argofsp = argofs;
+#endif
+
+       navail = NARGREGS - argofs;
+
+       if (navail < 2) {
+               /* half in and half out of the registers */
+               if (features(FEATURE_BIGENDIAN)) {
+                       cerror("param_64bit");
+                       p = q = NULL;
+               } else {
+                       q = block(REG, NIL, NIL, INT, 0, 0);
+                       regno(q) = R0 + argofs;
+                       if (dotemps) {
+                               q = block(SCONV, q, NIL,
+                                   ULONGLONG, 0, 0);
+                               p = nametree(sym);
+                               p->n_type = ULONGLONG;
+                               p->n_df = 0;
+                               p->n_ap = NULL;
+                               p = block(LS, p, bcon(32), ULONGLONG, 0, 0);
+                               q = block(PLUS, p, q, ULONGLONG, 0, 0);
+                               p = tempnode(0, ULONGLONG, 0, 0);
+                               sym->soffset = regno(p);
+                               sym->sflags |= STNODE;
+                       } else {
+                               p = nametree(sym);
+                               regno(p) = sym->soffset;
+                               p->n_type = INT;
+                               p->n_df = 0;
+                               p->n_ap = NULL;
+                       }
+               }
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+               *argofsp = argofs + 2;
+               return;
+       }
+
+       q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+       regno(q) = R0R1 + argofs;
+       if (dotemps) {
+               p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               sym->soffset = regno(p);
+               sym->sflags |= STNODE;
+       } else {
+               p = nametree(sym);
+       }
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+       *argofsp = argofs + 2;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+       NODE *p, *q;
+
+       q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+       regno(q) = R0 + (*argofsp)++;
+       if (dotemps) {
+               p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               sym->soffset = regno(p);
+               sym->sflags |= STNODE;
+       } else {
+               p = nametree(sym);
+       }
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+/* setup a double param on the stack
+ * used by bfcode() */
+static void
+param_double(struct symtab *sym, int *argofsp, int dotemps)
+{
+       NODE *p, *q, *t;
+       int tmpnr;
+
+       /*
+        * we have to dump the float from the general register
+        * into a temp, since the register allocator doesn't like
+        * floats to be in CLASSA.  This may not work for -xtemps.
+        */
+
+       t = tempnode(0, ULONGLONG, 0, 0);
+       tmpnr = regno(t);
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       q->n_rval = R0R1 + (*argofsp)++;
+       p = buildtree(ASSIGN, t, q);
+       ecomp(p);
+
+       if (dotemps) {
+               sym->soffset = tmpnr;
+               sym->sflags |= STNODE;
+       } else {
+               q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
+               p = nametree(sym);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+}
+
+/* setup a float param on the stack
+ * used by bfcode() */
+static void
+param_float(struct symtab *sym, int *argofsp, int dotemps)
+{
+       NODE *p, *q, *t;
+       int tmpnr;
+
+       /*
+        * we have to dump the float from the general register
+        * into a temp, since the register allocator doesn't like
+        * floats to be in CLASSA.  This may not work for -xtemps.
+        */
+
+       t = tempnode(0, INT, 0, 0);
+       tmpnr = regno(t);
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       q->n_rval = R0 + (*argofsp)++;
+       p = buildtree(ASSIGN, t, q);
+       ecomp(p);
+
+       if (dotemps) {
+               sym->soffset = tmpnr;
+               sym->sflags |= STNODE;
+       } else {
+               q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
+               p = nametree(sym);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retstruct(void)
+{
+       NODE *p, *q;
+
+       p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sap);
+       rvnr = regno(p);
+       q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       regno(q) = R0;
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *argofsp)
+{
+       int argofs = *argofsp;
+       NODE *p, *q;
+       int navail;
+       int sz;
+       int off;
+       int num;
+       int i;
+
+       navail = NARGREGS - argofs;
+       sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
+       off = ARGINIT/SZINT + argofs;
+       num = sz > navail ? navail : sz;
+       for (i = 0; i < num; i++) {
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               regno(q) = R0 + argofs++;
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               regno(p) = SP;
+               p = block(PLUS, p, bcon(4*off++), INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+
+       *argofsp = argofs;
+}
+
+
+/*
+ * Beginning-of-function code:
+ *
+ * 'sp' is an array of indices in symtab for the arguments
+ * 'cnt' is the number of arguments
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       union arglist *usym;
+       int saveallargs = 0;
+       int i, argofs = 0;
+
+       /*
+        * Detect if this function has ellipses and save all
+        * argument registers onto stack.
+        */
+       usym = cftnsp->sdf->dfun;
+       while (usym && usym->type != TNULL) {
+               if (usym->type == TELLIPSIS) {
+                       saveallargs = 1;
+                       break;
+               }
+               ++usym;
+       }
+
+       /* if returning a structure, move the hidden argument into a TEMP */
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               param_retstruct();
+               ++argofs;
+       }
+
+       /* recalculate the arg offset and create TEMP moves */
+       for (i = 0; i < cnt; i++) {
+
+               if (sp[i] == NULL)
+                       continue;
+
+               if ((argofs >= NARGREGS) && !xtemps)
+                       break;
+
+               if (argofs > NARGREGS) {
+                       putintemp(sp[i]);
+               } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
+                       param_struct(sp[i], &argofs);
+               } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
+                       param_64bit(sp[i], &argofs, xtemps && !saveallargs);
+               } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
+                       if (features(FEATURE_HARDFLOAT))
+                               param_double(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+                       else
+                               param_64bit(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+               } else if (sp[i]->stype == FLOAT) {
+                       if (features(FEATURE_HARDFLOAT))
+                               param_float(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+                       else
+                               param_32bit(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+               } else {
+                       param_32bit(sp[i], &argofs, xtemps && !saveallargs);
+               }
+       }
+
+       /* if saveallargs, save the rest of the args onto the stack */
+       while (saveallargs && argofs < NARGREGS) {
+               NODE *p, *q;
+               int off = ARGINIT/SZINT + argofs;
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               regno(q) = R0 + argofs++;
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               regno(p) = FPREG;
+               p = block(PLUS, p, bcon(4*off), INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+
+}
+
+/*
+ * End-of-Function code:
+ */
+void
+efcode(void)
+{
+       NODE *p, *q;
+       int tempnr;
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+
+       /*
+        * At this point, the address of the return structure on
+        * has been FORCEd to RETREG, which is R0.
+        * We want to copy the contents from there to the address
+        * we placed into the tempnode "rvnr".
+        */
+
+       /* move the pointer out of R0 to a tempnode */
+       q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       q->n_rval = R0;
+       p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
+       tempnr = regno(p);
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+
+       /* get the address from the tempnode */
+       q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sap);
+       q = buildtree(UMUL, q, NIL);
+       
+       /* now, get the structure destination */
+       p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sap);
+       p = buildtree(UMUL, p, NIL);
+
+       /* struct assignment */
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+/*
+ * End-of-job: called just before final exit.
+ */
+void
+ejobcode(int flag)
+{
+       printf("\t.ident \"PCC: %s\"\n", VERSSTR);
+}
+
+/*
+ * Beginning-of-job: called before compilation starts
+ *
+ * Initialise data structures specific for the local machine.
+ */
+void
+bjobcode(void)
+{
+}
+
+/*
+ * fix up type of field p
+ */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * Build target-dependent switch tree/table.
+ *
+ * Return 1 if successfull, otherwise return 0 and the
+ * target-independent tree will be used.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+
+/*
+ * Straighten a chain of CM ops so that the CM nodes
+ * only appear on the left node.
+ *
+ *       CM           CM
+ *     CM  CM     CM  b
+ *       x y  a b      CM  a
+ *                   x  y
+ */
+static NODE *
+straighten(NODE *p)
+{
+       NODE *r = p->n_right;
+
+       if (p->n_op != CM || r->n_op != CM)
+               return p;
+
+       p->n_right = r->n_left;
+       r->n_left = p;
+
+       return r;
+}
+
+static NODE *
+reverse1(NODE *p, NODE *a)
+{
+       NODE *l = p->n_left;
+       NODE *r = p->n_right;
+
+       a->n_right = r;
+       p->n_left = a;
+
+       if (l->n_op == CM) {
+               return reverse1(l, p);
+       } else {
+               p->n_right = l;
+               return p;
+       }
+}
+
+/*
+ * Reverse a chain of CM ops
+ */
+static NODE *
+reverse(NODE *p)
+{
+       NODE *l = p->n_left;
+       NODE *r = p->n_right;
+
+       p->n_left = r;
+
+       if (l->n_op == CM)
+               return reverse1(l, p);
+
+       p->n_right = l;
+
+       return p;
+}
+
+
+/* push arg onto the stack */
+/* called by moveargs() */
+static NODE *
+pusharg(NODE *p, int *regp)
+{
+       NODE *q;
+       int sz;
+
+       /* convert to register size, if smaller */
+       sz = tsize(p->n_type, p->n_df, p->n_ap);
+       if (sz < SZINT)
+               p = block(SCONV, p, NIL, INT, 0, 0);
+
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       regno(q) = SP;
+
+       if (szty(p->n_type) == 1) {
+               ++(*regp);
+               q = block(MINUSEQ, q, bcon(4), INT, 0, 0);
+       } else {
+               (*regp) += 2;
+               q = block(MINUSEQ, q, bcon(8), INT, 0, 0);
+       }
+
+       q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap);
+
+       return buildtree(ASSIGN, q, p);
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+       int reg = *regp;
+       NODE *q;
+
+       q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       regno(q) = reg++;
+       q = buildtree(ASSIGN, q, p);
+
+       *regp = reg;
+       return q;
+}
+
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+       int reg = *regp;
+       NODE *q, *r;
+
+#if ALLONGLONG == 64
+       /* alignment */
+       ++reg;
+       reg &= ~1;
+       *regp = reg;
+#endif
+
+       if (reg > R3) {
+               q = pusharg(p, regp);
+       } else if (reg == R3) {
+               /* half in and half out of the registers */
+               r = tcopy(p);
+               if (!features(FEATURE_BIGENDIAN)) {
+                       q = block(SCONV, p, NIL, INT, 0, 0);
+                       q = movearg_32bit(q, regp);     /* little-endian */
+                       r = buildtree(RS, r, bcon(32));
+                       r = block(SCONV, r, NIL, INT, 0, 0);
+                       r = pusharg(r, regp); /* little-endian */
+               } else {
+                       q = buildtree(RS, p, bcon(32));
+                       q = block(SCONV, q, NIL, INT, 0, 0);
+                       q = movearg_32bit(q, regp);     /* big-endian */
+                       r = block(SCONV, r, NIL, INT, 0, 0);
+                       r = pusharg(r, regp); /* big-endian */
+               }
+               q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap));
+       } else {
+               q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+               regno(q) = R0R1 + (reg - R0);
+               q = buildtree(ASSIGN, q, p);
+               *regp = reg + 2;
+       }
+
+       return q;
+}
+
+/* setup call stack with float/double argument */
+/* called from moveargs() */
+static NODE *
+movearg_float(NODE *p, int *regp)
+{
+       NODE *q, *r;
+       TWORD ty = INCREF(p->n_type);
+       int tmpnr;
+
+       /*
+        * Floats are passed in the general registers for
+        * compatibily with libraries compiled to handle soft-float.
+        */
+
+       if (xtemps) {
+               /* bounce on TOS */
+               r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
+               regno(r) = SP;
+               r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_ap);
+               r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
+               r = buildtree(ASSIGN, r, p);
+               ecomp(r);
+
+               /* bounce into temp */
+               r = block(REG, NIL, NIL, PTR+INT, 0, 0);
+               regno(r) = SP;
+               r = block(PLUS, r, bcon(-8), PTR+INT, 0, 0);
+               r = block(UMUL, r, NIL, INT, 0, 0);
+               q = tempnode(0, INT, 0, 0);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, r);
+               ecomp(r);
+       } else {
+               /* copy directly into temp */
+               q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, p);
+               ecomp(r);
+       }
+
+       /* copy from temp to register parameter */
+       r = tempnode(tmpnr, INT, 0, 0);
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       regno(q) = (*regp)++;
+       p = buildtree(ASSIGN, q, r);
+
+       return p;
+}
+
+/* setup call stack with float/double argument */
+/* called from moveargs() */
+static NODE *
+movearg_double(NODE *p, int *regp)
+{
+       NODE *q, *r;
+       TWORD ty = INCREF(p->n_type);
+       int tmpnr;
+
+       if (xtemps) {
+               /* bounce on TOS */
+               r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
+               regno(r) = SP;
+               r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap);
+               r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
+               r = buildtree(ASSIGN, r, p);
+               ecomp(r);
+
+               /* bounce into temp */
+               r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0);
+               regno(r) = SP;
+               r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0);
+               r = block(UMUL, r, NIL, LONGLONG, 0, 0);
+               q = tempnode(0, LONGLONG, 0, 0);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, r);
+               ecomp(r);
+       } else {
+               /* copy directly into temp */
+               q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, p);
+               ecomp(r);
+       }
+
+       /* copy from temp to register parameter */
+       r = tempnode(tmpnr, LONGLONG, 0, 0);
+       q = block(REG, NIL, NIL, LONGLONG, 0, 0);
+       regno(q) = R0R1 - R0 + (*regp);
+       p = buildtree(ASSIGN, q, r);
+
+       (*regp) += 2;
+
+       return p;
+}
+
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, int *regp)
+{
+       int reg = *regp;
+       NODE *l, *q, *t, *r;
+       int tmpnr;
+       int navail;
+       int num;
+       int sz;
+       int ty;
+       int i;
+
+       assert(p->n_op == STARG);
+
+       navail = NARGREGS - (reg - R0);
+       navail = navail < 0 ? 0 : navail;
+       sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
+       num = sz > navail ? navail : sz;
+
+       /* remove STARG node */
+       l = p->n_left;
+       nfree(p);
+       ty = l->n_type;
+
+       /*
+        * put it into a TEMP, rather than tcopy(), since the tree
+        * in p may have side-affects
+        */
+       t = tempnode(0, ty, l->n_df, l->n_ap);
+       tmpnr = regno(t);
+       q = buildtree(ASSIGN, t, l);
+
+       /* copy structure into registers */
+       for (i = 0; i < num; i++) {
+               t = tempnode(tmpnr, ty, 0, 0);
+               t = block(SCONV, t, NIL, PTR+INT, 0, 0);
+               t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
+               t = buildtree(UMUL, t, NIL);
+
+               r = block(REG, NIL, NIL, INT, 0, 0);
+               regno(r) = reg++;
+               r = buildtree(ASSIGN, r, t);
+
+               q = block(CM, q, r, INT, 0, 0);
+       }
+
+       /* put the rest of the structure on the stack */
+       for (i = num; i < sz; i++) {
+               t = tempnode(tmpnr, ty, 0, 0);
+               t = block(SCONV, t, NIL, PTR+INT, 0, 0);
+               t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
+               t = buildtree(UMUL, t, NIL);
+               r = pusharg(t, &reg);
+               q = block(CM, q, r, INT, 0, 0);
+       }
+
+       q = reverse(q);
+
+       *regp = reg;
+       return q;
+}
+
+
+static NODE *
+moveargs(NODE *p, int *regp)
+{
+       NODE *r, **rp;
+       int reg;
+
+       if (p->n_op == CM) {
+               p->n_left = moveargs(p->n_left, regp);
+               r = p->n_right;
+               rp = &p->n_right;
+       } else {
+               r = p;
+               rp = &p;
+       }
+
+       reg = *regp;
+
+       if (reg > R3 && r->n_op != STARG) {
+               *rp = pusharg(r, regp);
+       } else if (r->n_op == STARG) {
+               *rp = movearg_struct(r, regp);
+       } else if (DEUNSIGN(r->n_type) == LONGLONG) {
+               *rp = movearg_64bit(r, regp);
+       } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
+               *rp = movearg_double(r, regp);
+       } else if (r->n_type == FLOAT) {
+               *rp = movearg_float(r, regp);
+       } else {
+               *rp = movearg_32bit(r, regp);
+       }
+
+       return straighten(p);
+}
+
+/*
+ * Fixup arguments to pass pointer-to-struct as first argument.
+ *
+ * called from funcode().
+ */
+static NODE *
+retstruct(NODE *p)
+{
+       NODE *l, *r, *t, *q;
+       TWORD ty;
+
+       l = p->n_left;
+       r = p->n_right;
+
+       ty = DECREF(l->n_type) - FTN;
+
+//      assert(tsize(ty, l->n_df, l->n_ap) == SZINT);
+
+       /* structure assign */
+       q = tempnode(0, ty, l->n_df, l->n_ap);
+       q = buildtree(ADDROF, q, NIL);
+
+       /* insert hidden assignment at beginning of list */
+       if (r->n_op != CM) {
+               p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap);
+       } else {
+               for (t = r; t->n_left->n_op == CM; t = t->n_left)
+                       ;
+               t->n_left = block(CM, q, t->n_left, INCREF(ty),
+                           l->n_df, l->n_ap);
+       }
+
+       return p;
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       assert(0);
+       return NULL;
+}
+
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       assert(0);
+       return NULL;
+}
+
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       assert(0);
+       return NULL;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       int reg = R0;
+
+       if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) {
+               p = retstruct(p);
+               reg = R1;
+       }
+
+       p->n_right = moveargs(p->n_right, &reg);
+
+       if (p->n_right == NULL)
+               p->n_op += (UCALL - CALL);
+
+       return p;
+}
diff --git a/lang/pcc/pcc/arch/arm/local.c b/lang/pcc/pcc/arch/arm/local.c
new file mode 100644 (file)
index 0000000..18c4564
--- /dev/null
@@ -0,0 +1,696 @@
+/*      $Id: local.c,v 1.34 2016/03/09 18:19:56 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * We define location operations which operate on the expression tree
+ * during the first pass (before sending to the backend for code generation.)
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+
+#undef NIL
+#define NIL NULL
+
+#ifdef LANG_CXX
+#define p1listf listf
+#define p1tfree tfree
+#else
+#define NODE P1ND
+#define talloc p1alloc
+#define tcopy p1tcopy
+#define nfree p1nfree
+#endif
+
+extern void defalign(int);
+
+static char *
+getsoname(struct symtab *sp)
+{
+       struct attr *ap;
+       return (ap = attr_find(sp->sap, ATTR_SONAME)) ?
+           ap->sarg(0) : sp->sname;
+}
+
+
+/*
+ * clocal() is called to do local transformations on
+ * an expression tree before being sent to the backend.
+ */
+NODE *
+clocal(NODE *p)
+{
+       struct symtab *q;
+       NODE *l, *r, *t;
+       int o;
+       int ty;
+       int tmpnr, isptrvoid = 0;
+       char *n;
+
+       o = p->n_op;
+       switch (o) {
+
+       case STASG:
+
+               l = p->n_left;
+               r = p->n_right;
+               if (r->n_op != STCALL && r->n_op != USTCALL)
+                       return p;
+
+               /* assign left node as first argument to function */
+               nfree(p);
+               t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);
+               l->n_rval = R0;
+               l = buildtree(ADDROF, l, NIL);
+               l = buildtree(ASSIGN, t, l);
+
+               if (r->n_right->n_op != CM) {
+                       r->n_right = block(CM, l, r->n_right, INT, 0, 0);
+               } else {
+                       for (t = r->n_right; t->n_left->n_op == CM;
+                           t = t->n_left)
+                               ;
+                       t->n_left = block(CM, l, t->n_left, INT, 0, 0);
+               }
+               return r;
+
+       case CALL:
+       case STCALL:
+       case USTCALL:
+               if (p->n_type == VOID)
+                       break;
+               /*
+                * if the function returns void*, ecode() invokes
+                * delvoid() to convert it to uchar*.
+                * We just let this happen on the ASSIGN to the temp,
+                * and cast the pointer back to void* on access
+                * from the temp.
+                */
+               if (p->n_type == PTR+VOID)
+                       isptrvoid = 1;
+               r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               tmpnr = regno(r);
+               r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
+
+               p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+               if (isptrvoid) {
+                       p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
+               }
+               p = buildtree(COMOP, r, p);
+               break;
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p;
+               if (blevel == 0)
+                       return p;
+
+               switch (q->sclass) {
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       slval(r, 0);
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+               case REGISTER:
+                       p->n_op = REG;
+                       slval(p, 0);
+                       p->n_rval = q->soffset;
+                       break;
+               case STATIC:
+                       if (q->slevel > 0) {
+                               slval(p, 0);
+                               p->n_sp = q;
+                       }
+                       /* FALL-THROUGH */
+               default:
+                       ty = p->n_type;
+                       n = getsoname(p->n_sp);
+                       if (strncmp(n, "__builtin", 9) == 0)
+                               break;
+                       p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap);
+                       p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap);
+                       break;
+               }
+               break;
+
+       case STNAME:
+               if ((q = p->n_sp) == NULL)
+                       return p;
+               if (q->sclass != STNAME)
+                       return p;
+               ty = p->n_type;
+               p = block(ADDROF, p, NIL, INCREF(ty),
+                   p->n_df, p->n_ap);
+               p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap);
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(BOOL_TYPE) : RETREG(p->n_type);
+               break;
+
+       case SCONV:
+               l = p->n_left;
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       return l;
+               }
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       return l;
+                               }
+                       }
+               }
+
+               if (l->n_op == ICON) {
+                       CONSZ val = glval(l);
+                       CONSZ lval;
+
+                       if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
+                       switch (p->n_type) {
+                       case BOOL:
+                               slval(l, glval(l) != 0);
+                               break;
+                       case CHAR:
+                               lval = (char)val;
+                               break;
+                       case UCHAR:
+                               lval = val & 0377;
+                               break;
+                       case SHORT:
+                               lval = (short)val;
+                               break;
+                       case USHORT:
+                               lval = val & 0177777;
+                               break;
+                       case ULONG:
+                       case UNSIGNED:
+                               lval = val & 0xffffffff;
+                               break;
+                       case LONG:
+                       case INT:
+                               lval = (int)val;
+                               break;
+                       case LONGLONG:
+                               lval = (long long)val;
+                               break;
+                       case ULONGLONG:
+                               lval = val;
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               ((FLT *)l->n_dcon)->fp = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", l->n_type);
+                       }
+                       if (p->n_type < FLOAT)
+                               slval(l, lval);
+                       l->n_type = p->n_type;
+                       l->n_ap = 0;
+                       nfree(p);
+                       return l;
+               } else if (p->n_op == FCON) {
+                       slval(l, ((FLT *)l->n_dcon)->fp);
+                       l->n_sp = NULL;
+                       l->n_op = ICON;
+                       l->n_type = p->n_type;
+                       l->n_ap = 0;
+                       nfree(p);
+                       return clocal(l);
+               }
+               if ((DEUNSIGN(p->n_type) == CHAR ||
+                   DEUNSIGN(p->n_type) == SHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               break;
+
+       case PCONV:
+               l = p->n_left;
+               if (l->n_op == ICON) {
+                       slval(l, (unsigned)glval(l));
+                       goto delp;
+               }
+               if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+                       p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
+                       break;
+               }
+               if (l->n_op == SCONV)
+                       break;
+               if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+                       goto delp;
+               if (p->n_type > BTMASK && l->n_type > BTMASK)
+                       goto delp;
+               break;
+
+       delp:
+               l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_ap = p->n_ap;
+               nfree(p);
+               p = l;
+               break;
+       }
+
+       return p;
+}
+
+/*
+ * Called before sending the tree to the backend.
+ */
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+
+       if (p->n_op != FCON)
+               return;
+
+#define IALLOC(sz)     (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       slval(p, 0);
+       p->n_sp = sp;
+}
+
+/*
+ * Called during the first pass to determine if a NAME can be addressed.
+ *
+ * Return nonzero if supported, otherwise return 0.
+ */
+int
+andable(NODE *p)
+{
+       if (blevel == 0)
+               return 1;
+       if (ISFTN(p->n_type))
+               return 1;
+       return 0;
+}
+
+/*
+ * Return 1 if a variable of type 't' is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return 0; /* not yet */
+       return 1;
+}
+
+/*
+ * Allocate bits from the stack for dynamic-sized arrays.
+ *
+ * 'p' is the tree which represents the type being allocated.
+ * 'off' is the number of 'p's to be allocated.
+ * 't' is the storeable node where the address is written.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       slval(sp, 0);
+       sp->n_rval = SP;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       slval(sp, 0);
+       sp->n_rval = SP;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp));
+}
+
+/*
+ * Print an integer constant node, may be associated with a label.
+ * Do not free the node after use.
+ * 'off' is bit offset from the beginning of the aggregate
+ * 'fsz' is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; int i[2]; } u;
+       struct symtab *q;
+       TWORD t;
+       int i, j;
+
+       t = p->n_type;
+       if (t > BTMASK)
+               t = p->n_type = INT; /* pointer */
+
+       if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+               uerror("element not constant");
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+               i = (glval(p) >> 32);
+               j = (glval(p) & 0xffffffff);
+               p->n_type = INT;
+               if (features(FEATURE_BIGENDIAN)) {
+                       slval(p, i);
+                       ninval(off+32, 32, p);
+                       slval(p, j);
+                       ninval(off, 32, p);
+               } else {
+                       slval(p, j);
+                       ninval(off, 32, p);
+                       slval(p, i);
+                       ninval(off+32, 32, p);
+               }
+               break;
+       case INT:
+       case UNSIGNED:
+               printf("\t.word 0x%x", (int)glval(p));
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)) {
+                               printf("+" LABFMT, q->soffset);
+                       } else
+                               printf("+%s", getexname(q));
+               }
+               printf("\n");
+               break;
+       case LDOUBLE:
+       case DOUBLE:
+               u.d = (double)((FLT *)p->n_dcon)->fp;
+#if defined(HOST_BIG_ENDIAN)
+               if (features(FEATURE_BIGENDIAN))
+#else
+               if (!features(FEATURE_BIGENDIAN))
+#endif
+                       printf("\t.word\t0x%x\n\t.word\t0x%x\n",
+                           u.i[0], u.i[1]);
+               else
+                       printf("\t.word\t0x%x\n\t.word\t0x%x\n",
+                           u.i[1], u.i[0]);
+               break;
+       case FLOAT:
+               u.f = (float)((FLT *)p->n_dcon)->fp;
+               printf("\t.word\t0x%x\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/*
+ * Prefix a leading underscore to a global variable (if necessary).
+ */
+char *
+exname(char *p)
+{
+       return (p == NULL ? "" : p);
+}
+
+/*
+ * Map types which are not defined on the local machine.
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+               break;
+       }
+       return (type);
+}
+
+/*
+ * Before calling a function do any tree re-writing for the local machine.
+ *
+ * 'p' is the function tree (NAME)
+ * 'q' is the CM-separated list of arguments.
+ */
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+/*
+ * While handling uninitialised variables, handle variables marked extern.
+ */
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off;
+
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       printf("        .%scomm ", sp->sclass == STATIC ? "l" : "");
+       if (sp->slevel == 0)
+               printf("%s,0%o\n", getexname(sp), off);
+       else
+               printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+/*
+ * va_start(ap, last) implementation.
+ *
+ * f is the NAME node for this builtin function.
+ * a is the argument list containing:
+ *        CM
+ *     ap   last
+ */
+NODE *
+arm_builtin_stdarg_start(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q;
+       int sz = 1;
+
+       /* check num args and type */
+       if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+           !ISPTR(a->n_left->n_type))
+               goto bad;
+
+       /* must first deal with argument size; use int size */
+       p = a->n_right;
+       if (p->n_type < INT) {
+               /* round up to word */
+               sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
+       }
+
+       p = buildtree(ADDROF, p, NIL);  /* address of last arg */
+       p = optim(buildtree(PLUS, p, bcon(sz)));
+       q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+       q = buildtree(CAST, q, p);
+       p = q->n_right;
+       nfree(q->n_left);
+       nfree(q);
+       p = buildtree(ASSIGN, a->n_left, p);
+       nfree(a);
+
+       return p;
+
+bad:
+       uerror("bad argument to __builtin_stdarg_start");
+       return bcon(0);
+}
+
+NODE *
+arm_builtin_va_arg(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q, *r;
+       int sz, tmpnr;
+
+       /* check num args and type */
+       if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+           !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+               goto bad;
+
+       r = a->n_right;
+
+       /* get type size */
+       sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
+       if (sz < SZINT/SZCHAR) {
+               werror("%s%s promoted to int when passed through ...",
+                       ISUNSIGNED(r->n_type) ? "unsigned " : "",
+                       DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+               sz = SZINT/SZCHAR;
+       }
+
+       /* alignment */
+       p = tcopy(a->n_left);
+       if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
+               p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
+               p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
+       }
+
+       /* create a copy to a temp node */
+       q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+       tmpnr = regno(q);
+       p = buildtree(ASSIGN, q, p);
+
+       q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
+       q = buildtree(PLUS, q, bcon(sz));
+       q = buildtree(ASSIGN, a->n_left, q);
+
+       q = buildtree(COMOP, p, q);
+
+       nfree(a->n_right);
+       nfree(a);
+
+       p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
+       p = buildtree(UMUL, p, NIL);
+       p = buildtree(COMOP, q, p);
+
+       return p;
+
+bad:
+       uerror("bad argument to __builtin_va_arg");
+       return bcon(0);
+}
+
+NODE *
+arm_builtin_va_end(const struct bitable *bt, NODE *a)
+{
+       p1tfree(a);
+       return bcon(0);
+}
+
+NODE *
+arm_builtin_va_copy(const struct bitable *bt, NODE *a)
+{
+       NODE  *f;
+
+       if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+               goto bad;
+       f = buildtree(ASSIGN, a->n_left, a->n_right);
+       nfree(a);
+       return f;
+
+bad:
+       uerror("bad argument to __buildtin_va_copy");
+       return bcon(0);
+}
+
+char *nextsect;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       char *a2 = pragtok(NULL);
+
+       if (strcmp(str, "tls") == 0) { 
+               uerror("thread-local storage not supported for this target");
+               return 1;
+       } 
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "section") == 0 && a2 != NULL) {
+               nextsect = newstring(a2, strlen(a2));
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+               printf("\t.section .%ctors,\"aw\",@progbits\n",
+                   constructor ? 'c' : 'd');
+               printf("\t.p2align 2\n");
+               printf("\t.long %s\n", exname(sp->sname));
+               printf("\t.previous\n");
+               constructor = destructor = 0;
+       }
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/arm/local2.c b/lang/pcc/pcc/arch/arm/local2.c
new file mode 100644 (file)
index 0000000..1ada054
--- /dev/null
@@ -0,0 +1,1531 @@
+/*      $Id: local2.c,v 1.39 2016/03/09 18:19:56 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pass2.h"
+
+extern void defalign(int);
+
+#define        exname(x) x
+
+char *rnames[] = {
+       "r0", "r1", "r2", "r3","r4","r5", "r6", "r7",
+       "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc",
+       "r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6",
+       "r6r7", "r7r8", "r8r9", "r9r10",
+       "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+};
+
+/*
+ * Handling of integer constants.  We have 8 bits + an even
+ * number of rotates available as a simple immediate.
+ * If a constant isn't trivially representable, use an ldr
+ * and a subsequent sequence of orr operations.
+ */
+
+static int
+trepresent(const unsigned int val)
+{
+       int i;
+#define rotate_left(v, n) (v << n | v >> (32 - n))
+
+       for (i = 0; i < 32; i += 2)
+               if (rotate_left(val, i) <= 0xff)
+                       return 1;
+       return 0;
+}
+
+/*
+ * Return values are:
+ * 0 - output constant as is (should be covered by trepresent() above)
+ * 1 - 4 generate 1-4 instructions as needed.
+ */
+static int
+encode_constant(int constant, int *values)
+{
+       int tmp = constant;
+       int i = 0;
+       int first_bit, value;
+
+       while (tmp) {
+               first_bit = ffs(tmp);
+               first_bit -= 1; /* ffs indexes from 1, not 0 */
+               first_bit &= ~1; /* must use even bit offsets */
+
+               value = tmp & (0xff << first_bit);
+               values[i++] = value;
+               tmp &= ~value;
+       }
+       return i;
+}
+
+#if 0
+static void
+load_constant(NODE *p)
+{
+       int v = p->n_lval & 0xffffffff;
+       int reg = DECRA(p->n_reg, 1);
+
+       load_constant_into_reg(reg, v);
+}
+#endif
+
+static void
+load_constant_into_reg(int reg, int v)
+{
+       if (trepresent(v))
+               printf("\tmov %s,#%d\n", rnames[reg], v);
+       else if (trepresent(-v))
+               printf("\tmvn %s,#%d\n", rnames[reg], -v);
+       else {
+               int vals[4], nc, i;
+
+               nc = encode_constant(v, vals);
+               for (i = 0; i < nc; i++) {
+                       if (i == 0) {
+                               printf("\tmov %s,#%d" COM "load constant %d\n",
+                                   rnames[reg], vals[i], v);
+                       } else {
+                               printf("\torr %s,%s,#%d\n",     
+                                   rnames[reg], rnames[reg], vals[i]);
+                       }
+               }
+       }
+}
+
+static TWORD ftype;
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+       int addto;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("offcalc: p2maxautooff=%d\n", p2maxautooff);
+#endif
+
+       addto = p2maxautooff;
+
+#if 0
+       addto += 7;
+       addto &= ~7;
+#endif
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("offcalc: addto=%d\n", addto);
+#endif
+
+       addto -= AUTOINIT / SZCHAR;
+
+       return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+       int vals[4], nc, i;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%lx, autos=%d, tmpnum=%d, lblnum=%d\n",
+                       ipp->ipp_ip.type,
+                       ipp->ipp_ip.lineno,
+                       ipp->ipp_name,
+                       ipp->ipp_vis,
+                       ipp->ipp_type,
+                       ipp->ipp_regs[0],
+                       ipp->ipp_autos,
+                       ipp->ip_tmpnum,
+                       ipp->ip_lblnum);
+#endif
+
+       ftype = ipp->ipp_type;
+
+#if 0
+       printf("\t.align 2\n");
+       if (ipp->ipp_vis)
+               printf("\t.global %s\n", exname(ipp->ipp_name));
+       printf("\t.type %s,%%function\n", exname(ipp->ipp_name));
+#endif
+       printf("%s:\n", exname(ipp->ipp_name));
+
+       /*
+        * We here know what register to save and how much to 
+        * add to the stack.
+        */
+       addto = offcalc(ipp);
+
+       printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], 16);
+       printf("\tmov %s,%s\n", rnames[IP], rnames[SP]);
+       printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP],
+           rnames[IP], rnames[LR], rnames[PC]);
+       printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]);
+
+       if (addto == 0)
+               return;
+
+       if (trepresent(addto)) {
+               printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto);
+       } else {
+               nc = encode_constant(addto, vals);
+               for (i = 0; i < nc; i++)
+                       printf("\tsub %s,%s,#%d\n",
+                           rnames[SP], rnames[SP], vals[i]);
+       }
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       /* struct return needs special treatment */
+       if (ftype == STRTY || ftype == UNIONTY) {
+               assert(0);
+       } else {
+               printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP],
+                   rnames[SP], rnames[PC]);
+               printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], 16);
+       }
+       printf("\t.size %s,.-%s\n", exname(ipp->ipp_name),
+           exname(ipp->ipp_name));
+}
+
+
+/*
+ * these mnemonics match the order of the preprocessor decls
+ * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
+ */
+
+static char *
+ccbranches[] = {
+       "beq",          /* branch if equal */
+       "bne",          /* branch if not-equal */
+       "ble",          /* branch if less-than-or-equal */
+       "blt",          /* branch if less-than */
+       "bge",          /* branch if greater-than-or-equal */
+       "bgt",          /* branch if greater-than */
+       /* what should these be ? */
+       "bls",          /* branch if lower-than-or-same */
+       "blo",          /* branch if lower-than */
+       "bhs",          /* branch if higher-than-or-same */
+       "bhi",          /* branch if higher-than */
+};
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "orr";
+               break;
+       case ER:
+               str = "eor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int o = p->n_op;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       if (o >= ULE)
+               o -= (ULE-LE);
+       switch (o) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       expand(p, 0, "\tcmp UR,UL" COM "compare 64-bit values (upper)\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+       expand(p, 0, "\tcmp AR,AL" COM "(and lower)\n");
+       cbgen(p->n_op, e);
+       deflab(s);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       CONSZ val;
+       int shft;
+
+        if (p->n_op == ASSIGN)
+                p = p->n_left;
+
+       if (features(FEATURE_BIGENDIAN))
+               shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
+       else
+               shft = UPKFOFF(p->n_rval);
+
+        switch (**cp) {
+        case 'S':
+                printf("#%d", UPKFSZ(p->n_rval));
+                break;
+        case 'H':
+                printf("#%d", shft);
+                break;
+        case 'M':
+        case 'N':
+                val = (CONSZ)1 << UPKFSZ(p->n_rval);
+                --val;
+                val <<= shft;
+                printf("%lld", (**cp == 'M' ? val : ~val)  & 0xffffffff);
+                break;
+        default:
+                comperr("fldexpand");
+        }
+        return 1;
+}
+
+
+/*
+ * Structure assignment.
+ */
+static void
+stasg(NODE *p)
+{
+       NODE *l = p->n_left;
+       int val = getlval(l);
+
+       /* R0 = dest, R1 = src, R2 = len */
+       load_constant_into_reg(R2, attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
+       if (l->n_op == OREG) {
+               if (R2TEST(regno(l))) {
+                       int r = regno(l);
+                       printf("\tadd %s,%s,lsl #%d\n",
+                           rnames[R0], rnames[R2UPK2(r)], R2UPK3(r));
+                       printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0],
+                           rnames[R2UPK1(r)]);
+               } else  {
+                       if (trepresent(val)) {
+                               printf("\tadd %s,%s,#%d\n",
+                                   rnames[R0], rnames[regno(l)], val);
+                       } else {
+                               load_constant_into_reg(R0, val);
+                               printf("\tadd %s,%s,%s\n", rnames[R0],
+                                   rnames[R0], rnames[regno(l)]);
+                       }
+               }
+       } else if (l->n_op == NAME) {
+               cerror("not implemented");
+       }
+
+       printf("\tbl %s\n", exname("memcpy"));
+}
+
+static void
+shiftop(NODE *p)
+{
+       NODE *r = p->n_right;
+       TWORD ty = p->n_type;
+       char *shifttype;
+
+       if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) {
+               expand(p, INBREG, "\tmov A1,AL,lsr ");
+               printf(CONFMT COM "64-bit left-shift\n", 32 - getlval(r));
+               expand(p, INBREG, "\tmov U1,UL,asl AR\n");
+               expand(p, INBREG, "\torr U1,U1,A1\n");
+               expand(p, INBREG, "\tmov A1,AL,asl AR\n");
+       } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) {
+               expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n");
+               expand(p, INBREG, "\tmov U1,AL");
+               if (getlval(r) - 32 != 0)
+                       printf(",asl " CONFMT, getlval(r) - 32);
+               printf("\n");
+       } else if (p->n_op == LS && r->n_op == ICON) {
+               expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n");
+               expand(p, INBREG, "\tmov U1,#0\n");
+       } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) {
+               expand(p, INBREG, "\tmov U1,UL,asl ");
+               printf(CONFMT COM "64-bit right-shift\n", 32 - getlval(r));
+               expand(p, INBREG, "\tmov A1,AL,lsr AR\n");
+               expand(p, INBREG, "\torr A1,A1,U1\n");
+               if (ty == LONGLONG)
+                       expand(p, INBREG, "\tmov U1,UL,asr AR\n");
+               else
+                       expand(p, INBREG, "\tmov U1,UL,lsr AR\n");
+       } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) {
+               if (ty == LONGLONG) {
+                       expand(p, INBREG, "\tmvn U1,#1" COM "64-bit right-shift\n");
+                       expand(p, INBREG, "\tmov A1,UL");
+                       shifttype = "asr";
+               }else {
+                       expand(p, INBREG, "\tmov U1,#0" COM "64-bit right-shift\n");
+                       expand(p, INBREG, "\tmov A1,UL");
+                       shifttype = "lsr";
+               }
+               if (getlval(r) - 32 != 0)
+                       printf(",%s " CONFMT, shifttype, getlval(r) - 32);
+               printf("\n");
+       } else if (p->n_op == RS && r->n_op == ICON) {
+               expand(p, INBREG, "\tmov A1,#0" COM "64-bit right-shift\n");
+               expand(p, INBREG, "\tmov U1,#0\n");
+       }
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
+ */
+static void
+fpemul(NODE *p)
+{
+       NODE *l = p->n_left;
+       char *ch = NULL;
+
+       if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+       else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+       else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "adddf3";
+
+       else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+       else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+       else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subdf3";
+
+       else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+       else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+       else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "muldf3";
+
+       else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+       else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+       else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divdf3";
+
+       else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+       else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+       else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negdf2";
+
+       else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+       else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+       else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqdf2";
+
+       else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+       else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+       else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "nedf2";
+
+       else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+       else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+       else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "gedf2";
+
+       else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+       else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+       else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "ledf2";
+
+       else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+       else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+       else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gtdf2";
+
+       else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+       else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+       else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "ltdf2";
+
+       else if (p->n_op == SCONV && p->n_type == FLOAT) {
+               if (l->n_type == DOUBLE) ch = "truncdfsf2";
+               else if (l->n_type == LDOUBLE) ch = "truncdfsf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdisf";
+               else if (l->n_type == LONGLONG) ch = "floatdisf";
+               else if (l->n_type == LONG) ch = "floatsisf";
+               else if (l->n_type == ULONG) ch = "floatunsisf";
+               else if (l->n_type == INT) ch = "floatsisf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+       } else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+               if (l->n_type == FLOAT) ch = "extendsfdf2";
+               else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+               else if (l->n_type == LONGLONG) ch = "floatdidf";
+               else if (l->n_type == LONG) ch = "floatsidf";
+               else if (l->n_type == ULONG) ch = "floatunsidf";
+               else if (l->n_type == INT) ch = "floatsidf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+       } else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+               if (l->n_type == FLOAT) ch = "extendsfdf2";
+               else if (l->n_type == DOUBLE) ch = "extenddftd2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+               else if (l->n_type == LONGLONG) ch = "floatdidf";
+               else if (l->n_type == LONG) ch = "floatsidf";
+               else if (l->n_type == ULONG) ch = "floatunsidf";
+               else if (l->n_type == INT) ch = "floatsidf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+       } else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+               if (l->n_type == FLOAT) ch = "fixunssfdi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+       } else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+               if (l->n_type == FLOAT) ch = "fixsfdi";
+               else if (l->n_type == DOUBLE) ch = "fixdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+       } else if (p->n_op == SCONV && p->n_type == LONG) {
+               if (l->n_type == FLOAT) ch = "fixsfsi";
+               else if (l->n_type == DOUBLE) ch = "fixdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+       } else if (p->n_op == SCONV && p->n_type == ULONG) {
+               if (l->n_type == FLOAT) ch = "fixunssfdi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+       } else if (p->n_op == SCONV && p->n_type == INT) {
+               if (l->n_type == FLOAT) ch = "fixsfsi";
+               else if (l->n_type == DOUBLE) ch = "fixdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+       } else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+               if (l->n_type == FLOAT) ch = "fixunssfsi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+       }
+
+       if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+       printf("\tbl __%s" COM "softfloat operation\n", exname(ch));
+
+       if (p->n_op >= EQ && p->n_op <= GT)
+               printf("\tcmp %s,#0\n", rnames[R0]);
+}
+
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+
+static void
+emul(NODE *p)
+{
+       char *ch = NULL;
+
+       if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+       else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashlsi3";
+       else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3";
+
+       else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+       else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrsi3";
+       else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3";
+
+       else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+       else if (p->n_op == RS && p->n_type == LONG) ch = "ashrsi3";
+       else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3";
+       
+       else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+       else if (p->n_op == DIV && p->n_type == LONG) ch = "divsi3";
+       else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3";
+
+       else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+       else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivsi3";
+       else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3";
+
+       else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+       else if (p->n_op == MOD && p->n_type == LONG) ch = "modsi3";
+       else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3";
+
+       else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+       else if (p->n_op == MOD && p->n_type == ULONG) ch = "umodsi3";
+       else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3";
+
+       else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+       else if (p->n_op == MUL && p->n_type == LONG) ch = "mulsi3";
+       else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3";
+
+       else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+       else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
+       else if (p->n_op == UMINUS && p->n_type == INT) ch = "negsi2";
+
+       else ch = 0, comperr("ZE");
+       printf("\tbl __%s" COM "emulated operation\n", exname(ch));
+}
+
+static void
+halfword(NODE *p)
+{
+        NODE *r = getlr(p, 'R');
+        NODE *l = getlr(p, 'L');
+       int idx0 = 0, idx1 = 1;
+       CONSZ lval;
+
+       if (features(FEATURE_BIGENDIAN)) {
+               idx0 = 1;
+               idx1 = 0;
+       }
+
+       if (p->n_op == ASSIGN && r->n_op == OREG) {
+                /* load */
+               lval = getlval(r);
+                expand(p, 0, "\tldrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[r->n_rval], lval+idx0);
+                expand(p, 0, "\tldrb AL,");
+                printf("[%s," CONFMT "]\n", rnames[r->n_rval], lval+idx1);
+                expand(p, 0, "\torr AL,A1,AL,asl #8\n");
+        } else if (p->n_op == ASSIGN && l->n_op == OREG) {
+                /* store */
+               lval = getlval(l);
+                expand(p, 0, "\tstrb AR,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx0);
+                expand(p, 0, "\tmov A1,AR,asr #8\n");
+                expand(p, 0, "\tstrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx1);
+        } else if (p->n_op == SCONV || p->n_op == UMUL) {
+                /* load */
+               lval = getlval(l);
+                expand(p, 0, "\tldrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx0);
+                expand(p, 0, "\tldrb A2,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx1);
+                expand(p, 0, "\torr A1,A1,A2,asl #8\n");
+        } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) {
+                /* load */
+               lval = getlval(p);
+                expand(p, 0, "\tldrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[p->n_rval], lval+idx0);
+                expand(p, 0, "\tldrb A2,");
+                printf("[%s," CONFMT "]\n", rnames[p->n_rval], lval+idx1);
+                expand(p, 0, "\torr A1,A1,A2,asl #8\n");
+       } else {
+               comperr("halfword");
+        }
+}
+
+static void
+bfext(NODE *p)
+{
+        int sz;
+
+        if (ISUNSIGNED(p->n_right->n_type))
+                return;
+        sz = 32 - UPKFSZ(p->n_left->n_rval);
+
+       expand(p, 0, "\tmov AD,AD,asl ");
+        printf("#%d\n", sz);
+       expand(p, 0, "\tmov AD,AD,asr ");
+        printf("#%d\n", sz);
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (t < LONGLONG || t == FLOAT || t > BTMASK)
+               return 4;
+       if (t == LONGLONG || t == ULONGLONG)
+               return 8;
+       if (t == DOUBLE || t == LDOUBLE)
+               return 8;
+       if (t == STRTY || t == UNIONTY)
+               return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       comperr("argsiz");
+       return 0;
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       int pr;
+
+       switch (c) {
+
+       case 'B': /* bit-field sign extension */
+               bfext(p);
+               break;
+
+       case 'C':  /* remove from stack after subroutine call */
+               pr = p->n_qual;
+#if 0
+               if (p->n_op == STCALL || p->n_op == USTCALL)
+                       pr += 4;
+#endif
+               if (p->n_op == UCALL)
+                       return; /* XXX remove ZC from UCALL */
+               if (pr > 0)
+                       printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr);
+               break;
+
+       case 'D': /* Long long comparision */
+               twollcomp(p);
+               break;
+
+       case 'E': /* print out emulated ops */
+               emul(p);
+                break;
+
+       case 'F': /* print out emulated floating-point ops */
+               fpemul(p);
+               break;
+
+       case 'H':               /* do halfword access */
+               halfword(p);
+               break;
+
+       case 'I':               /* init constant */
+               if (p->n_name[0] != '\0')
+                       comperr("named init");
+               load_constant_into_reg(DECRA(p->n_reg, 1),
+                   getlval(p) & 0xffffffff);
+               break;
+
+       case 'J':               /* init longlong constant */
+               load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1,
+                   getlval(p) & 0xffffffff);
+               load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1 + 1,
+                    (getlval(p) >> 32));
+                break;
+
+       case 'O': /* 64-bit left and right shift operators */
+               shiftop(p);
+               break;
+
+       case 'Q': /* emit struct assign */
+               stasg(p);
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o == OREG || o == REG || o == NAME)
+               return SRDIR; /* Direct match */
+       if (o == UMUL && shumul(p->n_left, SOREG))
+               return SROREG; /* Convert into oreg */
+       return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       char *s;
+       int val = getlval(p);
+
+       switch (p->n_op) {
+       case ICON:
+#if 0
+               if (p->n_sp)
+                       printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel);
+#endif
+#ifdef notdef  /* ICON cannot ever use sp here */
+               /* If it does, it's a giant bug */
+               if (p->n_sp == NULL || (
+                  (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0)))
+                       s = p->n_name;
+               else
+                       s = exname(p->n_name);
+#else
+               s = p->n_name;
+#endif
+                       
+               if (*s != '\0') {
+                       fprintf(fp, "%s", s);
+                       if (val > 0)
+                               fprintf(fp, "+%d", val);
+                       else if (val < 0)
+                               fprintf(fp, "-%d", -val);
+               } else
+                       fprintf(fp, CONFMT, (CONSZ)val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%s", rnames[p->n_rval-R0R1+1]);
+               break;
+
+       case NAME:
+       case OREG:
+               setlval(p, getlval(p) + size);
+               adrput(stdout, p);
+               setlval(p, getlval(p) - size);
+               break;
+       case ICON:
+               printf(CONFMT, getlval(p) >> 32);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       int r;
+       /* output an address, with offsets, from p */
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       fputs(p->n_name, io);
+                       if (getlval(p) != 0)
+                               fprintf(io, "+%lld", getlval(p));
+               } else
+                       fprintf(io, CONFMT, getlval(p));
+               return;
+
+       case OREG:
+               r = p->n_rval;
+                if (R2TEST(r))
+                       fprintf(io, "[%s, %s, lsl #%d]",
+                               rnames[R2UPK1(r)],
+                               rnames[R2UPK2(r)],
+                               R2UPK3(r));
+               else
+                       fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)getlval(p));
+               return;
+
+       case ICON:
+               /* addressable value of the constant */
+               conput(io, p);
+               return;
+
+       case REG:
+               switch (p->n_type) {
+               case DOUBLE:
+               case LDOUBLE:
+                       if (features(FEATURE_HARDFLOAT)) {
+                               fprintf(io, "%s", rnames[p->n_rval]);
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case LONGLONG:
+               case ULONGLONG:
+                       fprintf(io, "%s", rnames[p->n_rval-R0R1]);
+                       break;
+               default:
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               }
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("\t%s " LABFMT COM "conditional branch\n",
+           ccbranches[o-EQ], lab);
+}
+
+/*
+ * The arm can only address 4k to get a NAME, so there must be some
+ * rewriting here.  Strategy:
+ * For first 1000 nodes found, print out the word directly.
+ * For the following 1000 nodes, group them together in asm statements
+ * and create a jump over.
+ * For the last <1000 statements, print out the words last.
+ */
+struct addrsymb {
+       SLIST_ENTRY(addrsymb) link;
+       char *name;     /* symbol name */
+       int num;        /* symbol offset */
+       char *str;      /* replace label */
+};
+SLIST_HEAD(, addrsymb) aslist;
+static struct interpass *ipbase;
+static int prtnumber, nodcnt, notfirst;
+#define        PRTLAB  ".LY%d" /* special for here */
+
+static struct interpass *
+anode(char *p)
+{
+       extern int thisline;
+       struct interpass *ip = tmpalloc(sizeof(struct interpass));
+
+       ip->ip_asm = p;
+       ip->type = IP_ASM;
+       ip->lineno = thisline;
+       return ip;
+}
+
+static void
+flshlab(void)
+{
+       struct interpass *ip;
+       struct addrsymb *el;
+       int lab = prtnumber++;
+       char *c;
+
+       if (SLIST_FIRST(&aslist) == NULL)
+               return;
+
+       snprintf(c = tmpalloc(32), 32, "\tb " PRTLAB "\n", lab);
+       ip = anode(c);
+       DLIST_INSERT_BEFORE(ipbase, ip, qelem);
+
+       SLIST_FOREACH(el, &aslist, link) {
+               /* insert each node as asm */
+               int l = 32+strlen(el->name);
+               c = tmpalloc(l);
+               if (el->num)
+                       snprintf(c, l, "%s:\n\t.word %s+%d\n",
+                           el->str, el->name, el->num);
+               else
+                       snprintf(c, l, "%s:\n\t.word %s\n", el->str, el->name);
+               ip = anode(c);
+               DLIST_INSERT_BEFORE(ipbase, ip, qelem);
+       }
+       /* generate asm label */
+       snprintf(c = tmpalloc(32), 32, PRTLAB ":\n", lab);
+       ip = anode(c);
+       DLIST_INSERT_BEFORE(ipbase, ip, qelem);
+}
+
+static void
+prtaddr(NODE *p, void *arg)
+{
+       NODE *l = p->n_left;
+       struct addrsymb *el;
+       int found = 0;
+       int lab;
+
+       nodcnt++;
+
+       if (p->n_op == ASSIGN && p->n_right->n_op == ICON &&
+           p->n_right->n_name[0] != '\0') {
+               /* named constant */
+               p = p->n_right;
+
+               /* Restore addrof */
+               l = mklnode(NAME, getlval(p), 0, 0);
+               l->n_name = p->n_name;
+               p->n_left = l;
+               p->n_op = ADDROF;
+       }
+
+       if (p->n_op != ADDROF || l->n_op != NAME)
+               return;
+
+       /* if we passed 1k nodes printout list */
+       if (nodcnt > 1000) {
+               if (notfirst)
+                       flshlab();
+               SLIST_INIT(&aslist);
+               notfirst = 1;
+               nodcnt = 0;
+       }
+
+       /* write address to byte stream */
+
+       SLIST_FOREACH(el, &aslist, link) {
+               if (el->num == getlval(l) && el->name[0] == l->n_name[0] &&
+                   strcmp(el->name, l->n_name) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               /* we know that this is text segment */
+               lab = prtnumber++;
+               if (nodcnt <= 1000 && notfirst == 0) {
+                       if (getlval(l))
+                               printf(PRTLAB ":\n\t.word %s+%lld\n",
+                                   lab, l->n_name, getlval(l));
+                       else
+                               printf(PRTLAB ":\n\t.word %s\n",
+                                   lab, l->n_name);
+               }
+               el = tmpalloc(sizeof(struct addrsymb));
+               el->num = getlval(l);
+               el->name = l->n_name;
+               el->str = tmpalloc(32);
+               snprintf(el->str, 32, PRTLAB, lab);
+               SLIST_INSERT_LAST(&aslist, el, link);
+       }
+
+       nfree(l);
+       p->n_op = NAME;
+       setlval(p, 0);
+       p->n_name = el->str;
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       SLIST_INIT(&aslist);
+       notfirst = nodcnt = 0;
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               switch (ip->type) {
+               case IP_NODE:
+                       lineno = ip->lineno;
+                       ipbase = ip;
+                       walkf(ip->ip_node, prtaddr, 0);
+                       break;
+               case IP_EPILOG:
+                       ipbase = ip;
+                       if (notfirst)
+                               flshlab();
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR+SHORT) || p->n_type == (PTR+USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ipp)
+{
+}
+
+/*
+ * Register move: move contents of register 's' to register 'r'.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+        switch (t) {
+       case DOUBLE:
+       case LDOUBLE:
+               if (features(FEATURE_HARDFLOAT)) {
+                       printf("\tfmr %s,%s" COM "rmove\n",
+                               rnames[d], rnames[s]);
+                       break;
+               }
+               /* FALLTHROUGH */
+        case LONGLONG:
+        case ULONGLONG:
+#define LONGREG(x, y) rnames[(x)-(R0R1-(y))]
+                if (s == d+1) {
+                        /* dh = sl, copy low word first */
+                        printf("\tmov %s,%s" COM "rmove\n",
+                           LONGREG(d,0), LONGREG(s,0));
+                        printf("\tmov %s,%s\n",
+                           LONGREG(d,1), LONGREG(s,1));
+                } else {
+                        /* copy high word first */
+                        printf("\tmov %s,%s" COM "rmove\n",
+                           LONGREG(d,1), LONGREG(s,1));
+                        printf("\tmov %s,%s\n",
+                           LONGREG(d,0), LONGREG(s,0));
+                }
+#undef LONGREG
+                break;
+       case FLOAT:
+               if (features(FEATURE_HARDFLOAT)) {
+                       printf("\tmr %s,%s" COM "rmove\n",
+                               rnames[d], rnames[s]);
+                       break;
+               }
+               /* FALLTHROUGH */
+        default:
+               printf("\tmov %s,%s" COM "rmove\n", rnames[d], rnames[s]);
+        }
+}
+
+/*
+ * Can we assign a register from class 'c', given the set
+ * of number of assigned registers in each class 'r'.
+ *
+ * On ARM, we have:
+ *     11  CLASSA registers (32-bit hard registers)
+ *     10  CLASSB registers (64-bit composite registers)
+ *     8 or 32 CLASSC registers (floating-point)
+ *
+ *  There is a problem calculating the available composite registers
+ *  (ie CLASSB).  The algorithm below assumes that given any two
+ *  registers, we can make a composite register.  But this isn't true
+ *  here (or with other targets), since the number of combinations
+ *  of register pairs could become very large.  Additionally,
+ *  having so many combinations really isn't so practical, since
+ *  most register pairs cannot be used to pass function arguments.
+ *  Consequently, when there is pressure composite registers,
+ *  "beenhere" compilation failures are common.
+ *
+ *  [We need to know which registers are allocated, not simply
+ *  the number in each class]
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num = 0;    /* number of registers used */
+
+#if 0
+       static const char classes[] = { 'X', 'A', 'B', 'C', 'D' };
+       printf("COLORMAP: requested class %c\n", classes[c]);
+       printf("COLORMAP: class A: %d\n", r[CLASSA]);
+       printf("COLORMAP: class B: %d\n", r[CLASSB]);
+#endif
+
+       switch (c) {
+       case CLASSA:
+               num += r[CLASSA];
+               num += 2*r[CLASSB];
+               return num < 11;
+       case CLASSB:
+               num += 2*r[CLASSB];
+               num += r[CLASSA];
+               return num < 6;  /* XXX see comments above */
+       case CLASSC:
+               num += r[CLASSC];
+               if (features(FEATURE_FPA))
+                       return num < 8;
+               else if (features(FEATURE_VFP))
+                       return num < 8;
+               else
+                       cerror("colormap 1");
+       }
+       cerror("colormap 2");
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == DOUBLE || t == LDOUBLE) {
+               if (features(FEATURE_HARDFLOAT))
+                       return CLASSC;
+               else
+                       return CLASSB;
+       }
+       if (t == FLOAT) {
+               if (features(FEATURE_HARDFLOAT))
+                       return CLASSC;
+               else
+                       return CLASSA;
+       }
+       if (DEUNSIGN(t) == LONGLONG)
+               return CLASSB;
+       return CLASSA;
+}
+
+int
+retreg(int t)
+{
+       int c = gclass(t);
+       if (c == CLASSB)
+               return R0R1;
+       else if (c == CLASSC)
+               return F0;
+       return R0;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               size += argsiz(p->n_right);
+       size += argsiz(p);
+       op->n_qual = size - 16; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       return SRNOPE;
+}
+
+/*
+ * default to ARMv2
+ */
+#ifdef TARGET_BIG_ENDIAN
+#define DEFAULT_FEATURES       FEATURE_BIGENDIAN | FEATURE_MUL
+#else
+#define DEFAULT_FEATURES       FEATURE_MUL
+#endif
+
+static int fset = DEFAULT_FEATURES;
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+       if (strcasecmp(str, "little-endian") == 0) {
+               fset &= ~FEATURE_BIGENDIAN;
+       } else if (strcasecmp(str, "big-endian") == 0) {
+               fset |= FEATURE_BIGENDIAN;
+       } else if (strcasecmp(str, "fpe=fpa") == 0) {
+               fset &= ~(FEATURE_VFP | FEATURE_FPA);
+               fset |= FEATURE_FPA;
+       } else if (strcasecmp(str, "fpe=vfp") == 0) {
+               fset &= ~(FEATURE_VFP | FEATURE_FPA);
+               fset |= FEATURE_VFP;
+       } else if (strcasecmp(str, "fpe=vfpv3-d16") == 0) {
+               fset &= ~(FEATURE_VFP | FEATURE_FPA);
+               fset |= FEATURE_VFP;
+       } else if (strcasecmp(str, "soft-float") == 0) {
+               fset &= ~(FEATURE_VFP | FEATURE_FPA);
+       } else if (strcasecmp(str, "arch=armv1") == 0) {
+               fset &= ~FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset &= ~FEATURE_MUL;
+               fset &= ~FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv2") == 0) {
+               fset &= ~FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset &= ~FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv2a") == 0) {
+               fset &= ~FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset &= ~FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv3") == 0) {
+               fset &= ~FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset &= ~FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv4") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv4t") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv4tej") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv5") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv5te") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv5tej") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset &= ~FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv6") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv6t2") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv6kz") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv6k") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv7") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset |= FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv7-m") == 0 || strcasecmp(str, "arch=armv7e-m") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset |= FEATURE_DIV;
+       } else if (strcasecmp(str, "arch=armv7-a") == 0) {
+               fset |= FEATURE_HALFWORDS;
+               fset |= FEATURE_EXTEND;
+               fset |= FEATURE_MUL;
+               fset |= FEATURE_MULL;
+               fset &= ~FEATURE_DIV;
+       } else {
+               fprintf(stderr, "unknown m option '%s'\n", str);
+               exit(1);
+       }
+}
+
+int
+features(int mask)
+{
+       if (mask == FEATURE_HARDFLOAT)
+               return ((fset & mask) != 0);
+       return ((fset & mask) == mask);
+}
+
+/*
+ * Define the current location as an internal label.
+ */
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/arm/macdefs.h b/lang/pcc/pcc/arch/arm/macdefs.h
new file mode 100644 (file)
index 0000000..fbf8e64
--- /dev/null
@@ -0,0 +1,269 @@
+/*     $Id: macdefs.h,v 1.19 2016/03/09 18:19:56 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         32
+#define SZINT          32
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      64
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         32
+#define ALINT          32
+#define ALFLOAT                32
+#define ALDOUBLE       32
+#define ALLDOUBLE      32
+#define ALLONG         32
+#define ALLONGLONG     32
+#define ALSHORT                16
+#define ALPOINT                32
+#define ALSTRUCT       32
+#define ALSTACK                32 
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         -1
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffff
+#define        MIN_LONG        MIN_INT
+#define        MAX_LONG        MAX_INT
+#define        MAX_ULONG       MAX_UNSIGNED
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+#define        BOOL_TYPE       INT     /* what used to store _Bool */
+
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "#%lld"         /* format for printing constants */
+#define LABFMT ".L%d"          /* format for printing labels */
+#define        STABLBL "LL%d"          /* format for stab (debugging) labels */
+#define STAB_LINE_ABSOLUTE     /* S_LINE fields use absolute addresses */
+
+#undef FIELDOPS                /* no bit-field instructions */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+
+#define        szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \
+       (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+#define R0     0
+#define R1     1
+#define R2     2
+#define R3     3
+#define R4     4
+#define R5     5
+#define R6     6
+#define R7     7
+#define R8     8
+#define R9     9
+#define R10    10
+#define R11    11
+#define R12    12
+#define        R13     13
+#define R14    14
+#define R15    15
+
+#define SL     R10
+#define FP     R11
+#define IP     R12
+#define SP     R13
+#define LR     R14
+#define PC     R15
+
+#define R0R1   16
+#define R1R2   17
+#define R2R3   18
+#define R3R4   19
+#define R4R5   20
+#define R5R6   21
+#define R6R7   22
+#define R7R8   23
+#define R8R9   24
+#define R9R10  25
+
+#define F0     26
+#define F1     27
+#define F2     28
+#define F3     29
+#define F4     30
+#define F5     31
+#define F6     32
+#define F7     33
+
+#define NUMCLASS 3
+#define        MAXREGS 34
+
+#define RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,                    \
+       0, 0, 0, 0, 0,                                                  \
+        SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG,            \
+        SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,                      \
+       SCREG, SCREG, SCREG, SCREG,                                     \
+       SCREG, SCREG, SCREG, SCREG,                                     \
+
+#define ROVERLAP \
+       { R0R1, -1 },                                   \
+       { R0R1, R1R2, -1 },                             \
+       { R1R2, R2R3, -1 },                             \
+       { R2R3, R3R4, -1 },                             \
+       { R3R4, R4R5, -1 },                             \
+       { R4R5, R5R6, -1 },                             \
+       { R5R6, R6R7, -1 },                             \
+       { R6R7, R7R8, -1 },                             \
+       { R7R8, R8R9, -1 },                             \
+       { R8R9, R9R10, -1 },                            \
+       { R9R10, -1 },                                  \
+       { -1 },                                         \
+       { -1 },                                         \
+       { -1 },                                         \
+       { -1 },                                         \
+       { -1 },                                         \
+       { R0, R1, R1R2, -1 },                           \
+       { R1, R2, R0R1, R2R3, -1 },                     \
+       { R2, R3, R1R2, R3R4, -1 },                     \
+       { R3, R4, R2R3, R4R5, -1 },                     \
+       { R4, R5, R3R4, R5R6, -1 },                     \
+       { R5, R6, R4R5, R6R7, -1 },                     \
+       { R6, R7, R5R6, R7R8, -1 },                     \
+       { R7, R8, R6R7, R8R9, -1 },                     \
+       { R8, R9, R7R8, R9R10, -1 },                    \
+       { R9, R10, R8R9, -1 },                          \
+       { -1, },                                        \
+       { -1, },                                        \
+       { -1, },                                        \
+       { -1, },                                        \
+       { -1, },                                        \
+       { -1, },                                        \
+       { -1, },                                        \
+       { -1, },                                        \
+
+#define BACKTEMP               /* stack grows negatively for temporaries */
+#define BACKAUTO               /* stack grows negatively for automatics */
+
+#define ARGINIT                (4*8)   /* # bits above fp where arguments start */
+#define AUTOINIT       (12*8)  /* # bits above fp where automatics start */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_LE
+
+/* XXX - to die */
+#define FPREG   FP     /* frame pointer */
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p)      (1 << gclass((p)->n_type))
+
+#define GCLASS(x)      (x < 16 ? CLASSA : x < 26 ? CLASSB : CLASSC)
+#define DECRA(x,y)      (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)       ((x) << 6)      /* A1 */
+#define ENCRA2(x)       ((x) << 12)     /* A2 */
+#define ENCRA(x,y)      ((x) << (6+y*6))        /* encode regs in int */
+#define RETREG(x)      retreg(x)
+
+int COLORMAP(int c, int *r);
+int retreg(int ty);
+int features(int f);
+
+#define FEATURE_BIGENDIAN      0x00010000
+#define FEATURE_HALFWORDS      0x00020000      /* ldrsh/ldrh, ldrsb */
+#define FEATURE_EXTEND         0x00040000      /* sxth, sxtb, uxth, uxtb */
+#define FEATURE_MUL            0x00080000
+#define FEATURE_MULL           0x00100000
+#define FEATURE_DIV            0x00200000
+#define FEATURE_FPA            0x10000000
+#define FEATURE_VFP            0x20000000
+#define FEATURE_HARDFLOAT      (FEATURE_FPA|FEATURE_VFP)
+
+#if 0
+#define TARGET_STDARGS
+#define TARGET_BUILTINS                                                \
+       { "__builtin_stdarg_start", arm_builtin_stdarg_start }, \
+       { "__builtin_va_arg", arm_builtin_va_arg },             \
+       { "__builtin_va_end", arm_builtin_va_end },             \
+       { "__builtin_va_copy", arm_builtin_va_copy },
+#endif
+
+#undef NODE
+#ifdef LANG_CXX
+#define NODE struct node
+#else
+#define NODE struct p1node
+#endif
+struct node;
+struct bitable;
+NODE *arm_builtin_stdarg_start(const struct bitable *bt, NODE *a);
+NODE *arm_builtin_va_arg(const struct bitable *bt, NODE *a);
+NODE *arm_builtin_va_end(const struct bitable *bt, NODE *a);
+NODE *arm_builtin_va_copy(const struct bitable *bt, NODE *a);
+#undef NODE
+
+#define COM     "\t@ "
+#define NARGREGS       4
diff --git a/lang/pcc/pcc/arch/arm/order.c b/lang/pcc/pcc/arch/arm/order.c
new file mode 100644 (file)
index 0000000..1d42ebd
--- /dev/null
@@ -0,0 +1,339 @@
+/*      $Id: order.c,v 1.10 2016/03/09 18:19:56 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  Machine-dependent code-generation strategy (pass 2).
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "pass2.h"
+
+/*
+ * Check size of offset in OREG.  Called by oregok() to see if an
+ * OREG can be generated.
+ */
+int
+notoff(TWORD ty, int r, CONSZ off, char *cp)
+{
+       if (cp && cp[0]) return 1;
+       if (DEUNSIGN(ty) == INT || ty == UCHAR)
+               return !(off < 4096 && off > -4096);
+       else
+               return !(off < 256 && off > -256);
+}
+
+/*
+ * Generate instructions for an OREG.  Why is this routine MD?
+ * Called by swmatch().
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *r;
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+       r = p->n_right;
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( r->n_op == ICON ){
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+               /* usually for arraying indexing: */
+               if (r->n_op == LS && r->n_right->n_op == ICON &&
+                   getlval(r->n_right) == 2 && p->n_op == PLUS) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       if (isreg(r->n_left) == 0)
+                               (void)geninsn(r->n_left, INAREG);
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Unable to convert to OREG (notoff() returned failure).  Output
+ * suitable instructions to replace OREG.
+ */
+void
+myormake(NODE *q)
+{
+        NODE *p, *r;
+
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+
+       p = q->n_left;
+
+       /*
+        * This handles failed OREGs conversions, due to the offset
+        * being too large for an OREG.
+        */
+       if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) {
+               if (isreg(p->n_left) == 0)
+                       (void)geninsn(p->n_left, INAREG);
+               if (isreg(p->n_right) == 0)
+                       (void)geninsn(p->n_right, INAREG);
+               (void)geninsn(p, INAREG);
+       } else if (p->n_op == REG) {
+               q->n_op = OREG;
+               setlval(q, getlval(p));
+               q->n_rval = p->n_rval;
+               tfree(p);
+       } else if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
+           r->n_right->n_op == ICON && getlval(r->n_right) == 2 &&
+           p->n_left->n_op == REG && r->n_left->n_op == REG) {
+               q->n_op = OREG;
+               setlval(q, 0);
+               q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval,
+                                  getlval(r->n_right));
+               tfree(p);
+       }
+}
+
+/*
+ * Check to if the UMUL node can be converted into an OREG.
+ */
+int
+shumul(NODE *p, int shape)
+{
+       /* Turns currently anything into OREG */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setbin(NODE *p)
+{
+       return 0;
+
+}
+
+/*
+ * Rewrite assignment operations.
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setasg(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Rewrite UMUL operation.
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ *
+ * Called as a result of specifying NSPECIAL in the table.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+
+       switch (q->op) {
+
+#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP)
+       case UMINUS:
+       case SCONV:
+               if (q->lshape == SBREG && q->rshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0R1 },
+                               { NRES, R0 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG && q->rshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0 },
+                               { NRES, R0R1 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG && q->rshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0 },
+                               { NRES, R0 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SBREG && q->rshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0R1 },
+                               { NRES, R0R1 },
+                               { 0 }
+                       };
+                       return s;
+               }
+
+       case OPLOG:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0R1 },
+                               { NRIGHT, R2R3 },
+                               { NRES, R0 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0 },
+                               { NRIGHT, R1 },
+                               { NRES, R0 },
+                               { 0 }
+                       };
+                       return s;
+               }
+       case PLUS:
+       case MINUS:
+       case MUL:
+#endif
+       case MOD:
+       case DIV:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0R1 },
+                               { NRIGHT, R2R3 },
+                               { NRES, R0R1 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0 },
+                               { NRIGHT, R1 },
+                               { NRES, R0 },
+                               { 0 }
+                       };
+                       return s;
+               }
+       case LS:
+       case RS:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0R1 },
+                               { NRIGHT, R2 },
+                               { NRES, R0R1 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R0 },
+                               { NRIGHT, R1 },
+                               { NRES, R0 },
+                               { 0 }
+                       };
+                       return s;
+               }
+       case STASG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, R0 },
+                               { NRIGHT, R1 },
+                               { NEVER, R2 },
+                               { 0 } };
+                       return s;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+#ifdef PCC_DEBUG
+       comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring);
+#endif
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node ('+','-', '*', '/', etc) if it
+ * differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0;
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+        static int r[] = { R3, R2, R1, R0, -1 };
+       int num = 1;
+
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return &r[4-0];
+
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+                num += szty(p->n_right->n_type);
+        num += szty(p->n_right->n_type);
+
+       num = (num > 4 ? 4 : num);
+
+        return &r[4 - num];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return features(op->visit & 0xffff0000);
+}
diff --git a/lang/pcc/pcc/arch/arm/table.c b/lang/pcc/pcc/arch/arm/table.c
new file mode 100644 (file)
index 0000000..b98745e
--- /dev/null
@@ -0,0 +1,1847 @@
+/*     $Id: table.c,v 1.20 2011/11/13 22:30:18 gmcgarry Exp $  */
+/*-
+ * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * A template has five logical sections:
+ *
+ *     1) subtree (operator); goal to achieve (cookie)
+ *     2) left node descendent of operator (node class; type)
+ *     3) right node descendent of operator (node class; type)
+ *     4) resource requirements (number of scratch registers);
+ *        subtree rewriting rule
+ *     5) emitted instructions
+ */
+
+#include "pass2.h"
+
+#define TUWORD TUNSIGNED|TULONG
+#define TSWORD TINT|TLONG
+#define TWORD  TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               COM "pointer conversion\n", },
+
+
+/*
+ * Conversions of integral types
+ *
+ * For each deunsigned type, they look something like this:
+ *
+ * signed -> bigger signed     - nothing to do
+ * signed -> bigger unsigned   - clear the top bits (of source type)
+ *
+ * signed -> smaller signed    - sign-extend the bits (to dest type)
+ * signed -> smaller unsigned  - clear the top bits (of dest type)
+ * unsigned -> smaller signed  - sign-extend top bits (to dest type)
+ * unsigned -> smaller unsigned        - clear the top bits (of dest type)
+ *
+ * unsigned -> bigger          - nothing to do
+ */
+
+{ SCONV,       INAREG,
+       SAREG,  TCHAR,
+       SAREG,  TSWORD|TSHORT,
+               0,      RLEFT,
+               COM "convert char to short/int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TCHAR,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TUCHAR,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sxtb A1,AL" COM "convert uchar to char\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUCHAR,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #24" COM "convert uchar to char\n"
+               "       mov A1,A1,asr #24\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT,
+               0,      RLEFT,
+               COM "convert uchar to (u)short/(u)int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT,
+       SAREG,  TSWORD,
+               0,      RLEFT,
+               COM "convert short to int\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TSHORT,
+       SAREG,  TUWORD|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       uxth A1,AL" COM "convert short to uint\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT,
+       SAREG,  TUWORD|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #16" COM "convert short to uint\n"
+               "       mov A1,AL,lsr #16\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TUSHORT,
+       SAREG,  TSHORT,
+               NAREG|NASL,     RESC1,
+               "       sxth A1,AL" COM "convert ushort to short\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUSHORT,
+       SAREG,  TSHORT,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #16" COM "convert ushort to short\n"
+               "       mov A1,A1,asr #16\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sxtb A1,AL" COM "convert (u)short to char\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #24" COM "convert (u)short to char\n"
+               "       mov A1,A1,asr #24\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sxtb A1,AL" COM "convert (u)short to char\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       and A1,AL,#255" COM "convert (u)short to uchar\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUSHORT,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               COM "convert ushort to (u)int\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TWORD,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sxtb A1,AL" COM "convert (u)int to char\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #24" COM "convert (u)int to char\n"
+               "       mov A1,A1,asr #24\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TWORD,
+       SAREG,  TSHORT,
+               NAREG|NASL,     RESC1,
+               "       sxth A1,AL" COM "convert (u)int to short\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TSHORT,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #16" COM "convert (u)int to short\n"
+               "       mov A1,A1,asr #16\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       and A1,AL,#255" COM "convert uchar to char\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SAREG,  TWORD,
+       SAREG,  TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       uxth A1,AL" COM "convert int to ushort\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl #16" COM "convert int to ushort\n"
+               "       mov A1,AL,lsr #16\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TPOINT|TWORD,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               COM "convert between pointers and words\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               0,      RLEFT,
+               COM "convert (u)longlong to (u)longlong\n", },
+
+/* convert (u)char/(u)short/(u)int to longlong */
+{ SCONV,       INBREG,
+       SAREG,  TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,             RESC1,
+               "       mov A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n"
+               "       mov U1,AL,asr #31\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TCHAR,
+               NAREG,          RESC1,
+               "       sxtb A1,AL" COM "convert (u)longlong to char\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TCHAR,
+               NAREG,          RESC1,
+               "       mov A1,AL,asl #24" COM "convert (u)longlong to char\n"
+               "       mov A1,A1,asr #24\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TSHORT,
+               NAREG,          RESC1,
+               "       sxth A1,AL" COM "convert (u)longlong to short\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TSHORT,
+               NAREG,          RESC1,
+               "       mov A1,AL,asl #16" COM "convert (u)longlong to short\n"
+               "       mov A1,A1,asr #16\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TWORD,
+               NAREG,          RESC1,
+               "       mov A1,AL" COM "convert (u)longlong to (u)int\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TUCHAR,
+               NAREG,          RESC1,
+               "       and A1,AL,#255" COM "convert (u)longlong to uchar\n", },
+
+{ SCONV,       INAREG | FEATURE_EXTEND,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TUSHORT,
+               NAREG,          RESC1,
+               "       uxth A1,AL" COM "convert (u)longlong to ushort\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TUSHORT,
+               NAREG,          RESC1,
+               "       mov A1,AL,asl #16" COM "convert (u)longlong to ushort\n"
+               "       mov A1,A1,lsr #16\n", },
+
+/* conversions on load from memory */
+
+/* char */
+{ SCONV,       INAREG,
+       SOREG,  TCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       ldrsb A1,AL" COM "convert char to int/long\n", },
+
+/* uchar */
+{ SCONV,       INAREG,
+       SOREG,  TUCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       ldrb A1,AL" COM "convert uchar to int/long\n", },
+/* short */
+{ SCONV,       INAREG | FEATURE_HALFWORDS,
+       SOREG,  TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       ldrsh A1,AL" COM "convert short to int/long\n", },
+
+/* ushort */
+{ SCONV,       INAREG | FEATURE_HALFWORDS,
+       SOREG,  TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       ldrh A1,AL" COM "convert ushort to int/long\n", },
+
+/* short */
+{ SCONV,       INAREG,
+       SOREG,  TSHORT|TUSHORT,
+       SAREG,  TWORD,
+               2*NAREG|NASL,   RESC1,
+               "ZH", },
+
+{ SCONV,       INAREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SAREG,  TWORD,
+               NAREG,          RESC1,
+               "       fix AL,AR" COM "convert float to int\n", },
+
+{ SCONV,       INAREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SAREG,  TSWORD,
+               NAREG,          RESC1,
+               "       ftosis AL,AR" COM "convert float to int\n", },
+
+{ SCONV,       INAREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SAREG,  TSWORD,
+               NAREG,          RESC1,
+               "       ftouis AL,AR" COM "convert float to int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INBREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NBREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INBREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NBREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INBREG,
+       SAREG,  TFLOAT,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INAREG | FEATURE_FPA,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TWORD,
+               NAREG,          RESC1,
+               "       fix AL,AR" COM "convert double/ldouble to int\n", },
+
+{ SCONV,       INAREG | FEATURE_VFP,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TSWORD,
+               NAREG,          RESC1,
+               "       ftosid AL,AR" COM "convert double/ldouble to int\n", },
+
+{ SCONV,       INAREG | FEATURE_VFP,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TUWORD,
+               NAREG,          RESC1,
+               "       ftouid AL,AR" COM "convert double/ldouble to int\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INBREG | FEATURE_FPA,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INBREG | FEATURE_VFP,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NBREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SAREG,  TWORD,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               "       flts AL,AR" COM "convert int to float\n" },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SAREG,  TSWORD,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               "       fsitos AL,AR" COM "convert int to float\n" },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SAREG,  TUWORD,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               "       fuitos AL,AR" COM "convert int to float\n" },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SBREG,  TULONGLONG|TLONGLONG,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SBREG,  TULONGLONG|TLONGLONG,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TULONGLONG|TLONGLONG,
+       SAREG,  TFLOAT,
+               NAREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SAREG,  TWORD,
+       SCREG,  TDOUBLE,
+               NCREG,          RESC1,
+               "       fltd AL,AR" COM "convert int to double\n" },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SAREG,  TSWORD,
+       SCREG,  TDOUBLE,
+               NCREG,          RESC1,
+               "       fsitod AL,AR" COM "convert int to double\n" },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SAREG,  TUWORD,
+       SCREG,  TDOUBLE,
+               NCREG,          RESC1,
+               "       fuitod AL,AR" COM "convert int to double\n" },
+
+{ SCONV,       INBREG,
+       SAREG,  TWORD,
+       SBREG,  TDOUBLE,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TDOUBLE,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TDOUBLE,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TDOUBLE,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SAREG,  TWORD,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               "       flte AL,AR" COM "convert int to ldouble\n" },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SAREG,  TSWORD,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               "       fsitod AL,AR" COM "convert int to ldouble\n" },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SAREG,  TUWORD,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               "       fuitod AL,AR" COM "convert uint to ldouble\n" },
+
+{ SCONV,       INBREG,
+       SAREG,  TWORD,
+       SBREG,  TLDOUBLE,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TLDOUBLE,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLDOUBLE,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               "       fcvtds AL,AR" COM "convert float to double\n" },
+
+{ SCONV,       INAREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,          RESC1,
+               COM "unimplemented\n", },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,          RESC1,
+               "       fcvtsd AL,AR" COM "convert float to double\n" },
+
+{ SCONV,       INBREG,
+       SAREG,  TFLOAT,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_FPA,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,              RLEFT,
+               COM "convert (l)double to (l)double", },
+
+{ SCONV,       INCREG | FEATURE_VFP,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,              RLEFT,
+               COM "convert (l)double to (l)double", },
+
+{ SCONV,       INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               0,              RLEFT,
+               COM "convert (l)double to (l)double", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,                FOREFF,
+       SCON|SNAME,     TANY,
+       SANY,           TANY,
+               0,      0,
+               "       bl CL" COM "call (args, no result) to scon/sname (CL)\n"
+               "ZC", },
+
+{ UCALL,       FOREFF,
+       SCON|SNAME,     TANY,
+       SANY,           TANY,
+               0,      0,
+               "       bl CL" COM "call (no args, no result) to scon/sname (CL)\n", },
+
+{ CALL,                INAREG,
+       SCON|SNAME,     TANY,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result in r0) to scon/sname (CL)\n"
+               "ZC", },
+
+{ CALL,                INBREG,
+       SCON|SNAME,     TANY,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+               "ZC", },
+
+{ CALL,                INCREG | FEATURE_FPA,
+       SCON|SNAME,     TANY,
+       SCREG,          TFLOAT,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result r0) to scon/sname (CL)\n"
+               "ZC", },
+
+{ CALL,                INCREG | FEATURE_FPA,
+       SCON|SNAME,     TANY,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+               "ZC", },
+
+{ CALL,                INAREG,
+       SCON|SNAME,     TANY,
+       SAREG,          TFLOAT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result r0) to scon/sname (CL)\n"
+               "ZC", },
+
+{ CALL,                INBREG,
+       SCON|SNAME,     TANY,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+               "ZC", },
+
+{ UCALL,       INAREG,
+       SCON|SNAME,     TANY,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", },
+
+{ UCALL,       INBREG,
+       SCON|SNAME,     TANY,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", },
+
+{ UCALL,       INCREG | FEATURE_FPA,
+       SCON|SNAME,     TANY,
+       SCREG,          TFLOAT,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", },
+
+{ UCALL,       INCREG | FEATURE_FPA,
+       SCON|SNAME,     TANY,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", },
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       mov lr,pc\n"
+               "       mov pc,AL\n"
+               "ZC", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       mov lr,pc\n"
+               "       mov pc,AL\n", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG,  RESC1,
+               "       mov lr,pc\n"
+               "       mov pc,AL\n"
+               "ZC", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG,  RESC1,
+               "       mov lr,pc\n"
+               "       mov pc,AL\n", },
+
+{ CALL,                INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG,  RESC1,
+               "       mov lr,pc\n"
+               "       mov pc,AL\n"
+               "ZC", },
+
+{ UCALL,       INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG,  RESC1,
+               "       mov lr,pc\n"
+               "       mov pc,AL\n", },
+
+/* struct return */
+{ USTCALL,     FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       bl CL\n", },
+
+{ USTCALL,     INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL\n", },
+
+{ USTCALL,     INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       mov lr,pc\n"
+               "       mov pc,AL\n", },
+
+{ STCALL,      FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       bl CL\n"
+               "ZC", },
+
+{ STCALL,      INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL\n"
+               "ZC", },
+
+{ STCALL,      INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       mov lr,pc\n"
+               "       mov pc,AL\n"
+               "ZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+
+{ PLUS,                INAREG,
+       SAREG,  TWORD|TPOINT,
+       SCCON,  TANY,
+               NAREG,  RESC1,
+               "       add A1,AL,AR" COM "addition of constant\n", },
+
+{ PLUS,                INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SSCON,  TANY,
+               NBREG|NBSL,     RESC1,
+               "       adds A1,AL,AR" COM "64-bit addition of constant\n"
+               "       adc U1,UL,UR\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       add A1,AL,AR" COM "addition\n", },
+
+{ PLUS,                INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       adds A1,AL,AR" COM "64-bit addition\n"
+               "       adc U1,UL,UR\n", },
+
+{ PLUS,                INCREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       adfs A1,AL,AR" COM "float add\n", },
+
+{ PLUS,                INCREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       fadds A1,AL,AR" COM "float add\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ PLUS,                INCREG | FEATURE_FPA,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       adfd A1,AL,AR" COM "double add\n", },
+
+{ PLUS,                INCREG | FEATURE_VFP,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       faddd A1,AL,AR" COM "double add\n", },
+
+{ PLUS,                INBREG,
+       SBREG,  TDOUBLE,
+       SBREG,  TDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ PLUS,                INCREG | FEATURE_FPA,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       adfe A1,AL,AR" COM "ldouble add\n", },
+
+{ PLUS,                INCREG | FEATURE_VFP,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       faddd A1,AL,AR" COM "ldouble add\n", },
+
+{ PLUS,                INBREG,
+       SBREG,  TLDOUBLE,
+       SBREG,  TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ MINUS,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SCCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       sub A1,AL,AR" COM "subtraction of constant\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       sub A1,AL,AR" COM "subtraction\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCCON,  TANY,
+               NBREG|NBSL,     RESC1,
+               "       subs A1,AL,AR" COM "64-bit subtraction of constant\n"
+               "       rsc  U1,UL,AR\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       subs A1,AL,AR" COM "64-bit subtraction\n"
+               "       sbc  U1,UL,AR\n", },
+
+{ MINUS,       INCREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       sufs A1,AL,AR" COM "float subtraction\n", },
+
+{ MINUS,       INCREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       fsubs A1,AL,AR" COM "float subtraction\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ MINUS,       INCREG | FEATURE_FPA,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       sufd A1,AL,AR" COM "double subtraction\n", },
+
+{ MINUS,       INCREG | FEATURE_VFP,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       fsubd A1,AL,AR" COM "double subtraction\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TDOUBLE,
+       SBREG,  TDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ MINUS,       INCREG | FEATURE_FPA,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       sufe A1,AL,AR" COM "ldouble subtraction\n", },
+
+{ MINUS,       INCREG | FEATURE_VFP,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       fsubd A1,AL,AR" COM "double subtraction\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TLDOUBLE,
+       SBREG,  TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+
+{ LS,  INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TANY,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl AR" COM "left shift\n", },
+
+{ LS,  INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SCCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asl AR" COM "left shift by constant\n", },
+
+{ LS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "ZO" },
+
+{ LS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TANY,
+               NSPECIAL|NBREG, RESC1,
+               "ZE" },
+
+{ RS,  INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TANY,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asr AR" COM "right shift\n", },
+
+{ RS,  INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SAREG,  TANY,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,lsr AR" COM "right shift\n", },
+
+{ RS,  INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SCCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,asr AR" COM "right shift by constant\n", },
+
+{ RS,  INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SCCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       mov A1,AL,lsr AR" COM "right shift by constant\n", },
+
+{ RS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "ZO" },
+
+{ RS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TANY,
+               NSPECIAL|NBREG, RESC1,
+               "ZE" },
+
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TWORD|TPOINT,
+       SAREG,          TWORD|TPOINT,
+               0,      RDEST,
+               "       str AR,AL" COM "assign word\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG|SNAME,    TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               0,      RDEST,
+               "       str AR,AL" COM "assign 64-bit value\n"
+               "       str UR,UL\n", },
+
+/* XXX don't know if this works */
+{ ASSIGN,      FOREFF|INBREG,
+       SAREG,          TPTRTO|TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               0,      RDEST,
+               "       stmdb AL,{AR-UR}" COM "assign 64-bit value\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TCHAR|TUCHAR,
+       SAREG,          TCHAR|TUCHAR,
+               0,      RDEST,
+               "       strb AR,AL" COM "assign (u)char\n", },
+
+{ ASSIGN,      FOREFF|INAREG | FEATURE_HALFWORDS,
+       SOREG|SNAME,    TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RDEST,
+               "       strh AR,AL" COM "assign (u)short\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               NAREG|NASL,     RDEST,
+               "ZH", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_FPA,
+       SOREG|SNAME,    TFLOAT,
+       SCREG,          TFLOAT,
+               0,      RDEST,
+               "       stfs AR,AL" COM "assign float\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_VFP,
+       SOREG|SNAME,    TFLOAT,
+       SCREG,          TFLOAT,
+               0,      RDEST,
+               COM "unimplemented\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TFLOAT,
+       SAREG,          TFLOAT,
+               0,      RDEST,
+               "       str AR,AL" COM "assign float (soft-float)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_FPA,
+       SOREG|SNAME,    TDOUBLE,
+       SCREG,          TDOUBLE,
+               0,      RDEST,
+               "       stfd AR,AL" COM "assign double\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_VFP,
+       SOREG|SNAME,    TDOUBLE,
+       SCREG,          TDOUBLE,
+               0,      RDEST,
+               COM "unimplemented\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG|SNAME,    TDOUBLE,
+       SBREG,          TDOUBLE,
+               0,      RDEST,
+               "       str AR,AL" COM "assign double (soft-float)\n"
+               "       str UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_FPA,
+       SOREG|SNAME,    TLDOUBLE,
+       SCREG,          TLDOUBLE,
+               0,      RDEST,
+               "       stfe AR,AL" COM "assign ldouble\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_VFP,
+       SOREG|SNAME,    TLDOUBLE,
+       SCREG,          TLDOUBLE,
+               0,      RDEST,
+               COM "not implemented", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG|SNAME,    TLDOUBLE,
+       SBREG,          TLDOUBLE,
+               0,      RDEST,
+               "       str AR,AL" COM "assign ldouble (soft-float)\n"
+               "       str UR,UL\n", },
+
+/* assign register to register */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               0,      RDEST,
+               "       mov AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+        SBREG, TLONGLONG|TULONGLONG,
+        SBREG, TLONGLONG|TULONGLONG,
+                0,     RDEST,
+               "       mov AL,AR" COM "assign UR:AR to UL:AL\n"
+                "      mov UL,UR\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               0,      RDEST,
+               "       mvf AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               0,      RDEST,
+               "       fcpys AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               0,      RDEST,
+               "       mov AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_FPA,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       mvf AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_VFP,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fcpyd AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       mov AL,AR" COM "assign (l)double reg to (l)double reg\n"
+               "       mov UL,UR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,           TANY,
+       SOREG|SNAME,    TANY,
+               3*NAREG,        RDEST,
+               "       ldr A1,AR" COM "bit-field assignment\n"
+               "       ldr A2,AL\n"
+               "       ldr A3,=M\n"
+               "       mov A1,A1,asl H\n"
+               "       and A1,A1,A3\n"
+               "       bic A2,A2,A3\n"
+               "       orr A3,A2,A1\n"
+               "       str A3,AL\n"
+               "F      ldr AD,AR\n"
+               "FZB", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,   TANY,
+       SAREG,  TANY,
+               3*NAREG,        RDEST,
+               "       ldr A2,AL" COM "bit-field assignment\n"
+               "       ldr A3,=M\n"
+               "       mov A1,AR,asl H\n"
+               "       and A1,A1,A3\n"
+               "       bic A2,A2,A3\n"
+               "       orr A3,A2,A1\n"
+               "       str A3,AL\n"
+               "F      mov AD,AR\n"
+               "FZB", },
+
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SAREG,          TPTRTO|TANY,
+               NSPECIAL,       RDEST,
+               "ZQ", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+
+{ DIV, INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG|NASL,    RESC1,
+               "ZE", },
+
+{ DIV, INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZE", },
+
+{ DIV, INCREG | FEATURE_FPA,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               NCREG,  RESC1,
+               "       dvfs A1,AL,AL" COM "fast (float) divide\n", },
+
+{ DIV, INCREG | FEATURE_VFP,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               NCREG,  RESC1,
+               "       fdivs A1,AL,AL" COM "fast (float) divide\n", },
+
+{ DIV, INAREG,
+       SAREG,          TFLOAT,
+       SAREG,          TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ DIV, INCREG | FEATURE_FPA,
+       SCREG,          TDOUBLE,
+       SCREG,          TDOUBLE,
+               NCREG,  RESC1,
+               "       dvfd A1,AL,AL" COM "double divide\n", },
+
+{ DIV, INCREG | FEATURE_VFP,
+       SCREG,          TDOUBLE,
+       SCREG,          TDOUBLE,
+               NCREG,  RESC1,
+               "       fdivd A1,AL,AL" COM "double divide\n", },
+
+{ DIV, INBREG,
+       SBREG,          TDOUBLE,
+       SBREG,          TDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ DIV, INCREG | FEATURE_FPA,
+       SCREG,          TLDOUBLE,
+       SCREG,          TLDOUBLE,
+               NCREG,  RESC1,
+               "       dvfe A1,AL,AR" COM "long double load\n", },
+
+{ DIV, INCREG | FEATURE_VFP,
+       SCREG,          TLDOUBLE,
+       SCREG,          TLDOUBLE,
+               NCREG,  RESC1,
+               "       fdivd A1,AL,AL" COM "double divide\n", },
+
+{ DIV, INBREG,
+       SBREG,          TLDOUBLE,
+       SBREG,          TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ MOD, INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG, RESC1,
+               "ZE", },
+
+{ MOD, INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ MUL, INAREG | FEATURE_MUL,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG,  RESC1,
+               "       mul A1,AL,AR\n", },
+
+{ MUL, INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NSPECIAL|NAREG, RESC1,
+               "ZE", },
+
+{ MUL, INBREG | FEATURE_MULL,
+       SAREG,          TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,          TUWORD|TPOINT|TUSHORT|TUCHAR,
+               NBREG,  RESC1,
+               "       smull U1,A1,AL,AR\n", },
+
+{ MUL, INBREG | FEATURE_MUL,
+       SAREG,          TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,          TUWORD|TPOINT|TUSHORT|TUCHAR,
+               NBREG,  RESC1,
+               "       mul A1,AL,AR\n"
+               "       mov U1,A1,asr #31\n", },
+
+{ MUL, INBREG,
+       SAREG,          TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,          TUWORD|TPOINT|TUSHORT|TUCHAR,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ MUL, INBREG | FEATURE_MULL,
+       SAREG,          TSWORD|TSHORT|TCHAR,
+       SAREG,          TSWORD|TSHORT|TCHAR,
+               NBREG,  RESC1,
+               "       umull U1,A1,AL,AR\n", },
+
+{ MUL, INBREG | FEATURE_MUL,
+       SAREG,          TSWORD|TSHORT|TCHAR,
+       SAREG,          TSWORD|TSHORT|TCHAR,
+               NBREG,  RESC1,
+               "       mul A1,AL,AR\n"
+               "       mov U1,#0\n", },
+
+{ MUL, INBREG,
+       SAREG,          TSWORD|TSHORT|TCHAR,
+       SAREG,          TSWORD|TSHORT|TCHAR,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ MUL, INBREG | FEATURE_MULL,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       umull U1,A1,AL,AR\n", },
+
+{ MUL, INBREG | FEATURE_MUL,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       mul A1,AL,AR\n"
+               "       mov U1,A1,asr #31\n", },
+
+{ MUL, INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ MUL, INCREG | FEATURE_FPA,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               NCREG,  RESC1,
+               "       fmls A1,AL,AL" COM "fast (float) multiply\n", },
+
+{ MUL, INCREG | FEATURE_VFP,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               NCREG,  RESC1,
+               "       fmuls A1,AL,AL" COM "float multiply\n", },
+
+{ MUL, INAREG,
+       SAREG,          TFLOAT,
+       SAREG,          TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ MUL, INCREG | FEATURE_FPA,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       mufd A1,AL,AL" COM "fast (l)double multiply\n", },
+
+{ MUL, INCREG | FEATURE_VFP,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       muld A1,AL,AL" COM "(l)double multiply\n", },
+
+{ MUL, INBREG,
+       SBREG,          TDOUBLE|TLDOUBLE,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+/*
+ * Indirection operators.
+ */
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       ldr A1,AL" COM "word load\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TCHAR,
+               NAREG,  RESC1,
+               "       ldrsb A1,AL" COM "char load\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TUCHAR,
+               NAREG,  RESC1,
+               "       ldrb A1,AL" COM "uchar load\n", },
+
+{ UMUL,        INAREG | FEATURE_HALFWORDS,
+       SANY,           TANY,
+       SOREG|SNAME,    TUSHORT,
+               NAREG,  RESC1,
+               "       ldrh A1,AL" COM "short load\n", },
+
+{ UMUL,        INAREG | FEATURE_HALFWORDS,
+       SANY,           TANY,
+       SOREG|SNAME,    TSHORT,
+               NAREG,  RESC1,
+               "       ldrsh A1,AL" COM "short load\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TSHORT|TUSHORT,
+               2*NAREG|NASL,   RESC1,
+               "ZH", },
+
+{ UMUL, INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       ldr A1,AL" COM "64-bit load\n"
+               "       ldr U1,UL\n", },
+
+{ UMUL, INCREG | FEATURE_FPA,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NCREG,  RESC1,
+               "       ldfs A1,AL" COM "float load\n", },
+
+{ UMUL, INCREG | FEATURE_VFP,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NCREG,  RESC1,
+               COM "not implemented\n", },
+
+{ UMUL, INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NAREG,  RESC1,
+               "       ldr A1,AL" COM "float load\n", },
+
+{ UMUL, INCREG | FEATURE_FPA,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE,
+               NCREG,  RESC1,
+               "       ldfd A1,AL" COM "double load\n", },
+
+{ UMUL, INCREG | FEATURE_VFP,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE,
+               NCREG,  RESC1,
+               COM "not implemented\n", },
+
+{ UMUL, INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE,
+               NBREG,  RESC1,
+               "       ldr A1,AL" COM "double load\n"
+               "       ldr U1,UL\n", },
+
+{ UMUL, INCREG | FEATURE_FPA,
+       SANY,           TANY,
+       SOREG|SNAME,    TLDOUBLE,
+               NCREG,  RESC1,
+               "       ldfe A1,AL" COM "long double load\n", },
+
+{ UMUL, INCREG | FEATURE_VFP,
+       SANY,           TANY,
+       SOREG|SNAME,    TLDOUBLE,
+               NCREG,  RESC1,
+               COM "not implemented\n", },
+
+{ UMUL, INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TLDOUBLE,
+               NBREG,  RESC1,
+               "       ldr A1,AL" COM "long double load (soft-float)\n"
+               "       ldr U1,UL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* compare with register */
+{ OPLOG,       FORCC,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+               0,      RESCC,
+               "       cmp AL,AR" COM "AR-AL (sets flags)\n", },
+
+/* compare with register */
+{ OPLOG,       FORCC,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+               0,      RESCC,
+               "       cmp AL,AR" COM "AR-AL (sets flags)\n", },
+
+/* compare with register */
+{ OPLOG,       FORCC,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               0,      RESCC,
+               "ZD", },
+
+{ OPLOG,       FORCC | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NSPECIAL,       RESCC,
+               "       cmfs AL,AR" COM "float compare\n", },
+
+{ OPLOG,       FORCC | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               0,      RESCC,
+               "       fcmps AL,AR" COM "float compare\n", },
+
+{ OPLOG,       FORCC,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL,       RESCC,
+               "ZF", },
+
+{ OPLOG,       FORCC | FEATURE_FPA,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NSPECIAL,       RESCC,
+               "       cmfd AL,AR" COM "double compare\n", },
+
+{ OPLOG,       FORCC | FEATURE_VFP,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               0,      RESCC,
+               "       fcmpd AL,AR" COM "double compare\n", },
+
+{ OPLOG,       FORCC,
+       SBREG,  TDOUBLE,
+       SBREG,  TDOUBLE,
+               NSPECIAL,       RESCC,
+               "ZF", },
+
+{ OPLOG,       FORCC | FEATURE_FPA,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NSPECIAL,       RESCC,
+               "       cmfe AL,AR" COM "ldouble compare\n", },
+
+{ OPLOG,       FORCC | FEATURE_VFP,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               0,      RESCC,
+               "       fcmpd AL,AR" COM "double compare\n", },
+
+{ OPLOG,       FORCC,
+       SBREG,  TLDOUBLE,
+       SBREG,  TLDOUBLE,
+               NSPECIAL,       RESCC,
+               "ZF", },
+
+/* AND/OR/ER */
+{ AND, INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1|RESCC,
+               "       and A1,AL,AR" COM "64-bit and\n"
+               "       and U1,UL,UR\n", },
+
+{ OR,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       orr A1,AL,AR" COM "64-bit or\n"
+               "       orr U1,UL,UR\n" },
+
+{ ER,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       eor A1,AL,AR" COM "64-bit xor\n"
+               "       eor U1,UL,UR\n" },
+
+{ OPSIMP,      INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1|RESCC,
+               "       O A1,AL,AR\n", },
+
+{ OPSIMP,      INAREG|FORCC,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       Os A1,AL,AR\n", },
+
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       b LL\n", },
+
+#if 0
+{ GOTO,        FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       mov pc,AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       ldr A1,AL" COM "load word from memory\n", },
+
+{ OPLTYPE,      INBREG,
+        SANY,          TANY,
+        SOREG|SNAME,   TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+                "      ldr A1,AL" COM "load long long from memory\n"
+               "       ldr U1,UL\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TCHAR,
+               NAREG,  RESC1,
+               "       ldrsb A1,AL" COM "load char from memory\n" },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TUCHAR,
+               NAREG,  RESC1,
+               "       ldrb A1,AL" COM "load uchar from memory\n", },
+
+{ OPLTYPE,     INAREG | FEATURE_HALFWORDS,
+       SANY,           TANY,
+       SOREG|SNAME,    TSHORT,
+               NAREG,  RESC1,
+               "       ldrsh A1,AL" COM "load short from memory\n", },
+
+{ OPLTYPE,     INAREG | FEATURE_HALFWORDS,
+       SANY,           TANY,
+       SOREG|SNAME,    TUSHORT,
+               NAREG,  RESC1,
+               "       ldrh A1,AL" COM "load ushort from memory\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TSHORT|TUSHORT,
+               2*NAREG,        RESC1,
+               "ZH", },
+
+#if 0
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SCON,           TPOINT,
+               NAREG,  RESC1,
+               "       ldr A1,AL" COM "load integer constant\n", },
+#endif
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SCON,           TANY,
+               NAREG,  RESC1,
+               "ZI", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "ZJ", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG,  TANY,
+               NAREG,  RESC1,
+               "       mov A1,AL" COM "load AL into A1\n" },
+
+{ OPLTYPE,      INBREG,
+        SANY,   TANY,
+        SBREG, TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+               "       mov A1,AL" COM "load UL:AL into U1:A1\n"
+                "       mov U1,UL\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_FPA,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NCREG,  RESC1,
+               "       ldfs A1,AL" COM "load float\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_VFP,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NCREG,  RESC1,
+               COM "not implemented\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NAREG,  RESC1,
+               "       ldr A1,AL" COM "load float (soft-float)\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_FPA,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE,
+               NCREG,  RESC1,
+               "       ldfd A1,AL" COM "load double\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_VFP,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE,
+               NCREG,  RESC1,
+               COM "not implemented\n" },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE,
+               NBREG,  RESC1,
+               "       ldr A1,AL" COM "load double (soft-float)\n"
+               "       ldr U1,UL\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_FPA,
+       SANY,           TANY,
+       SOREG|SNAME,    TLDOUBLE,
+               NCREG,  RESC1,
+               "       ldfe A1,AL" COM "load ldouble\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_VFP,
+       SANY,           TANY,
+       SOREG|SNAME,    TLDOUBLE,
+               NCREG,  RESC1,
+               COM "not implemented\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TLDOUBLE,
+               NBREG,  RESC1,
+               "       ldr A1,AL" COM "load ldouble (soft-float)\n"
+               "       ldr U1,UL\n", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       rsb A1,AL,#0" COM "negation\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       rsbs A1,AL,#0" COM "64-bit negation\n"
+               "       rsc U1,UL,#0\n", },
+
+{ UMINUS,      INCREG | FEATURE_FPA,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       mvfs A1,AL" COM "float negation\n", },
+
+{ UMINUS,      INCREG | FEATURE_VFP,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       negs A1,AL" COM "float negation\n", },
+
+{ UMINUS,      INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ UMINUS,      INCREG | FEATURE_FPA,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       mvfd A1,AL" COM "double negation\n", },
+
+{ UMINUS,      INCREG | FEATURE_VFP,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       negd A1,AL" COM "double negation\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TDOUBLE,
+       SBREG,  TDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ UMINUS,      INCREG | FEATURE_FPA,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       mvfe A1,AL" COM "ldouble negation\n", },
+
+{ UMINUS,      INCREG | FEATURE_VFP,
+       SCREG,  TLDOUBLE,
+       SCREG,  TLDOUBLE,
+               NCREG,  RESC1,
+               "       negd A1,AL" COM "ldouble negation\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TLDOUBLE,
+       SBREG,  TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ COMPL,       INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       mvn A1,AL" COM "complement\n", },
+
+{ COMPL,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,
+               "       mvn A1,AL" COM "64-bit complement\n"
+               "       mvn U1,UL\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+{ FUNARG,       FOREFF,
+        SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SANY,   TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                0,      0,
+               "       stmfd sp!,{AL}" COM "save function arg to stack\n", },
+
+{ FUNARG,       FOREFF,
+        SBREG,  TLONGLONG|TULONGLONG,
+        SANY,  TLONGLONG|TULONGLONG,
+                0,      0,
+               "       stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", },
+
+{ FUNARG,      FOREFF,
+       SCREG,  TFLOAT,
+       SANY,   TFLOAT,
+               0,      0,
+               "       stmfd sp!,{AL}" COM "save function arg to stack\n", },
+
+{ FUNARG,       FOREFF,
+        SCREG,  TDOUBLE|TLDOUBLE,
+        SANY,  TDOUBLE|TLDOUBLE,
+                0,      0,
+               "       stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/hppa/code.c b/lang/pcc/pcc/arch/hppa/code.c
new file mode 100644 (file)
index 0000000..352eecd
--- /dev/null
@@ -0,0 +1,258 @@
+/*     $Id: code.c,v 1.28 2012/06/06 09:28:01 ragge Exp $      */
+/*     $OpenBSD: code.c,v 1.2 2007/11/22 15:06:43 stefan Exp $ */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+NODE *funarg(NODE *, int *);
+int argreg(TWORD, int *);
+
+static const char *const loctbl[] = { "text", "data", "section .rodata" };
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       extern char *nextsect;
+       static int lastloc = -1;
+       TWORD t;
+       char *n;
+       int s;
+
+       if (sp == NULL) {
+               lastloc = -1;
+               return;
+       }
+       t = sp->stype;
+       s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+       if (nextsect) {
+               printf("\t.section %s\n", nextsect);
+               nextsect = NULL;
+               s = -1;
+       } else if (s != lastloc)
+               printf("\t.%s\n", loctbl[s]);
+       lastloc = s;
+       while (ISARY(t))
+               t = DECREF(t);
+       s = ISFTN(t) ? ALINT : talign(t, sp->ssue);
+       if (s > ALCHAR)
+               printf("\t.align\t%d\n", s / ALCHAR);
+       n = sp->soname ? sp->soname : sp->sname;
+       if (sp->sclass == EXTDEF)
+               printf("\t.export %s, %s\n", n,
+                   ISFTN(t)? "code" : "data");
+       if (sp->slevel == 0)
+               printf("\t.type\t%s, @%s\n\t.label %s\n",
+                   n, ISFTN(t)? "function" : "object", n);
+       else
+               printf("\t.type\t" LABFMT ", @%s\n\t.label\t" LABFMT "\n", 
+                   sp->soffset, ISFTN(t)? "function" : "object", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       NODE *p, *q;
+       int sz;
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+       /* address of return struct is in %ret0 */
+       /* create a call to memcpy() */
+       /* will get the result in %ret0 */
+       p = block(REG, NIL, NIL, CHAR+PTR, 0, 0);
+       p->n_rval = RET0;
+       q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0);
+       q->n_rval = FP;
+       q->n_lval = 8; /* return buffer offset */
+       p = block(CM, q, p, INT, 0, 0);
+       sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+       p = block(CM, p, bcon(sz), INT, 0, 0);
+       p->n_right->n_name = "";
+       p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0);
+       p->n_left->n_name = "memcpy";
+       p = clocal(p);
+       send_passt(IP_NODE, p);
+}
+
+int
+argreg(TWORD t, int *n)
+{
+       switch (t) {
+       case FLOAT:
+               return FR7L - 2 * (*n)++;
+       case DOUBLE:
+       case LDOUBLE:
+               *n += 2;
+               return FR6 - *n - 2;
+       case LONGLONG:
+       case ULONGLONG:
+               *n += 2;
+               return AD1 - (*n - 2) / 2;
+       default:
+               return ARG0 - (*n)++;
+       }
+}
+
+/*
+ * code for the beginning of a function; 'a' is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int cnt)
+{
+       struct symtab *sp;
+       NODE *p, *q;
+       int i, n, sz;
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               /* Function returns struct, adjust arg offset */
+               for (i = 0; i < cnt; i++)
+                       a[i]->soffset += SZPOINT(LONG);
+       }
+
+       /* recalculate the arg offset and create TEMP moves */
+       for (n = 0, i = 0; i < cnt; i++) {
+               sp = a[i];
+
+               sz = szty(sp->stype);
+               if (n % sz)
+                       n++;    /* XXX LDOUBLE */
+
+               if (n < 4) {
+                       p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
+                       /* TODO p->n_left->n_lval = -(32 + n * 4); */
+                       q = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue);
+                       q->n_rval = argreg(sp->stype, &n);
+                       p = buildtree(ASSIGN, p, q);
+                       sp->soffset = regno(p->n_left);
+                       sp->sflags |= STNODE;
+                       ecomp(p);
+               } else {
+                       sp->soffset += SZINT * n;
+                       if (xtemps) {
+                               /* put stack args in temps if optimizing */
+                               p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
+                               p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0));
+                               sp->soffset = regno(p->n_left);
+                               sp->sflags |= STNODE;
+                               ecomp(p);
+                       }
+               }
+       }
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+       if (flag)
+               return;
+
+       printf("\t.end\n");
+}
+
+void
+bjobcode(void)
+{
+       printf("\t.level\t1.1\n"
+           "\t.import $global$, data\n"
+           "\t.import $$dyncall, millicode\n");
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+NODE *
+funarg(NODE *p, int *n)
+{
+       NODE *r;
+       int sz;
+
+       if (p->n_op == CM) {
+               p->n_left = funarg(p->n_left, n);
+               p->n_right = funarg(p->n_right, n);
+               return p;
+       }
+
+       sz = szty(p->n_type);
+       if (*n % sz)
+               (*n)++; /* XXX LDOUBLE */
+
+       if (*n >= 4) {
+               *n += sz;
+               r = block(OREG, NIL, NIL, p->n_type|PTR, 0, 0);
+               r->n_rval = SP;
+               r->n_lval = -(32 + *n * 4);
+       } else {
+               r = block(REG, NIL, NIL, p->n_type, 0, 0);
+               r->n_lval = 0;
+               r->n_rval = argreg(p->n_type, n);
+       }
+       p = block(ASSIGN, r, p, p->n_type, 0, 0);
+       clocal(p);
+
+       return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       int n = 0;
+
+       p->n_right = funarg(p->n_right, &n);
+       return p;
+}
diff --git a/lang/pcc/pcc/arch/hppa/local.c b/lang/pcc/pcc/arch/hppa/local.c
new file mode 100644 (file)
index 0000000..2daf821
--- /dev/null
@@ -0,0 +1,823 @@
+/*     $Id: local.c,v 1.41 2015/08/18 10:15:08 ragge Exp $     */
+/*     $OpenBSD: local.c,v 1.2 2007/11/18 17:39:55 ragge Exp $ */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+#include "pass2.h"
+
+/*     this file contains code which is dependent on the target machine */
+
+#define        IALLOC(sz)      (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+struct symtab *makememcpy(void);
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+       register struct symtab *q, *sp;
+       register NODE *r, *l, *s;
+       register int o, m, rn;
+       char *ch, name[16], *n;
+       TWORD t;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       switch (o = p->n_op) {
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       break;  /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+                       /* first four integral args are in regs */
+                       rn = (q->soffset >> 5) - 8;
+                       if (rn < 4) {
+                               r = block(REG, NIL, NIL, p->n_type, 0, 0);
+                               r->n_lval = 0;
+                               switch (p->n_type) {
+                               case FLOAT:
+                                       r->n_rval = FR7L - rn;
+                                       break;
+                               case DOUBLE:
+                               case LDOUBLE:
+                                       r->n_rval = FR6 - rn;
+                                       break;
+                               case LONGLONG:
+                               case ULONGLONG:
+                                       r->n_rval = AD1 - rn / 2;
+                                       break;
+                               default:
+                                       r->n_rval = ARG0 - rn;
+                               }
+                               r->n_sue = p->n_sue;
+                               p->n_sue = NULL;
+                               nfree(p);
+                               p = r;
+                               break;
+                       }
+                       /* FALLTHROUGH */
+
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+               case STATIC:
+               case EXTERN:
+                       if (p->n_sp->sflags & SSTRING)
+                               break;
+
+                       n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
+                       if (strncmp(n, "__builtin", 9) == 0)
+                               break;
+
+                       l = block(REG, NIL, NIL, INT, 0, 0);
+                       l->n_lval = 0;
+                       l->n_rval = R1;
+                       l = block(ASSIGN, l, p, INT, 0, 0);
+                       r = xbcon(0, p->n_sp, INT);
+                       p = block(UMUL,
+                           block(PLUS, l, r, INT, 0, 0),
+                           NIL, p->n_type, p->n_df, p->n_sue);
+                       break;
+               }
+               break;
+
+       case ADDROF:
+               l = p->n_left;
+               if (!l->n_sp)
+                       break;
+
+               if (l->n_sp->sclass != EXTERN &&
+                   l->n_sp->sclass != STATIC &&
+                   l->n_sp->sclass != USTATIC &&
+                   l->n_sp->sclass != EXTDEF)
+                       break;
+
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               l->n_lval = 0;
+               l->n_rval = R1;
+               l = block(ASSIGN, l, p->n_left, INT, 0, 0);
+               r = xbcon(0, p->n_left->n_sp, INT);
+               l = block(PLUS, l, r, p->n_type, p->n_df, p->n_sue);
+               nfree(p);
+               p = l;
+               break;
+
+       case CBRANCH:
+               l = p->n_left;
+
+               /*
+                * Remove unnecessary conversion ops.
+                */
+               if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+                       if (coptype(l->n_op) != BITYPE)
+                               break;
+                       if (l->n_right->n_op == ICON) {
+                               r = l->n_left->n_left;
+                               if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+                                       break;
+                               /* Type must be correct */
+                               t = r->n_type;
+                               nfree(l->n_left);
+                               l->n_left = r;
+                               l->n_type = t;
+                               l->n_right->n_type = t;
+                       }
+               }
+               break;
+
+       case PCONV:
+               /* Remove redundant PCONV's. Be careful */
+               l = p->n_left;
+               if (l->n_op == ICON) {
+                       l->n_lval = (unsigned)l->n_lval;
+                       goto delp;
+               }
+               if (l->n_type < INT || l->n_type == LONGLONG ||
+                   l->n_type == ULONGLONG) {
+                       /* float etc? */
+                       p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
+                       break;
+               }
+               /* if left is SCONV, cannot remove */
+               if (l->n_op == SCONV)
+                       break;
+
+               /* avoid ADDROF TEMP */
+               if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+                       break;
+
+               /* if conversion to another pointer type, just remove */
+               if (p->n_type > BTMASK && l->n_type > BTMASK)
+                       goto delp;
+               break;
+
+       delp:   l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_sue = p->n_sue;
+               nfree(p);
+               p = l;
+               break;
+
+       case SCONV:
+               l = p->n_left;
+
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       p = l;
+                       break;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == UMUL || l->n_op == TEMP ||
+                                   l->n_op == NAME) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       p = l;
+                                       break;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       p = l;
+                       break;
+               }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       CONSZ val = l->n_lval;
+
+                       if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+                           switch (m) {
+                       case BOOL:
+                               l->n_lval = l->n_lval != 0;
+                               break;
+                       case CHAR:
+                               l->n_lval = (char)val;
+                               break;
+                       case UCHAR:
+                               l->n_lval = val & 0377;
+                               break;
+                       case SHORT:
+                               l->n_lval = (short)val;
+                               break;
+                       case USHORT:
+                               l->n_lval = val & 0177777;
+                               break;
+                       case ULONG:
+                       case UNSIGNED:
+                               l->n_lval = val & 0xffffffff;
+                               break;
+                       case LONG:
+                       case INT:
+                               l->n_lval = (int)val;
+                               break;
+                       case LONGLONG:
+                               l->n_lval = (long long)val;
+                               break;
+                       case ULONGLONG:
+                               l->n_lval = val;
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", m);
+                       }
+                       l->n_type = m;
+                       l->n_sue = 0;
+                       nfree(p);
+                       return l;
+                } else if (l->n_op == FCON) {
+                       l->n_lval = l->n_dcon;
+                       l->n_sp = NULL;
+                       l->n_op = ICON;
+                       l->n_type = m;
+                       l->n_sue = 0;
+                       nfree(p);
+                       return clocal(l);
+               }
+
+               if (DEUNSIGN(p->n_type) == SHORT &&
+                   DEUNSIGN(l->n_type) == SHORT) {
+                       nfree(p);
+                       p = l;
+               }
+               if ((p->n_type == CHAR || p->n_type == UCHAR ||
+                   p->n_type == SHORT || p->n_type == USHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+                       p->n_left->n_type = INT;
+                       break;
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
+               p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
+               p = block(SCONV, p, NIL, p->n_type, 0, 0);
+               p->n_left->n_type = INT;
+               break;
+
+       case LS:
+       case RS:
+               /* shift count must be in an int */
+               if (p->n_right->n_op == ICON || p->n_right->n_lval <= 32)
+                       break;  /* do not do anything */
+               if (p->n_right->n_type != INT || p->n_right->n_lval > 32)
+                       p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
+               break;
+
+#if 0
+       case FLD:
+               /* already rewritten (in ASSIGN) */
+               if (p->n_left->n_op == TEMP)
+                       break;
+
+               r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+               l = block(ASSIGN, r, p->n_left, p->n_type, p->n_df, p->n_sue);
+               p->n_left = tcopy(r);
+               p = block(COMOP, l, p, p->n_type, p->n_df, p->n_sue);
+               break;
+#endif
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ?
+                   RETREG(CHAR) : RETREG(p->n_type);
+               if (p->n_right->n_op != FLD)
+                       break;
+               break;
+
+       case ASSIGN:
+               r = p->n_right;
+               l = p->n_left;
+
+               /* rewrite ICON#0 into %r0 */
+               if (r->n_op == ICON && r->n_lval == 0 &&
+                   (l->n_op == REG || l->n_op == OREG)) {
+                       r->n_op = REG;
+                       r->n_rval = R0;
+               }
+
+               /* rewrite FCON#0 into %fr0 */
+               if (r->n_op == FCON && r->n_lval == 0 && l->n_op == REG) {
+                       r->n_op = REG;
+                       r->n_rval = r->n_type == FLOAT? FR0L : FR0;
+               }
+
+               if (p->n_left->n_op != FLD)
+                       break;
+
+               r = tempnode(0, l->n_type, l->n_df, l->n_sue);
+               p = block(COMOP,
+                   block(ASSIGN, r, l->n_left, l->n_type, l->n_df, l->n_sue),
+                   p, p->n_type, p->n_df, p->n_sue);
+               s = tcopy(l->n_left);
+               p = block(COMOP, p,
+                   block(ASSIGN, s, tcopy(r), l->n_type, l->n_df, l->n_sue),
+                   p->n_type, p->n_df, p->n_sue);
+               l->n_left = tcopy(r);
+               break;
+
+       case STASG:
+               /* memcpy(left, right, size) */
+               sp = makememcpy();
+               l = p->n_left;
+               /* guess struct return */
+               if (l->n_op == NAME && ISFTN(l->n_sp->stype)) {
+                       l = block(REG, NIL, NIL, VOID|PTR, 0, 0);
+                       l->n_lval = 0;
+                       l->n_rval = RET0;
+               } else if (l->n_op == UMUL)
+                       l = tcopy(l->n_left);
+               else if (l->n_op == NAME)
+                       l = block(ADDROF,tcopy(l),NIL,PTR|STRTY,0,0);
+               l = block(CALL, block(ADDROF,
+                   (s = block(NAME, NIL, NIL, FTN, 0, 0)),
+                   NIL, PTR|FTN, 0, 0),
+                   block(CM, block(CM, l, tcopy(p->n_right),
+                   STRTY|PTR, 0, 0),
+                   (r = block(ICON, NIL, NIL, INT, 0, 0)), 0, 0, 0),
+                   INT, 0, 0);
+               r->n_lval = p->n_sue->suesize/SZCHAR;
+               s->n_sp = sp;
+               s->n_df = s->n_sp->sdf;
+               defid(s, EXTERN);
+               tfree(p);
+               p = l;
+               p->n_left = clocal(p->n_left);
+               p->n_right = clocal(p->n_right);
+               calldec(p->n_left, p->n_right);
+               funcode(p);
+               break;
+
+       case STARG:
+               /* arg = memcpy(argN-size, src, size) */
+               sp = makememcpy();
+               l = block(CALL, block(ADDROF,
+                   (s = block(NAME, NIL, NIL, FTN, 0, 0)),NIL,0,0,0),
+                   block(CM, block(CM, tcopy(p), tcopy(p->n_left), 0, 0, 0),
+                   (r = block(ICON, NIL, NIL, INT, 0, 0)), 0, 0, 0),
+                   INT, 0, 0);
+               r->n_lval = p->n_sue->suesize/SZCHAR;
+               s->n_sp = sp;
+               s->n_df = s->n_sp->sdf;
+               defid(s, EXTERN);
+               tfree(p);
+               p = l;
+               p->n_left = clocal(p->n_left);
+               calldec(p->n_left, p->n_right);
+               funcode(p);
+               break;
+
+       case STCALL:
+       case CALL:
+               for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+                       if (r->n_right->n_op == ASSIGN &&
+                           r->n_right->n_right->n_op == CALL) {
+                               s = r->n_right->n_right;
+                               l = tempnode(0, s->n_type, s->n_df, s->n_sue);
+                               ecode(buildtree(ASSIGN, l, s));
+                               r->n_right->n_right = tcopy(l);
+                       }
+                       if (r->n_left->n_op == ASSIGN &&
+                           r->n_left->n_right->n_op == CALL) {
+                               s = r->n_left->n_right;
+                               l = tempnode(0, s->n_type, s->n_df, s->n_sue);
+                               ecode(buildtree(ASSIGN, l, s));
+                               r->n_left->n_right = tcopy(l);
+                       }
+               }
+               break;
+       }
+
+       /* second pass - rewrite long ops */
+       switch (o) {
+       case DIV:
+       case MOD:
+       case MUL:
+       case RS:
+       case LS:
+               if (!(p->n_type == LONGLONG || p->n_type == ULONGLONG) ||
+                   !((o == DIV || o == MOD || o == MUL) &&
+                     p->n_type < FLOAT))
+                       break;
+               if (o == DIV && p->n_type == ULONGLONG) ch = "udiv";
+               else if (o == DIV) ch = "div";
+               else if (o == MUL) ch = "mul";
+               else if (o == MOD && p->n_type == ULONGLONG) ch = "umod";
+               else if (o == MOD) ch = "mod";
+               else if (o == RS && p->n_type == ULONGLONG) ch = "lshr";
+               else if (o == RS) ch = "ashr";
+               else if (o == LS) ch = "ashl";
+               else break;
+               snprintf(name, sizeof(name), "__%sdi3", ch);
+               p->n_right = block(CM, p->n_left, p->n_right, 0, 0, 0);
+               p->n_left = block(ADDROF,
+                   block(NAME, NIL, NIL, FTN, 0, 0), NIL, PTR|FTN, 0, 0);
+               p->n_left->n_left->n_sp = lookup(addname(name), 0);
+               defid(p->n_left->n_left, EXTERN);
+               p->n_left = clocal(p->n_left);
+               calldec(p->n_left, p->n_right);
+               p->n_op = CALL;
+               funcode(p);
+               break;
+       }
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+struct symtab *
+makememcpy(void)
+{
+       NODE *memcpy, *args, *t, *u;
+       struct symtab *sp;
+
+       /* TODO check that it's a func proto */
+       if ((sp = lookup(addname("memcpy"), SNORMAL)))
+               return sp;
+
+       memcpy = block(NAME, NIL, NIL, 0, 0, 0);
+       memcpy->n_sp = sp = lookup(addname("memcpy"), SNORMAL);
+       defid(memcpy, EXTERN);
+
+       args = block(CM, block(CM,
+           block(NAME, NIL, NIL, VOID|PTR, 0, 0),
+           block(NAME, NIL, NIL, VOID|PTR, 0, 0), 0, 0, 0),
+           block(NAME, NIL, NIL, LONG, 0, 0), 0, 0, 0);
+
+       tymerge(t = block(TYPE, NIL, NIL, VOID|PTR, 0, 0),
+           (u = block(UMUL, block(CALL, memcpy, args, LONG, 0, 0),
+           NIL, LONG, 0, 0)));
+       tfree(t);
+       tfree(u);
+
+       return sp;
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+       int o = p->n_op;
+
+       if (o != FCON)
+               return;
+
+       /* Write float constants to memory */
+       /* Should be volontary per architecture */
+
+#if 0
+       setloc1(RDATA);
+       defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ?
+           ALDOUBLE : ALLDOUBLE );
+       deflab1(i = getlab());
+#endif
+       sp = tmpalloc(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->ssue = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       defloc(sp);
+       ninval(0, btdims[p->n_type].suesize, p);
+
+       p->n_op = NAME;
+       p->n_lval = 0;
+       p->n_sp = sp;
+
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * Return 1 if a variable of type "t" is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       return 1;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(PLUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ *
+ * XXX this relies on the host fp numbers representation
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+       struct symtab *q;
+       TWORD t;
+       int i;
+
+       t = p->n_type;
+       if (t > BTMASK)
+               p->n_type = t = INT; /* pointer */
+
+       if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+               uerror("element not constant");
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+               i = (p->n_lval >> 32);
+               p->n_lval &= 0xffffffff;
+               p->n_type = INT;
+               ninval(off, 32, p);
+               p->n_lval = i;
+               ninval(off+32, 32, p);
+               break;
+       case INT:
+       case UNSIGNED:
+               printf("\t.long 0x%x", (int)p->n_lval);
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)) {
+                               printf("+" LABFMT, q->soffset);
+                       } else
+                               printf("+%s",
+                                   q->soname ? q->soname : exname(q->sname));
+               }
+               printf("\n");
+               break;
+       case LDOUBLE:
+       case DOUBLE:
+               u.d = (double)p->n_dcon;
+               printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+               break;
+       case FLOAT:
+               u.f = (float)p->n_dcon;
+               printf("\t.long\t0x%x\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+       if (p == NULL)
+               return "";
+       return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+       }
+
+       return (type);
+}
+
+void
+calldec(NODE *f, NODE *a)
+{
+       struct symtab *q;
+       if (f->n_op == UMUL && f->n_left->n_op == PLUS &&
+           f->n_left->n_right->n_op == ICON)
+               q = f->n_left->n_right->n_sp;
+       else if (f->n_op == PLUS && f->n_right->n_op == ICON)
+               q = f->n_right->n_sp;
+       else {
+               fwalk(f, eprint, 0);
+               cerror("unknown function");
+               return;
+       }
+
+       printf("\t.import\t%s,code\n", q->soname ? q->soname : exname(q->sname));
+}
+
+void
+extdec(struct symtab *q)
+{
+       printf("\t.import\t%s,data\n", q->soname ? q->soname : exname(q->sname));
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off;
+
+       off = tsize(sp->stype, sp->sdf, sp->ssue);
+       off = (off + (SZCHAR - 1)) / SZCHAR;
+       printf("\t.%scomm\t", sp->sclass == STATIC ? "l" : "");
+       if (sp->slevel == 0)
+               printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off);
+       else
+               printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+static char *
+section2string(char *name)
+{
+       int len = strlen(name);
+
+       if (strncmp(name, "link_set", 8) == 0) {
+               const char postfix[] = ",\"aw\",@progbits";
+               char *s;
+
+               s = IALLOC(len + sizeof(postfix));
+               memcpy(s, name, len);
+               memcpy(s + len, postfix, sizeof(postfix));
+               return s;
+       }
+
+       return newstring(name, len);
+}
+
+char *nextsect;
+char *alias;
+int constructor;
+int destructor;
+
+#define        SSECTION        010000
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       char *a2 = pragtok(NULL);
+
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "section") == 0 && a2 != NULL) {
+               nextsect = section2string(a2);
+               return 1;
+       }
+       if (strcmp(str, "alias") == 0 && a2 != NULL) {
+               alias = tmpstrdup(a2);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+       if (alias != NULL && (sp->sclass != PARAM)) {
+               printf("\t.globl %s\n%s = %s\n", exname(sp->soname),
+                   exname(sp->soname), exname(alias));
+               alias = NULL;
+       }
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+               printf("\t.section .%ctors,\"aw\",@progbits\n"
+                   "\t.p2align 2\n\t.long %s\n\t.previous\n",
+                   constructor ? 'c' : 'd', exname(sp->sname));
+               constructor = destructor = 0;
+       }
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/hppa/local2.c b/lang/pcc/pcc/arch/hppa/local2.c
new file mode 100644 (file)
index 0000000..346767e
--- /dev/null
@@ -0,0 +1,880 @@
+/*     $Id: local2.c,v 1.31 2015/01/04 19:17:23 ragge Exp $    */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+void prtprolog(struct interpass_prolog *, int);
+int countargs(NODE *p, int *);
+void fixcalls(NODE *p, void *);
+
+static int stkpos;
+int p2calls;
+
+static const int rl[] =
+  { R0, R1, R1, R1, R1, R1, R31, R31, R31, R31,
+    R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18,
+    T1, T4, T3, T2, ARG3, ARG1, RET1 };
+static const int rh[] =
+  { R0, R31, T4, T3, T2, T1, T4, T3, T2, T1,
+    R18, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17,
+    T4, T3, T2, T1, ARG2, ARG0, RET0 };
+
+void
+deflab(int label)
+{
+       printf("\t.label\t" LABFMT "\n", label);
+}
+
+static int regoff[MAXREGS];
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+       int i;
+
+       /* if this functions calls nothing -- no frame is needed */
+       if (p2calls || p2maxautooff > 4) {
+               printf("\tcopy\t%%r3,%%r1\n\tcopy\t%%sp,%%r3\n");
+               if (addto < 0x2000)
+                       printf("\tstw,ma\t%%r1,%d(%%sp)\n", addto);
+               else if (addto < 0x802000)
+                       printf("\tstw,ma\t%%r1,8192(%%sp)\n"
+                           "\taddil\t%d-8192,%%sp\n"
+                           "\tcopy\t%%r1,%%sp\n", addto);
+               else
+                       comperr("too much local allocation");
+               if (p2calls)
+                       printf("\tstw\t%%rp,-20(%%r3)\n");
+       }
+
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       if (i <= R31)
+                               printf("\tstw\t%s,%d(%%r3)\n",
+                                   rnames[i], regoff[i]);
+                       else if (i <= RETD0)
+                               printf("\tstw\t%s,%d(%%r3)\n"
+                                   "\tstw\t%s,%d(%%r3)\n",
+                                   rnames[rl[i - RD0]], regoff[i] + 0,
+                                   rnames[rh[i - RD0]], regoff[i] + 4);
+                       else if (i <= FR31)
+                               printf("\tfstws\t%s,%d(%%r3)\n",
+                                   rnames[i], regoff[i]);
+                       else
+                               printf("\tfstds\t%s,%d(%%r3)\n",
+                                   rnames[i], regoff[i]);
+               }
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+       int i, addto, off;
+
+       addto = 32;
+       if (p2calls) {
+               i = p2calls - 1;
+               /* round up to 4 args */
+               if (i < 4)
+                       i = 4;
+               addto += i * 4;
+       }
+
+       for (off = 4, i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       regoff[i] = off;
+                       off += szty(PERMTYPE(i)) * SZINT/SZCHAR;
+               }
+       addto += off + p2maxautooff;
+       return (addto + 63) & ~63;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+
+       ftype = ipp->ipp_type;
+
+       /*
+        * We here know what registers to save and how much to 
+        * add to the stack.
+        */
+       addto = offcalc(ipp);
+       printf("\t.proc\ncallinfo frame=%d, save_rp, save_sp\n\t.entry\n",
+           addto);
+       prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       int i;
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       /* return from function code */
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       if (i <= R31)
+                               printf("\tldw\t%d(%%r3),%s\n",
+                                   regoff[i], rnames[i]);
+                       else if (i <= RETD0)
+                               printf("\tldw\t%d(%%r3),%s\n"
+                                   "\tldw\t%d(%%r3),%s\n",
+                                   regoff[i] + 0, rnames[rl[i - RD0]],
+                                   regoff[i] + 4, rnames[rh[i - RD0]]);
+                       else if (i <= FR31)
+                               printf("\tfldws\t%d(%%r3),%s\n",
+                                   regoff[i], rnames[i]);
+                       else
+                               printf("\tfldds\t%d(%%r3),%s\n",
+                                   regoff[i], rnames[i]);
+               }
+
+       if (p2calls || p2maxautooff > 4) {
+               if (p2calls)
+                       printf("\tldw\t-20(%%r3),%%rp\n");
+               printf("\tcopy\t%%r3,%%r1\n"
+                   "\tldw\t0(%%r3),%%r3\n"
+                   "\tbv\t%%r0(%%rp)\n"
+                   "\tcopy\t%%r1,%%sp\n");
+       } else
+               printf("\tbv\t%%r0(%%rp)\n\tnop\n");
+
+       printf("\t.exit\n\t.procend\n\t.size\t%s, .-%s\n",
+           ipp->ipp_name, ipp->ipp_name);
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       case EQ:
+               str = "=";
+               break;
+       case NE:
+               str = "<>";
+               break;
+       case LE:
+               str = "<";
+               break;
+       case LT:
+               str = "<=";
+               break;
+       case ULE:
+               str = "<<";
+               break;
+       case ULT:
+               str = "<<=";
+               break;
+       case GE:
+               str = ">=";
+               break;
+       case GT:
+               str = ">";
+               break;
+       case UGE:
+               str = ">>";
+               break;
+       case UGT:
+               str = ">>=";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case FLOAT:
+                       return(SZFLOAT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer", p->n_type);
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+static int
+argsiz(NODE *p)
+{
+       NODE *q;
+       TWORD t = p->n_type;
+
+       if (t < LONGLONG || t == FLOAT || t > BTMASK)
+               return 4;
+       if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+               return 8;
+       if (t == LDOUBLE)
+               return 8;       /* LDOUBLE is 16 */
+       if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == STARG)
+               return 4 + attr_find(p->n_right->n_ap, ATTR_P2STRUCT)->iarg(0);
+        /* perhaps it's down there somewhere -- let me take another look! */
+       if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == CALL) {
+               q = p->n_right->n_right->n_left->n_left->n_right;
+               if (q->n_op == STARG)
+                       return 4 + attr_find(q->n_ap, ATTR_P2STRUCT)->iarg(0);
+       }
+       comperr("argsiz %p", p);
+       return 0;
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int o = p->n_op;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       if (o >= ULE)
+               o -= (ULE-LE);
+       switch (o) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       if (cb1) {
+               p->n_op = cb1;
+               p->n_label = s;
+               expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n");
+               p->n_label = e;
+               p->n_op = o;
+       }
+       if (cb2) {
+               p->n_op = cb2;
+               expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n");
+               p->n_op = o;
+       }
+       expand(p, 0, "\tcomb,O\tAR,AL,LC\n\tnop\n");
+       deflab(s);
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       int n;
+
+       switch (c) {
+
+       case 'C':       /* after-call fixup */
+               n = p->n_qual;  /* args */
+               break;
+
+       case 'P':       /* returning struct-call setup */
+               n = p->n_qual;  /* args */
+               break;
+
+       case 'D':       /* Long long comparision */
+               twollcomp(p);
+               break;
+
+       case 'F':       /* struct as an arg */
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o == NAME || o == REG || o == ICON || o == OREG ||
+           (o == UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return(0);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       return 0;
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       if (isreg(p))
+               return SRDIR; /* Direct match */
+
+       return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       /* fix for L% and R% */
+       printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       CONSZ val = p->n_lval;
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "RR'%s-$global$", p->n_name);
+                       if (val)
+                               fprintf(fp, "+" CONFMT, val);
+               } else
+                       fprintf(fp, CONFMT, val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%s", rnames[rh[p->n_rval - RD0]]);
+               break;
+
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+
+       case ICON:
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       printf("LR'%s-$global$", p->n_name);
+                       if (p->n_lval != 0)
+                               printf("+" CONFMT, p->n_lval);
+               } else
+                       printf("L%%" CONFMT, p->n_lval >> 32);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       int r;
+       /* output an address, with offsets, from p */
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+
+       case ICON:
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       fprintf(io, "RR'%s-$global$", p->n_name);
+                       if (p->n_lval != 0)
+                               fprintf(io, "+" CONFMT, p->n_lval);
+               } else
+                       fprintf(io, "R%%" CONFMT, p->n_lval);
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               if (p->n_name[0] != '\0') {
+                       fprintf(io, "RR'%s-$global$", p->n_name);
+                       if (p->n_lval != 0)
+                               fprintf(io, "+" CONFMT, p->n_lval);
+               } else
+                       fprintf(io, "%d", (int)p->n_lval);
+               if (R2TEST(r)) {
+                       fprintf(io, "%s(%s)", rnames[R2UPK1(r)],
+                           rnames[R2UPK2(r)]);
+               } else
+                       fprintf(io, "(%s)", rnames[p->n_rval]);
+               return;
+       case REG:
+               if (RD0 <= p->n_rval && p->n_rval <= RETD0)
+                       fprintf(io, "%s", rnames[rl[p->n_rval - RD0]]);
+               else
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+/* not used */
+void
+cbgen(int o, int lab)
+{
+}
+
+int
+countargs(NODE *p, int *n)
+{
+       int sz;
+       
+       if (p->n_op == CM) {
+               countargs(p->n_left, n);
+               countargs(p->n_right, n);
+               return *n;
+       }
+
+       sz = argsiz(p) / 4;
+       if (*n % (sz > 4? 4 : sz))
+               (*n)++; /* XXX */
+
+       return *n += sz;
+}
+
+void
+fixcalls(NODE *p, void *arg)
+{
+       int n, o;
+
+       /* Prepare for struct return by allocating bounce space on stack */
+       switch (o = p->n_op) {
+       case STCALL:
+       case USTCALL:
+               if (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)
+                   + p2autooff > stkpos)
+                       stkpos = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + p2autooff;
+               /* FALLTHROGH */
+       case CALL:
+       case UCALL:
+               n = 0;
+               n = 1 + countargs(p->n_right, &n);
+               if (n > p2calls)
+                       p2calls = n;
+               break;
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       stkpos = p2autooff;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               switch (ip->type) {
+               case IP_PROLOG:
+                       p2calls = 0;
+                       break;
+
+               case IP_NODE:
+                       walkf(ip->ip_node, fixcalls, 0);
+                       break;
+               }
+       }
+       if (stkpos > p2autooff)
+               p2autooff = stkpos;
+       if (stkpos > p2maxautooff)
+               p2maxautooff = stkpos;
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ipole)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+       int sl, sh, dl, dh;
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+               sl = rl[s-RD0];
+               sh = rh[s-RD0];
+               dl = rl[d-RD0];
+               dh = rh[d-RD0];
+
+#define        SW(x,y) { int i = x; x = y; y = i; }
+               if (sl == dh || sh == dl) {
+                       /* Swap if moving to itself */
+                       SW(sl, sh);
+                       SW(dl, dh);
+               }
+               if (sl != dl)
+                       printf("\tcopy\t%s,%s\n", rnames[sl], rnames[dl]);
+               if (sh != dh)
+                       printf("\tcopy\t%s,%s\n", rnames[sh], rnames[dh]);
+               break;
+       case FLOAT:
+               printf("\tfcpy,sgl\t%s,%s\n", rnames[s], rnames[d]);
+               break;
+       case DOUBLE:
+       case LDOUBLE:
+               printf("\tfcpy,dbl\t%s,%s\n", rnames[s], rnames[d]);
+               break;
+       default:
+               printf("\tcopy\t%s,%s\n", rnames[s], rnames[d]);
+       }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num;
+
+       switch (c) {
+       case CLASSA:
+               num = 2 * r[CLASSB];
+               num += r[CLASSA];
+               return num < 28;
+       case CLASSB:
+               num = r[CLASSA];
+               num += r[CLASSB] * 2;
+               return num < 28;
+       case CLASSC:
+               num = (r[CLASSD] > 8? 8 : r[CLASSD]) * 2;
+               num += r[CLASSC];
+               return num < 28;
+       case CLASSD:
+               num = (r[CLASSC] + 1) / 2;
+               num += r[CLASSD];
+               return num < 28;
+       }
+       return 0; /* XXX gcc */
+}
+
+char * rnames[MAXREGS] = {
+       "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9",
+       "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18",
+       "%t4", "%t3", "%t2", "%t1", "%arg3", "%arg2", "%arg1", "%arg0", "%dp",
+       "%ret0", "%ret1", "%sp", "%r31",
+       "%rd0", "%rd1", "%rd2", "%rd3", "%rd4", "%rd5", "%rd6", "%rd7",
+       "%rd8", "%rd9", "%rd10", "%rd11", "%rd12", "%rd13", "%rd14", "%rd15",
+       "%rd16", "%rd17", "%rd18", "%rd19", "%rd20", "%rd21", "%rd22", "%rd23",
+       "%rd24", "%td4", "%td3", "%td2", "%td1", "%ad1", "%ad0", "%retd0",
+       "%fr0", "%fr4", "%fr5", "%fr6", "%fr7", "%fr8", "%fr9", "%fr10",
+       "%fr11", "%fr12", "%fr13", "%fr14", "%fr15", "%fr16", "%fr17", "%fr18",
+       "%fr19", "%fr20", "%fr21", "%fr22", "%fr23", "%fr24", "%fr25", "%fr26",
+       "%fr27", "%fr28", "%fr29", "%fr30", "%fr31",
+       "%fr0l", "%fr0r", "%fr4l", "%fr4r", "%fr5l", "%fr5r", "%fr6l", "%fr6r",
+       "%fr7l", "%fr7r", "%fr8l", "%fr8r", "%fr9l", "%fr9r",
+       "%fr10l", "%fr10r", "%fr11l", "%fr11r", "%fr12l", "%fr12r",
+       "%fr13l", "%fr13r", "%fr14l", "%fr14r", "%fr15l", "%fr15r",
+       "%fr16l", "%fr16r", "%fr17l", "%fr17r", "%fr18l", "%fr18r",
+#ifdef __hppa64__
+       "%fr19l", "%fr19r",
+       "%fr20l", "%fr20r", "%fr21l", "%fr21r", "%fr22l", "%fr22r",
+       "%fr23l", "%fr23r", "%fr24l", "%fr24r", "%fr25l", "%fr25r",
+       "%fr26l", "%fr26r", "%fr27l", "%fr27r", "%fr28l", "%fr28r",
+       "%fr29l", "%fr29r", "%fr30l", "%fr30r", "%fr31l", "%fr31r",
+#endif
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+               return CLASSB;
+       case FLOAT:
+               return CLASSC;
+       case DOUBLE:
+       case LDOUBLE:
+               return CLASSD;
+       default:
+               return CLASSA;
+       }
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 64;
+
+       p->n_qual = size;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               size += argsiz(p->n_right);
+       size += argsiz(p);
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       int o = p->n_op;
+
+       switch (shape) {
+       case SFUNCALL:
+               if (o == STCALL || o == USTCALL)
+                       return SRREG;
+               break;
+       case SPIMM:
+               if (o != ICON || p->n_name[0] ||
+                   p->n_lval < -31 || p->n_lval >= 32)
+                       break;
+               return SRDIR;
+       case SPICON:
+               if (o != ICON || p->n_name[0] ||
+                   p->n_lval < -1024 || p->n_lval >= 1024)
+                       break;
+               return SRDIR;
+       case SPCNHW:
+               if (o != ICON || p->n_name[0] || (p->n_lval & 0xffffffffLL))
+                       break;
+               return SRDIR;
+       case SPCNLW:
+               if (o != ICON || p->n_name[0] || (p->n_lval & ~0xffffffffLL))
+                       break;
+               return SRDIR;
+       case SPCNHI:
+               if (o != ICON || p->n_name[0] || (p->n_lval & ~0xfffff800LL))
+                       break;
+               return SRDIR;
+       case SPCON:
+               if (o != ICON || p->n_name[0] ||
+                   p->n_lval < -8192 || p->n_lval >= 8192)
+                       break;
+               return SRDIR;
+       case SPNAME:
+               if (o != ICON || !p->n_name[0])
+                       break;
+               return SRDIR;
+       }
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/hppa/macdefs.h b/lang/pcc/pcc/arch/hppa/macdefs.h
new file mode 100644 (file)
index 0000000..cab29ca
--- /dev/null
@@ -0,0 +1,472 @@
+/*     $Id: macdefs.h,v 1.22 2016/03/05 15:53:04 ragge Exp $   */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define        makecc(val,i)   (lastcon = (lastcon<<8)|((val<<24)>>24))
+
+#define        ARGINIT         (32*8)  /* bits below fp where args start */
+#define        AUTOINIT        (4*8)   /* bits above fp where locals start */
+
+/*
+ * storage sizes
+ */
+#define        SZCHAR          8
+#define        SZBOOL          8
+#define        SZINT           32
+#define        SZFLOAT         32
+#define        SZDOUBLE        64
+#define        SZLDOUBLE       64      /* or later 128 */
+#define        SZLONG          32
+#define        SZSHORT         16
+#define        SZLONGLONG      64
+#define        SZPOINT(t)      32
+
+/*
+ * alignment requirements
+ */
+#define        ALCHAR          8
+#define        ALBOOL          8
+#define        ALINT           32
+#define        ALFLOAT         32
+#define        ALDOUBLE        64
+#define        ALLDOUBLE       64      /* 128 later */
+#define        ALLONG          32
+#define        ALLONGLONG      32
+#define        ALSHORT         16
+#define        ALPOINT         32
+#define        ALSTRUCT        32
+#define        ALSTACK         64
+
+/*
+ * type value limits
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         (-0x7fffffff-1)
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffff
+#define        MIN_LONG        MIN_INT
+#define        MAX_LONG        MAX_INT
+#define        MAX_ULONG       MAX_UNSIGNED
+#define        MIN_LONGLONG    (-0x7fffffffffffffffLL-1)
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+#undef CHAR_UNSIGNED
+#define        BOOL_TYPE       CHAR
+
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define        CONFMT  "%lld"          /* format for printing constants */
+#define        LABFMT  ".L%d"          /* format for printing labels */
+#define        STABLBL ".LL%d"         /* format for stab (debugging) labels */
+
+#undef BACKAUTO        /* stack grows upwards */
+#undef BACKTEMP        /* stack grows upwards */
+
+#define        FIELDOPS        /* have bit field ops */
+#define        TARGET_ENDIAN   TARGET_BE
+#define        TARGET_FLT_EVAL_METHOD  0       /* all as their type */
+
+#define        BYTEOFF(x)      ((x)&03)
+#define        wdal(k)         (BYTEOFF(k)==0)
+
+#define        STOARG(p)
+#define        STOFARG(p)
+#define        STOSTARG(p)
+
+#define        szty(t) (((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : \
+           (t) == LDOUBLE ? 2 : 1)
+
+#define        R0      0
+#define        R1      1
+#define        RP      2
+#define        FP      3
+#define        R4      4
+#define        R5      5
+#define        R6      6
+#define        R7      7
+#define        R8      8
+#define        R9      9
+#define        R10     10
+#define        R11     11
+#define        R12     12
+#define        R13     13
+#define        R14     14
+#define        R15     15
+#define        R16     16
+#define        R17     17
+#define        R18     18
+#define        T4      19
+#define        T3      20
+#define        T2      21
+#define        T1      22
+#define        ARG3    23
+#define        ARG2    24
+#define        ARG1    25
+#define        ARG0    26
+#define        DP      27
+#define        RET0    28
+#define        RET1    29
+#define        SP      30
+#define        R31     31
+
+/* double regs overlay */
+#define        RD0     32      /* r0:r0 */
+#define        RD1     33      /* r1:r31 */
+#define        RD2     34      /* r1:t4 */
+#define        RD3     35      /* r1:t3 */
+#define        RD4     36      /* r1:t2 */
+#define        RD5     37      /* r1:t1 */
+#define        RD6     38      /* r31:t4 */
+#define        RD7     39      /* r31:t3 */
+#define        RD8     40      /* r31:t2 */
+#define        RD9     41      /* r31:t1 */
+#define        RD10    42      /* r4:r18 */
+#define        RD11    43      /* r5:r4 */
+#define        RD12    44      /* r6:r5 */
+#define        RD13    45      /* r7:r6 */
+#define        RD14    46      /* r8:r7 */
+#define        RD15    47      /* r9:r8 */
+#define        RD16    48      /* r10:r9 */
+#define        RD17    49      /* r11:r10 */
+#define        RD18    50      /* r12:r11 */
+#define        RD19    51      /* r13:r12 */
+#define        RD20    52      /* r14:r13 */
+#define        RD21    53      /* r15:r14 */
+#define        RD22    54      /* r16:r15 */
+#define        RD23    55      /* r17:r16 */
+#define        RD24    56      /* r18:r17 */
+#define        TD4     57      /* t1:t4 */
+#define        TD3     58      /* t4:t3 */
+#define        TD2     59      /* t3:t2 */
+#define        TD1     60      /* t2:t1 */
+#define        AD2     61      /* arg3:arg2 */
+#define        AD1     62      /* arg1:arg0 */
+#define        RETD0   63      /* ret1:ret0 */
+
+/* FPU regs */
+#define        FR0     64
+#define        FR4     65
+#define        FR5     66
+#define        FR6     67
+#define        FR7     68
+#define        FR8     69
+#define        FR9     70
+#define        FR10    71
+#define        FR11    72
+#define        FR12    73
+#define        FR13    74
+#define        FR14    75
+#define        FR15    76
+#define        FR16    77
+#define        FR17    78
+#define        FR18    79
+#define        FR19    80
+#define        FR20    81
+#define        FR21    82
+#define        FR22    83
+#define        FR23    84
+#define        FR24    85
+#define        FR25    86
+#define        FR26    87
+#define        FR27    88
+#define        FR28    89
+#define        FR29    90
+#define        FR30    91
+#define        FR31    92
+
+#define        FR0L    93
+#define        FR0R    94
+#define        FR4L    95
+#define        FR4R    96
+#define        FR5L    97
+#define        FR5R    98
+#define        FR6L    99
+#define        FR6R    100
+#define        FR7L    101
+#define        FR7R    102
+#define        FR8L    103
+#define        FR8R    104
+#define        FR9L    105
+#define        FR9R    106
+#define        FR10L   107
+#define        FR10R   108
+#define        FR11L   109
+#define        FR11R   110
+#define        FR12L   111
+#define        FR12R   112
+#define        FR13L   113
+#define        FR13R   114
+#define        FR14L   115
+#define        FR14R   116
+#define        FR15L   117
+#define        FR15R   118
+#define        FR16L   119
+#define        FR16R   120
+#define        FR17L   121
+#define        FR17R   122
+#define        FR18L   123
+#define        FR18R   124
+#ifdef __hppa64__
+#define        FR19L   125
+#define        FR19R   126
+#define        FR20L   127
+#define        FR20R   128
+#define        FR21L   129
+#define        FR21R   130
+#define        FR22L   131
+#define        FR22R   132
+#define        FR23L   133
+#define        FR23R   134
+#define        FR24L   135
+#define        FR24R   136
+#define        FR25L   137
+#define        FR25R   138
+#define        FR26L   139
+#define        FR26R   140
+#define        FR27L   141
+#define        FR27R   142
+#define        FR28L   143
+#define        FR28R   144
+#define        FR29L   145
+#define        FR29R   146
+#define        FR30L   147
+#define        FR30R   148
+#define        FR31L   149
+#define        FR31R   150
+
+#define        MAXREGS 151
+#else
+#define        MAXREGS 125
+#endif
+
+#define        RSTATUS \
+       0, SAREG|TEMPREG, 0, 0, SAREG|PERMREG, SAREG|PERMREG,           \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|PERMREG,                                                  \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       0, SAREG|TEMPREG, SAREG|TEMPREG, 0, SAREG|TEMPREG,              \
+       /* double overlays */                                           \
+       0,                                                              \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,                \
+       /* double-precision floats */                                   \
+       0,                                                              \
+       SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,     \
+       SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,     \
+       SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG,     \
+       SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG,     \
+       SDREG|PERMREG, SDREG|PERMREG,                                   \
+       SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,     \
+       SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,     \
+       SDREG|TEMPREG, SDREG|TEMPREG,                                   \
+       /* single-precision floats */                                   \
+       0, 0,                                                           \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,
+#ifdef __hppa64__
+       SCREG, SCREG,           \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,
+#endif
+
+#define        ROVERLAP \
+       { -1 },                         \
+       { RD1, RD2, RD3, RD4, RD5, -1 },\
+       { -1 }, { -1 },                 \
+       { RD10, RD11, -1 },             \
+       { RD11, RD12, -1 },             \
+       { RD12, RD13, -1 },             \
+       { RD13, RD14, -1 },             \
+       { RD14, RD15, -1 },             \
+       { RD15, RD16, -1 },             \
+       { RD16, RD17, -1 },             \
+       { RD17, RD18, -1 },             \
+       { RD18, RD19, -1 },             \
+       { RD19, RD20, -1 },             \
+       { RD20, RD21, -1 },             \
+       { RD21, RD22, -1 },             \
+       { RD22, RD23, -1 },             \
+       { RD23, RD24, -1 },             \
+       { RD24, RD10, -1 },             \
+       { TD1, TD4, -1 },               \
+       { TD3, TD2, -1 },               \
+       { TD1, TD2, -1 },               \
+       { TD1, TD4, -1 },               \
+       { AD2, -1 }, { AD2, -1 },       \
+       { AD1, -1 }, { AD1, -1 },       \
+       { -1 },                         \
+       { RETD0, -1 }, { RETD0, -1 },   \
+       { -1 },                         \
+       { RD1, RD5, RD6, RD7, RD8, -1 },\
+       { -1 },                         \
+       { R1, R31, -1 },                \
+       { R1, T4, -1 },                 \
+       { R1, T3, -1 },                 \
+       { R1, T2, -1 },                 \
+       { R1, T1, -1 },                 \
+       { R31, T4, -1 },                \
+       { R31, T3, -1 },                \
+       { R31, T2, -1 },                \
+       { R31, T1, -1 },                \
+       { R4, R18, -1 },                \
+       { R5, R4, -1 },                 \
+       { R6, R5, -1 },                 \
+       { R7, R6, -1 },                 \
+       { R8, R7, -1 },                 \
+       { R9, R8, -1 },                 \
+       { R10, R9, -1 },                \
+       { R11, R10, -1 },               \
+       { R12, R11, -1 },               \
+       { R13, R12, -1 },               \
+       { R14, R15, -1 },               \
+       { R15, R14, -1 },               \
+       { R16, R15, -1 },               \
+       { R17, R16, -1 },               \
+       { R18, R17, -1 },               \
+       { T1, T4, -1 },                 \
+       { T4, T3, -1 },                 \
+       { T3, T2, -1 },                 \
+       { T2, T1, -1 },                 \
+       { ARG3, ARG2, -1 },             \
+       { ARG1, ARG0, -1 },             \
+       { RET1, RET0, -1 },             \
+       { -1 },                         \
+       { FR4L, FR4R, -1 },             \
+       { FR5L, FR5R, -1 },             \
+       { FR6L, FR6R, -1 },             \
+       { FR7L, FR7R, -1 },             \
+       { FR8L, FR8R, -1 },             \
+       { FR9L, FR9R, -1 },             \
+       { FR10L, FR10R, -1 },           \
+       { FR11L, FR11R, -1 },           \
+       { FR12L, FR12R, -1 },           \
+       { FR13L, FR13R, -1 },           \
+       { FR14L, FR14R, -1 },           \
+       { FR15L, FR15R, -1 },           \
+       { FR16L, FR16R, -1 },           \
+       { FR17L, FR17R, -1 },           \
+       { FR18L, FR18R, -1 },           \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 }, { -1 },                 \
+       { FR4, -1 }, { FR4, -1 },       \
+       { FR5, -1 }, { FR5, -1 },       \
+       { FR6, -1 }, { FR6, -1 },       \
+       { FR7, -1 }, { FR7, -1 },       \
+       { FR8, -1 }, { FR8, -1 },       \
+       { FR9, -1 }, { FR9, -1 },       \
+       { FR10, -1 }, { FR10, -1 },     \
+       { FR11, -1 }, { FR11, -1 },     \
+       { FR12, -1 }, { FR12, -1 },     \
+       { FR13, -1 }, { FR13, -1 },     \
+       { FR14, -1 }, { FR14, -1 },     \
+       { FR15, -1 }, { FR15, -1 },     \
+       { FR16, -1 }, { FR16, -1 },     \
+       { FR17, -1 }, { FR17, -1 },     \
+       { FR18, -1 }, { FR18, -1 },
+#ifdef __hppa64__
+       { FR19, -1 }, { FR19, -1 },     \
+       { FR20, -1 }, { FR20, -1 },     \
+       { FR21, -1 }, { FR21, -1 },     \
+       { FR22, -1 }, { FR22, -1 },     \
+       { FR23, -1 }, { FR23, -1 },     \
+       { FR24, -1 }, { FR24, -1 },     \
+       { FR25, -1 }, { FR25, -1 },     \
+       { FR26, -1 }, { FR26, -1 },     \
+       { FR27, -1 }, { FR27, -1 },     \
+       { FR28, -1 }, { FR28, -1 },     \
+       { FR29, -1 }, { FR29, -1 },     \
+       { FR30, -1 }, { FR30, -1 },     \
+       { FR31, -1 }, { FR31, -1 },
+#endif
+
+#define        PCLASS(p)       \
+       (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SBREG : \
+       (p->n_type == FLOAT ? SCREG : \
+       (p->n_type == DOUBLE || p->n_type == LDOUBLE ? SDREG : SAREG)))
+
+#define        NUMCLASS        4       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define        PERMTYPE(x) ((x) < 32? INT : ((x) < 64? LONGLONG : ((x) < 93? LDOUBLE : FLOAT)))
+#define        GCLASS(x) ((x) < 32? CLASSA : ((x) < 64? CLASSB : ((x) < 93? CLASSD : CLASSC)))
+#define        DECRA(x,y)      (((x) >> (y*8)) & 255)  /* decode encoded regs */
+#define        ENCRD(x)        (x)                     /* Encode dest reg in n_reg */
+#define        ENCRA1(x)       ((x) << 8)              /* A1 */
+#define        ENCRA2(x)       ((x) << 16)             /* A2 */
+#define        ENCRA(x,y)      ((x) << (8+y*8))        /* encode regs in int */
+#define        RETREG(x)       (x == LONGLONG || x == ULONGLONG ? RETD0 : \
+                        x == FLOAT? FR4L : \
+                        x == DOUBLE || x == LDOUBLE ? FR4 : RET0)
+
+#define        FPREG   FP      /* frame pointer */
+#define        STKREG  SP      /* stack pointer */
+
+#define        MYREADER(p)     myreader(p)
+#define        MYCANON(p)      mycanon(p)
+#define        MYOPTIM
+
+#define        SFUNCALL        (MAXSPECIAL+1)  /* struct assign after function call */
+#define        SPCNHI          (MAXSPECIAL+2)  /* high 21bits constant */
+#define        SPCON           (MAXSPECIAL+3)  /* smaller constant */
+#define        SPICON          (MAXSPECIAL+4)  /* even smaller constant */
+#define        SPCNHW          (MAXSPECIAL+5)  /* LL const w/ 0 in low word */
+#define        SPCNLW          (MAXSPECIAL+6)  /* LL const w/ 0 in high word */
+#define        SPIMM           (MAXSPECIAL+7)  /* immidiate const for depi/comib */
+#define        SPNAME          (MAXSPECIAL+8)  /* ext symbol reference load/store */
diff --git a/lang/pcc/pcc/arch/hppa/order.c b/lang/pcc/pcc/arch/hppa/order.c
new file mode 100644 (file)
index 0000000..af8ed0f
--- /dev/null
@@ -0,0 +1,216 @@
+/*     $Id: order.c,v 1.10 2011/06/05 08:54:42 plunky Exp $    */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *r;
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+       r = p->n_right;
+       if (p->n_op == PLUS || p->n_op == MINUS) {
+               if (r->n_op == ICON) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+       NODE *p, *r;
+
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+
+       p = q->n_left;
+       if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
+           r->n_right->n_op == ICON && r->n_right->n_lval == 2 &&
+           p->n_left->n_op == REG && r->n_left->n_op == REG) {
+               q->n_op = OREG;
+               q->n_lval = 0;
+               q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0);
+               tfree(p);
+       }
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on hppa */
+       if (shape & SOREG)
+               return SOREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+
+       return 0;
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p,%s)\n", p, prcook(cookie));
+
+       if (p->n_left->n_op == FLD && !isreg(p->n_left->n_left)) {
+               NODE *l, *r;
+               int reg;
+
+               geninsn(p->n_left->n_left, INAREG);
+
+               reg = DECRA(p->n_left->n_left->n_reg, 0);
+               l = tcopy(p->n_left->n_left);
+               p->n_left->n_left->n_op = REG;
+               p->n_left->n_left->n_rval = reg;
+               p->n_left->n_left->n_lval = 0;
+               r = tcopy(p->n_left->n_left);
+
+               geninsn(p->n_left, INAREG);
+               l = mkbinode(ASSIGN, l, r, l->n_type);
+               geninsn(l, INAREG);
+               return (1);
+       }
+
+       return (0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setuni(%p,%s)\n", p, prcook(cookie));
+
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on hppa */
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[5], *s = &r[4];
+        
+       *s = -1;
+       if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL ||
+           p->n_op == FORTCALL)
+               return s;
+
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               if (p->n_right->n_op == ASSIGN &&
+                   p->n_right->n_left->n_op == REG)
+                       *--s = p->n_right->n_left->n_rval;
+
+       if (p->n_op == ASSIGN &&
+           p->n_left->n_op == REG)
+               *--s = p->n_left->n_rval;
+
+       return s;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/hppa/table.c b/lang/pcc/pcc/arch/hppa/table.c
new file mode 100644 (file)
index 0000000..4dc3947
--- /dev/null
@@ -0,0 +1,1015 @@
+/*     $Id: table.c,v 1.16 2012/09/18 10:57:10 mickey Exp $    */
+/*     $OpenBSD: table.c,v 1.2 2007/12/19 20:19:54 otto Exp $  */
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+
+#define        TLL             TLONGLONG|TULONGLONG
+#define        ANYSIGNED       TINT|TLONG|TSHORT|TCHAR
+#define        ANYUSIGNED      TUNSIGNED|TULONG|TUSHORT|TUCHAR
+#define        ANYFIXED        ANYSIGNED|ANYUSIGNED
+#define        TUWORD          TUNSIGNED|TULONG
+#define        TSWORD          TINT|TLONG
+#define        TWORD           TUWORD|TSWORD
+#define        THWORD          TUSHORT|TSHORT
+#define        TBYTE           TUCHAR|TCHAR
+
+#define        SHINT   SAREG   /* char, short and int */
+#define        ININT   INAREG
+#define        SHLL    SBREG   /* shape for long long */
+#define        INLL    INBREG
+#define        SHFL    SCREG   /* shape for float */
+#define        INFL    INCREG
+#define        SHDBL   SDREG   /* shape for double */
+#define        INDBL   INDREG
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "", },
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert int,short,char <-> int,short,char. */
+{ SCONV,       ININT,
+       SHINT,  TBYTE,
+       SHINT,  TBYTE,
+               0,      RLEFT,
+               "", },
+
+{ SCONV,       ININT,
+       SHINT,  THWORD,
+       SHINT,  THWORD,
+               0,      RLEFT,
+               "", },
+
+{ SCONV,       ININT,
+       SHINT,  TWORD,
+       SHINT,  TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert pointers to int. */
+{ SCONV,       ININT,
+       SHINT,  TWORD|TPOINT,
+       SANY,   TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV,       INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               0,      RLEFT,
+               "", },
+
+/* convert pointers to pointers. */
+{ SCONV,       ININT,
+       SHINT,  TPOINT,
+       SANY,   TPOINT,
+               0,      RLEFT,
+               "", },
+
+/* convert double <-> ldouble. nothing to do here (or support quads later) */
+{ SCONV,       INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               "", },
+
+/* convert float -> double */
+{ SCONV,       INFL,
+       SHFL,   TFLOAT,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               0,      0,
+               "\tfcnvff,sgl,dbl AL,AR\n", },
+
+/* convert double -> float */
+{ SCONV,       INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHFL,   TFLOAT,
+               0,      0,
+               "\tfcnvff,dbl,sgl\tAL,AR\n", },
+
+/* convert int,short,char to (u)long long */
+{ SCONV,       INLL,
+       SHINT,  ANYSIGNED,
+       SANY,   TLL,
+               NBREG,  RESC1,
+               "\tcopy\tAL,A1\n"
+               "\textrs\tAL,0,1,U1\n", },
+
+/* convert unsigned int,short,char to (u)long long */
+{ SCONV,       INLL,
+       SHINT,  TWORD,
+       SANY,   TLL,
+               NBREG,  RESC1,
+               "\tcopy\tAL,A1\n"
+               "\tcopy\t%r0,U1\n", },
+
+/* convert int,short,char (in memory) to float */
+{ SCONV,       INFL,
+       SOREG,  ANYSIGNED,
+       SHFL,   TFLOAT,
+               NCREG,  RESC1,
+               "\tfldws\tAL,A1\n"
+               "\tfcnvxf,sgl,sgl\tA1,A1\n", },
+
+/* convert int,short,char (in memory) to double */
+{ SCONV,       INDBL,
+       SOREG,  TSWORD,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "\tfldws\tAL,A1\n"
+               "\tfcnvxf,sgl,dbl\tA1,A1\n", },
+
+/* convert (u)long (in memory) to double */
+{ SCONV,       INDBL,
+       SOREG,  TLL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "\tfldds\tAL,A1\n"
+               "\tfcnvxf,dbl,dbl\tA1,A1\n", },
+
+/* convert int,short,char (in register) to float */
+{ SCONV,       INFL,
+       SHINT,  TSWORD,
+       SHFL,   TFLOAT,
+               NCREG,  RESC1,
+               "\tstw,ma\tAL,4(%sp)\n"
+               "\tfldws,ma\t-4(%sp),A1\n"
+               "\tfcnvxf,sgl,sgl\tA1,A1\n", },
+
+/* convert int,short,char (in register) to double */
+{ SCONV,       INDBL,
+       SHINT,  TSWORD,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "\tstw,ma\tAL,4(%sp)\n"
+               "\tfldws,mb\t-4(%sp),AR\n"
+               "\tfcnvxf,sgl,dbl\tA1,A1\n", },
+
+/* convert (u)long (in register) to double */
+{ SCONV,       INDBL,
+       SHLL,   TLL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "\tldo\t8(%sp),%sp\n"
+               "\tstw\tAL,-8(%sp)\n"
+               "\tstw\tUL,-4(%sp)\n"
+               "\tfldds,mb\t-8(%sp),A1\n"
+               "\tfcnvxf,dbl,dbl\tA1,A1\n", },
+
+/* convert char to (unsigned) short/int. */
+{ SCONV,       ININT,
+       SAREG,  TCHAR,
+       SAREG,  THWORD|TWORD,
+               NASL|NAREG,     RESC1,
+               "\textrs\tAL,31,8,A1\n", },
+
+/* convert unsigned char to (unsigned) short/int. */
+{ SCONV,       ININT,
+       SAREG,  TUCHAR,
+       SAREG,  THWORD|TWORD,
+               NASL|NAREG,     RESC1,
+               "\textru\tAL,31,8,A1\n", },
+
+/* convert char to (unsigned) long long. */
+{ SCONV,       INLL,
+       SAREG,  TCHAR,
+       SBREG,  TLL,
+               NBSL|NBREG,     RESC1,
+               "\textrs\tAL,31,8,A1\n\textrs\tA1,0,1,U1", },
+
+/* convert unsigned char to (unsigned) long long. */
+{ SCONV,       INLL,
+       SAREG,  TUCHAR,
+       SBREG,  TLL,
+               NBSL|NBREG,     RESC1,
+               "\textru\tAL,31,8,A1\n\tcopy\t%r0,U1", },
+
+/* convert short to (unsigned) int. */
+{ SCONV,       ININT,
+       SAREG,  TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "\textrs\tAL,31,16,A1\n", },
+
+/* convert unsigned short to (unsigned) int. */
+{ SCONV,       ININT,
+       SAREG,  TUSHORT,
+       SAREG,  THWORD,
+               NASL|NAREG,     RESC1,
+               "\textru\tAL,31,16,A1\n", },
+
+/* convert short to (unsigned) long long. */
+{ SCONV,       INLL,
+       SAREG,  TSHORT,
+       SBREG,  TLL,
+               NBSL|NBREG,     RESC1,
+               "\textrs\tAL,31,16,A1\n\textrs\tA1,0,1,U1", },
+
+/* convert unsigned short to (unsigned) long long. */
+{ SCONV,       INLL,
+       SAREG,  TUSHORT,
+       SBREG,  TLL,
+               NBSL|NBREG,     RESC1,
+               "\textru\tAL,31,16,A1\n\tcopy\t%r0,U1", },
+
+/* convert int,short,char (in memory) to int,short,char */
+{ SCONV,       ININT,
+       SOREG,  TBYTE,
+       SHINT,  TBYTE|TPOINT,
+               NAREG|NASL,     RESC1,
+               "\tldb\tAL,A1\n", },
+
+{ SCONV,       ININT,
+       SOREG,  THWORD,
+       SHINT,  THWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "\tldh\tAL,A1\n", },
+
+{ SCONV,       ININT,
+       SOREG,  TWORD,
+       SHINT,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "\tldw\tAL,A1\n", },
+
+/* convert (u)long long (in register) to int,short,char */
+{ SCONV,       ININT,
+       SHLL,   TLL,
+       SHINT,  ANYFIXED,
+               NAREG|NASL,     RESC1,
+               "\tcopy\tAL,A1\n", },
+
+/* convert (u)long (in memory) to int,short,char */
+{ SCONV,       ININT,
+       SOREG,  TLL,
+       SHINT,  ANYFIXED,
+               NAREG|NASL,     RESC1,
+               "\tldw\tAL,A1\n", },
+
+/* convert float (in register) to (u)int */
+{ SCONV,       ININT,
+       SHFL,   TFLOAT,
+       SHINT,  TWORD,
+               NAREG,  RESC1,
+               "\tfcnvfxt,sgl,sgl\tAL,AL\n"
+               "\tfstws,ma\tAL,4(%sp)\n"
+               "\tldw,mb\t-4(%sp),A1\n", },
+
+/* convert double (in register) to (u)int */
+{ SCONV,       ININT,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHINT,  TWORD,
+               NCREG|NCSL|NAREG,       RESC1,
+               "\tfcnvfxt,dbl,sgl\tAL,A1\n"
+               "\tfstws,ma\tA1,4(%sp)\n"
+               "\tldw,mb\t-4(%sp),A2\n", },
+
+/* convert float (in register) to (u)long */
+{ SCONV,       INLL,
+       SHFL,   TFLOAT,
+       SHLL,   TLL,
+               NDREG|NDSL|NBREG,       RESC1,
+               "\tfcnvfxt,sgl,dbl\tAL,A1\n"
+               "\tfstds,ma\tA1,8(%sp)\n"
+               "\tldw\t-8(%sp),A2\n"
+               "\tldw\t-4(%sp),U2\n"
+               "\tldo\t-8(%sp),%sp)\n", },
+
+/* convert double (in register) to (u)long */
+{ SCONV,       INLL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHLL,   TLL,
+               NBREG,  RESC1,
+               "\tfcnvfxt,dbl,dbl\tAL,AL\n"
+               "\tfstds,ma\tAL,8(%sp)\n"
+               "\tldw\t-8(%sp),A1\n"
+               "\tldw\t-4(%sp),U1\n"
+               "\tldo\t-8(%sp),%sp)\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ CALL,                ININT,
+       SAREG,  TANY,
+       SHINT,  ANYFIXED|TPOINT,
+               NAREG|NASL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ UCALL,       ININT,
+       SAREG,  TANY,
+       SHINT,  ANYFIXED|TPOINT,
+               NAREG|NASL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ CALL,                INLL,
+       SAREG,  TANY,
+       SHLL,   TLL,
+               NBREG|NBSL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ UCALL,       INLL,
+       SAREG,  TANY,
+       SHLL,   TLL,
+               NBREG|NBSL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ CALL,                INFL,
+       SAREG,  TANY,
+       SHFL,   TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ UCALL,       INFL,
+       SAREG,  TANY,
+       SHFL,   TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ CALL,                INDBL,
+       SAREG,  TANY,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+{ UCALL,       INDBL,
+       SAREG,  TANY,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "ZP\tblr\t%r0, %rp\n"
+               "\tbv,n\t%r0(AL)\n"
+               "\tnop\nZC",    },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* TODO fix char/short overflows */
+
+{ PLUS,                INLL,
+       SHLL,   TLL,
+       SPICON, TANY,
+               NBREG|NBSL,     RESC1,
+               "\taddi\tAL,AR,A1\n"
+               "\taddc\tUL,%r0,U1\n", },
+
+{ PLUS,                INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               NBREG|NBSL|NBSR,        RESC1,
+               "\tadd\tAL,AR,A1\n"
+               "\taddc\tUL,UR,U1\n", },
+
+{ PLUS,                INFL,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               NCREG|NCSL|NCSR,        RESC1,
+               "\tfadd,sgl\tAL,AR,A1\n", },
+
+{ PLUS,                INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL|NDSR,        RESC1,
+               "\tfadd,dbl\tAL,AR,A1\n", },
+
+{ PLUS,                ININT,
+       SHINT,  ANYFIXED|TPOINT,
+       SONE,   TANY,
+               NAREG|NASL,     RESC1,
+               "\tldo\t1(AL),A1\n", },
+
+{ PLUS,                ININT,
+       SHINT,  ANYFIXED|TPOINT,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "\tldo\tCR(AL),A1\n", },
+
+{ MINUS,       INLL,
+       SHLL,   TLL,
+       SPICON, TANY,
+               NBREG|NBSL|NBSR,        RESC1,
+               "\tsubi\tAL,AR,A1\n"
+               "\tsubb\tUL,%r0,U1\n", },
+
+{ PLUS,                ININT,
+       SHINT,  TANY|TPOINT,
+       SPNAME, TANY,
+               NAREG|NASL,     RESC1,
+               "\tldo\tAR(AL),A1\n", },
+
+{ MINUS,       INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               NBREG|NBSL|NBSR,        RESC1,
+               "\tsub\tAL,AR,A1\n"
+               "\tsubb\tUL,UR,U1\n", },
+
+{ MINUS,       INFL,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               NCREG|NCSL|NCSR,        RESC1,
+               "\tfsub,sgl\tAL,AR,A1\n", },
+
+{ MINUS,       INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL|NDSR,        RESC1,
+               "\tfsub,dbl\tAL,AR,A1\n", },
+
+{ MINUS,       ININT,
+       SHINT,  ANYFIXED|TPOINT,
+       SONE,   TANY,
+               NAREG|NASL,     RESC1,
+               "\tldo\t-1(AL),A1\n", },
+
+{ MINUS,       ININT,
+       SHINT,  ANYFIXED|TPOINT,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "\tldo\t-CR(AL),A1\n", },
+
+/* Simple reg->reg ops */
+{ OPSIMP,      ININT,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "\tO\tAL,AR,A1\n", },
+
+{ OPSIMP,      INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               NBREG|NBSL|NBSR,        RESC1,
+               "\tO\tAL,AR,A1\n"
+               "\tO\tUL,UR,U1\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS,  ININT,
+       SHINT,  ANYFIXED,
+       SCON,   ANYFIXED,
+               NAREG|NASL,     RESC1,
+               "\tzdep\tAL,31-AR,32-AR,A1\n", },
+
+{ LS,  ININT,
+       SHINT,  ANYFIXED,
+       SHINT,  ANYFIXED,
+               NAREG|NASR,     RESC1,
+               "\tsubi\t31,AR,A1\n"
+               "\tmtsar\tA1\n"
+               "\tzvdep\tAL,32,A1\n", },
+
+{ RS,  INLL,
+       SHLL,   TLONGLONG,
+       SCON,   ANYFIXED,
+               NBREG|NBSL,     RESC1,
+               "\tshd\tUL,AL,31-AR,A1\n"
+               "\textrs\tUL,31-AR,32,U1\n", },
+
+{ RS,  INLL,
+       SHLL,   TULONGLONG,
+       SCON,   ANYFIXED,
+               NBREG|NBSL,     RESC1,
+               "\tshd\tUL,AL,AR,A1\n"
+               "\textru\tUL,31-AR,32,U1\n", },
+
+{ RS,  ININT,
+       SHINT,  ANYSIGNED,
+       SCON,   ANYFIXED,
+               NAREG|NASL,     RESC1,
+               "\textrs\tAL,31-AR,32,A1\n", },
+
+{ RS,  ININT,
+       SHINT,  ANYUSIGNED,
+       SCON,   ANYFIXED,
+               NAREG|NASL,     RESC1,
+               "\textru\tAL,31-AR,32,A1\n", },
+
+/* TODO the following should be split into mtsar and actual shift parts */
+{ RS,  ININT,
+       SHINT,  ANYSIGNED,
+       SHINT,  ANYFIXED,
+               NAREG|NASR,     RESC1,
+               "\tsubi\t31,AR,A1\n"
+               "\tmtsar\tA1\n"
+               "\tvextrs\tAL,32,A1\n", },
+
+{ RS,  ININT,
+       SHINT,  ANYUSIGNED,
+       SHINT,  ANYFIXED,
+               NAREG|NASR,     RESC1,
+               "\tsubi\t31,AR,A1\n"
+               "\tmtsar\tA1\n"
+               "\tvextru\tAL,32,A1\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SPCON,  TANY,
+               0,      RDEST,
+               "\tldi\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,  TBYTE,
+       SHINT,  TBYTE,
+               0,      RDEST,
+               "\tstb\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,  THWORD,
+       SHINT,  THWORD,
+               0,      RDEST,
+               "\tsth\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,  TWORD|TPOINT,
+       SHINT,  TWORD|TPOINT,
+               0,      RDEST,
+               "\tstw\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SOREG,  TLL,
+       SHLL,   TLL,
+               0,      RDEST,
+               "\tstw\tAR,AL\n"
+               "\tstw\tUR,UL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SHINT,  TBYTE,
+       SOREG,  TBYTE,
+               0,      RDEST,
+               "\tldb\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SHINT,  THWORD,
+       SOREG,  THWORD,
+               0,      RDEST,
+               "\tldh\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SHINT,  TWORD|TPOINT,
+       SOREG,  TWORD|TPOINT,
+               0,      RDEST,
+               "\tldw\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SHLL,   TLL,
+       SOREG,  TLL,
+               0,      RDEST,
+               "\tldw\tAR,AL\n"
+               "\tldw\tUR,UL\n", },
+
+{ ASSIGN,      FOREFF|ININT,
+       SHINT,  TWORD|TPOINT,
+       SHINT,  TWORD|TPOINT,
+               0,      RDEST,
+               "\tcopy\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|ININT,
+       SHINT,  ANYFIXED,
+       SHINT,  ANYFIXED,
+               0,      RDEST,
+               "\tcopy\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|ININT,
+       SFLD,   TANY,
+       SPIMM,  TANY,
+               0,      RDEST,
+               "\tdepi\tAR,31-H,S,AL\n", },
+
+{ ASSIGN,      FOREFF|ININT,
+       SFLD,   TANY,
+       SHINT,  TANY,
+               0,      RDEST,
+               "\tdep\tAR,31-H,S,AL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               0,      RDEST,
+               "\tcopy\tAR,AL\n"
+               "\tcopy\tUR,UL\n", },
+
+{ ASSIGN,      FOREFF|INFL,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               0,      RDEST,
+               "\tfcpy,sgl\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "\tfcpy,dbl\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INFL,
+       SHFL,   TFLOAT,
+       SOREG,  TFLOAT,
+               0,      RDEST,
+               "\tfldws\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SOREG,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "\tfldds\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INFL,
+       SOREG,  TFLOAT,
+       SHFL,   TFLOAT,
+               0,      RDEST,
+               "\tfstws\tAR,AL\n", },
+
+{ ASSIGN,      FOREFF|INDBL,
+       SOREG,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "\tfstds\tAR,AL\n", },
+
+/*
+ * DIV/MOD/MUL
+ */
+{ DIV, INFL,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               NCREG|NCSL|NCSR,        RESC1,
+               "\tfdiv,sgl\tAL,AR,A1\n", },
+
+{ DIV, INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL|NDSR,        RESC1,
+               "\tfdiv,dbl\tAL,AR,A1\n", },
+
+{ MUL, INFL,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               NCREG|NCSL|NCSR,        RESC1,
+               "\tfmul,sgl\tAL,AR,A1\n", },
+
+{ MUL, INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL|NDSR,        RESC1,
+               "\tfmul,dbl\tAL,AR,A1\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,        INLL,
+       SANY,   TANY,
+       SOREG,  TLL,
+               NBREG,  RESC1,
+               "\tldw\tAL,A1\n"
+               "\tldw\tUL,U1\n", },
+
+{ UMUL,        ININT,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "\tldw\tAL,A1\n", },
+
+{ UMUL,        ININT,
+       SANY,   TANY,
+       SOREG,  THWORD,
+               NAREG|NASL,     RESC1,
+               "\tldh\tAL,A1\n", },
+
+{ UMUL,        ININT,
+       SANY,   TANY,
+       SOREG,  TBYTE,
+               NAREG|NASL,     RESC1,
+               "\tldb\tAL,A1\n", },
+
+{ UMUL,        INDBL,
+       SANY,   TANY,
+       SOREG,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "\tfldds\tAL,A1\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "\tfldws\tAL,A1\n", },
+
+/*
+ * Logical/branching operators
+ */
+{ OPLOG,       FORCC,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               0,      0,
+               "ZD", },
+
+{ OPLOG,       FORCC,
+       SHINT,  ANYFIXED|TPOINT,
+       SPIMM,  ANYFIXED|TPOINT,
+               0,      0,
+               "\tcomib,O\tAR,AL,LC\n\tnop\n", },
+
+{ OPLOG,       FORCC,
+       SHINT,  ANYFIXED|TPOINT,
+       SHINT,  ANYFIXED|TPOINT,
+               0,      0,
+               "\tcomb,O\tAR,AL,LC\n\tnop\n", },
+
+{ OPLOG,       FORCC,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               0,      RESCC,
+               "\tfcmp,sgl,!O\tAR,AL\n"
+               "\tftest\n"
+               "\tb\tLC\n"
+               "\tnop", },
+
+{ OPLOG,       FORCC,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               0,      RESCC,
+               "\tfcmp,dbl,!O\tAR,AL\n"
+               "\tftest\n"
+               "\tb\tLC\n"
+               "\tnop", },
+
+/*
+ * Jumps.
+ */
+{ GOTO,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "\tb\tLL\n\tnop\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "\tbv\t%r0(AL)\n\tnop\n", },
+#endif
+
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SNAME,  TANY,
+               0,      RDEST,
+               "\taddil\tUR,%r27\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SCON,   TPOINT,
+               0,      RDEST,
+               "\taddil\tUR,%r27\n", },
+
+{ OPLTYPE,     INLL,
+       SANY,   TANY,
+       SOREG,  TLL,
+               NBREG|NBSL,     RESC1,
+               "\tldw\tAL,A1\n"
+               "\tldw\tUL,U1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SOREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "\tldw\tAL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "\tcopy\tAL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SPCNHI, ANYFIXED,
+               NAREG,          RESC1,
+               "\tldil\tUR,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SPCON,  ANYFIXED,
+               NAREG,          RESC1,
+               "\tldi\tAR,A1\n", },
+
+{ OPLTYPE,     INLL,
+       SANY,   TANY,
+       SPCON,  TLL,
+               NBREG,          RESC1,
+               "\tldi\tAR,A1\n"
+               "\tcopy\t%r0,U1\n", },
+
+{ OPLTYPE,     ININT,
+       SANY,   TANY,
+       SCON,   TWORD,
+               NAREG,          RESC1,
+               "\tldil\tUR,A1\n"
+               "\tldo\tAR(A1),A1\n", },
+
+{ OPLTYPE,     INLL,
+       SHLL,   TLL,
+       SPCNHW, TLL,
+               NBREG,          RESC1,
+               "\tldil\tUR>>32,U1\n"
+               "\tldo\tAR>>32(U1),U1\n"
+               "\tcopy\t%r0,A1\n", },
+
+{ OPLTYPE,     INLL,
+       SHLL,   TLL,
+       SPCNLW, TLL,
+               NBREG,          RESC1,
+               "\tcopy\t%r0,U1\n"
+               "\tldil\tUR,A1\n"
+               "\tldo\tAR(A1),A1\n", },
+
+{ OPLTYPE,     INLL,
+       SHLL,   TLL,
+       SCON,   TLL,
+               NBREG,          RESC1,
+               "\tldil\tUR,A1\n"
+               "\tldo\tAR(A1),A1\n"
+               "\tldil\tUR>>32,U1\n"
+               "\tldo\tAR>>32(U1),U1\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TFLOAT,
+       SHFL,   TFLOAT,
+               NCREG,  RESC1,
+               "\tfldws\tAL,A1\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,   TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "\tfldds\tAL,A1\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS,      INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               NBREG|NBSL,     RESC1,
+               "\tsub\t%r0,AL,A1\n"
+               "\tsubb\t%r0,UL,A1\n", },
+
+{ UMINUS,      ININT,
+       SHINT,  TWORD,
+       SHINT,  TWORD,
+               NAREG|NASL,     RESC1,
+               "\tsub\t%r0,AL,A1\n", },
+
+{ UMINUS,      INFL,
+       SHFL,   TFLOAT,
+       SHFL,   TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "\tfsub,sgl\t%fr0,AL,A1\n", },
+
+{ UMINUS,      INDBL,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+       SHDBL,  TDOUBLE|TLDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "\tfsub,dbl\t%fr0,AL,A1\n", },
+
+{ COMPL,       INLL,
+       SHLL,   TLL,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,
+               "\tuaddcm\t%r0,AL,A1\n"
+               "\tuaddcm\t%r0,UL,U1\n", },
+
+{ COMPL,       ININT,
+       SHINT,  ANYFIXED,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "\tuaddcm\t%r0,AL,A1\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+{ STARG,       FOREFF,
+       SAREG|SOREG|SNAME|SCON, TANY,
+       SANY,   TSTRUCT,
+               NAREG | RNULL,  0,
+               "ZS", },
+
+/*
+ * struct field ops
+ */
+{ FLD, ININT,
+       SHINT,  TANY,
+       SFLD,   ANYSIGNED,
+               NAREG|NASL,     RESC1,
+               "\textrs\tAL,31-H,S,A1\n", },
+
+{ FLD, ININT,
+       SHINT,  TANY,
+       SFLD,   ANYUSIGNED,
+               NAREG|NASL,     RESC1,
+               "\textru\tAL,31-H,S,A1\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,                FREE,
+       FREE,   FREE,
+       FREE,   FREE,
+               FREE,   FREE,
+               "HELP; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/i386/code.c b/lang/pcc/pcc/arch/i386/code.c
new file mode 100644 (file)
index 0000000..05118fb
--- /dev/null
@@ -0,0 +1,669 @@
+/*     $Id: code.c,v 1.96 2015/11/17 19:19:40 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+#ifdef LANG_CXX
+#define        p1listf listf
+#define        p1tfree tfree
+#else
+#define        NODE P1ND
+#define        talloc p1alloc
+#endif
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case UDATA: break;
+#ifdef MACHOABI
+       case PICLDATA:
+       case PICDATA: name = ".section .data.rel.rw,\"aw\""; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break;
+       case STRNG: name = ".cstring"; break;
+       case RDATA: name = ".const_data"; break;
+#else
+       case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break;
+       case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
+       case STRNG:
+#ifdef AOUTABI
+       case RDATA: name = ".data"; break;
+#else
+       case RDATA: name = ".section .rodata"; break;
+#endif
+#endif
+       case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
+       case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
+#ifdef MACHOABI
+       case CTORS: name = ".mod_init_func\n\t.align 2"; break;
+       case DTORS: name = ".mod_term_func\n\t.align 2"; break;
+#else
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+#endif
+       case NMSEG: 
+               printf(PRTPREF "\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf(PRTPREF "\t%s\n", name);
+}
+
+#ifdef MACHOABI
+void
+defalign(int al)
+{
+       printf(PRTPREF "\t.align %d\n", ispow2(al/ALCHAR));
+}
+#endif
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       name = getexname(sp);
+       if (sp->sclass == EXTDEF) {
+               printf(PRTPREF "        .globl %s\n", name);
+#if defined(ELFABI)
+               printf(PRTPREF "\t.type %s,@%s\n", name,
+                   ISFTN(sp->stype)? "function" : "object");
+#endif
+       }
+#if defined(ELFABI)
+       if (!ISFTN(sp->stype)) {
+               if (sp->slevel == 0)
+                       printf(PRTPREF "\t.size %s,%d\n", name,
+                           (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
+               else
+                       printf(PRTPREF "\t.size " LABFMT ",%d\n", sp->soffset,
+                           (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
+       }
+#endif
+       if (sp->slevel == 0)
+               printf(PRTPREF "%s:\n", name);
+       else
+               printf(PRTPREF LABFMT ":\n", sp->soffset);
+}
+
+int structrettemp;
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       extern int gotnr;
+       NODE *p, *q;
+       int sz;
+
+       gotnr = 0;      /* new number for next fun */
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+
+       /* struct return for small structs */
+       sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
+#if defined(os_openbsd)
+       if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) {
+#else
+       if (sz == SZLONGLONG && attr_find(cftnsp->sap, ATTR_COMPLEX)) {
+#endif
+               /* Pointer to struct in eax */
+               if (sz == SZLONGLONG) {
+                       q = block(OREG, NIL, NIL, INT, 0, 0);
+                       slval(q, 4);
+                       p = block(REG, NIL, NIL, INT, 0, 0);
+                       p->n_rval = EDX;
+                       ecomp(buildtree(ASSIGN, p, q));
+               }
+               if (sz < SZSHORT) sz = CHAR;
+               else if (sz > SZSHORT) sz = INT;
+               else sz = SHORT;
+               q = block(OREG, NIL, NIL, sz, 0, 0);
+               p = block(REG, NIL, NIL, sz, 0, 0);
+               ecomp(buildtree(ASSIGN, p, q));
+               return;
+       }
+
+       /* Create struct assignment */
+       q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap);
+       q = buildtree(UMUL, q, NIL);
+       p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       p = buildtree(UMUL, p, NIL);
+       p = buildtree(ASSIGN, q, p);
+       ecomp(p);
+
+       /* put hidden arg in eax on return */
+       q = tempnode(structrettemp, INT, 0, 0);
+       p = block(REG, NIL, NIL, INT, 0, 0);
+       regno(p) = EAX;
+       ecomp(buildtree(ASSIGN, p, q));
+}
+
+#ifdef GCC_COMPAT
+static TWORD reparegs[] = { EAX, EDX, ECX };
+static TWORD fastregs[] = { ECX, EDX };
+#endif
+static TWORD longregs[] = { EAXEDX, EDXECX };
+static TWORD charregs[] = { AL, DL, CL };
+static TWORD *regpregs;
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ *
+ * Classifying args on i386; not simple:
+ * - Args may be on stack or in registers (regparm)
+ * - There may be a hidden first arg, unless OpenBSD struct return.
+ * - Regparm syntax is not well documented.
+ * - There may be stdcall functions, where the called function pops stack
+ * - ...probably more
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       extern int argstacksize;
+#ifdef GCC_COMPAT
+       struct attr *ap;
+#endif
+       struct symtab *sp2;
+       extern int gotnr;
+       NODE *n, *p;
+       int i, regparmarg;
+       int argbase, nrarg, sz;
+
+       /* Take care of PIC stuff first */
+        if (kflag) {
+#define STL     200
+                char *str = xmalloc(STL);
+#if !defined(MACHOABI)
+                int l = getlab();
+#else
+                char *name;
+#endif
+
+                /* Generate extended assembler for PIC prolog */
+                p = tempnode(0, INT, 0, 0);
+                gotnr = regno(p);
+                p = block(XARG, p, NIL, INT, 0, 0);
+                p->n_name = "=g";
+                p = block(XASM, p, bcon(0), INT, 0, 0);
+
+#if defined(MACHOABI)
+                if ((name = cftnsp->soname) == NULL)
+                        name = cftnsp->sname;
+                if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n",
+                    name, name) >= STL)
+                        cerror("bfcode");
+#else
+                if (snprintf(str, STL,
+                    "call " LABFMT ";" LABFMT ":;\tpopl %%0;"
+                    "\taddl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0;",
+                    l, l, l) >= STL)
+                        cerror("bfcode");
+#endif
+                p->n_name = addstring(str);
+                p->n_right->n_type = STRTY;
+               free(str);
+                ecomp(p);
+        }
+
+       argbase = ARGINIT;
+       nrarg = regparmarg = 0;
+       argstacksize = 0;
+
+#ifdef GCC_COMPAT
+       regpregs = reparegs;
+        if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
+                cftnsp->sflags |= SSTDCALL;
+        if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM)))
+                regparmarg = ap->iarg(0);
+        if ((ap = attr_find(cftnsp->sap, GCC_ATYP_FASTCALL)))
+                regparmarg = 2, regpregs = fastregs;
+#endif
+
+       /* Function returns struct, create return arg node */
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
+#if defined(os_openbsd)
+               /* OpenBSD uses non-standard return for small structs */
+               if (sz > SZLONGLONG)
+#else
+               if (sz != SZLONGLONG ||
+                   attr_find(cftnsp->sap, ATTR_COMPLEX) == 0)
+#endif
+               {
+                       if (regparmarg) {
+                               n = block(REG, 0, 0, INT, 0, 0);
+                               regno(n) = regpregs[nrarg++];
+                       } else {
+                               n = block(OREG, 0, 0, INT, 0, 0);
+                               slval(n, argbase/SZCHAR);
+                               argbase += SZINT;
+                               regno(n) = FPREG;
+                               argstacksize += 4; /* popped by callee */
+                       }
+                       p = tempnode(0, INT, 0, 0);
+                       structrettemp = regno(p);
+                       p = buildtree(ASSIGN, p, n);
+                       ecomp(p);
+               }
+       }
+
+       /*
+        * Find where all params are so that they end up at the right place.
+        * At the same time recalculate their arg offset on stack.
+        * We also get the "pop size" for stdcall.
+        */
+       for (i = 0; i < cnt; i++) {
+               sp2 = sp[i];
+               sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
+
+               SETOFF(sz, SZINT);
+
+               if (cisreg(sp2->stype) == 0 ||
+                   ((regparmarg - nrarg) * SZINT < sz)) {      /* not in reg */
+                       sp2->soffset = argbase;
+                       argbase += sz;
+                       nrarg = regparmarg;     /* no more in reg either */
+               } else {                                        /* in reg */
+                       sp2->soffset = regpregs[nrarg];
+                       nrarg += sz/SZINT;
+                       sp2->sclass = REGISTER;
+               }
+       }
+
+       /*
+        * Now (argbase - ARGINIT) is used space on stack.
+        * Move (if necessary) the args to something new.
+        */
+       for (i = 0; i < cnt; i++) {
+               int reg, j;
+
+               sp2 = sp[i];
+
+               if ((ISSOU(sp2->stype) && sp2->sclass == REGISTER) ||
+                   (sp2->sclass == REGISTER && xtemps == 0)) {
+                       /* must move to stack */
+                       sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
+                       SETOFF(sz, SZINT);
+                       SETOFF(autooff, SZINT);
+                       reg = sp2->soffset;
+                       sp2->sclass = AUTO;
+                       sp2->soffset = NOOFFSET;
+                       oalloc(sp2, &autooff);
+                        for (j = 0; j < sz/SZCHAR; j += 4) {
+                                p = block(OREG, 0, 0, INT, 0, 0);
+                                slval(p, sp2->soffset/SZCHAR + j);
+                                regno(p) = FPREG;
+                                n = block(REG, 0, 0, INT, 0, 0);
+                                regno(n) = regpregs[reg++];
+                                p = block(ASSIGN, p, n, INT, 0, 0);
+                                ecomp(p);
+                        }
+               } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) &&
+                   ((cqual(sp2->stype, sp2->squal) & VOL) == 0) && xtemps) {
+                       /* just put rest in temps */
+                       if (sp2->sclass == REGISTER) {
+                               n = block(REG, 0, 0, sp2->stype,
+                                   sp2->sdf, sp2->sap);
+                               if (ISLONGLONG(sp2->stype))
+                                       regno(n) = longregs[sp2->soffset];
+                               else if (DEUNSIGN(sp2->stype) == CHAR ||
+                                   sp2->stype == BOOL)
+                                       regno(n) = charregs[sp2->soffset];
+                               else
+                                       regno(n) = regpregs[sp2->soffset];
+                       } else {
+                                n = block(OREG, 0, 0, sp2->stype,
+                                   sp2->sdf, sp2->sap);
+                                slval(n, sp2->soffset/SZCHAR);
+                                regno(n) = FPREG;
+                       }
+                       p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap);
+                       sp2->soffset = regno(p);
+                       sp2->sflags |= STNODE;
+                       n = buildtree(ASSIGN, p, n);
+                       ecomp(n);
+               }
+       }
+
+        if (cftnsp->sflags & SSTDCALL) {
+#ifdef PECOFFABI
+                char buf[256];
+                char *name;
+#endif
+               /* XXX interaction STDCALL and struct return? */
+               argstacksize += (argbase - ARGINIT)/SZCHAR;
+#ifdef PECOFFABI
+                /*
+                 * mangle name in symbol table as a callee.
+                 */
+                if ((name = cftnsp->soname) == NULL)
+                        name = exname(cftnsp->sname);
+                snprintf(buf, 256, "%s@%d", name, argstacksize);
+                cftnsp->soname = addname(buf);
+#endif
+        }
+
+}
+
+#if defined(MACHOABI)
+struct stub stublist;
+struct stub nlplist;
+#endif
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+#if defined(MACHOABI)
+       /*
+        * iterate over the stublist and output the PIC stubs
+`       */
+       if (kflag) {
+               struct stub *p;
+
+               DLIST_FOREACH(p, &stublist, link) {
+                       printf(PRTPREF "\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n");
+                       printf(PRTPREF "L%s$stub:\n", p->name);
+                       printf(PRTPREF "\t.indirect_symbol %s\n", p->name);
+                       printf(PRTPREF "\thlt ; hlt ; hlt ; hlt ; hlt\n");
+                       printf(PRTPREF "\t.subsections_via_symbols\n");
+               }
+
+               printf(PRTPREF "\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
+               DLIST_FOREACH(p, &nlplist, link) {
+                       printf(PRTPREF "L%s$non_lazy_ptr:\n", p->name);
+                       printf(PRTPREF "\t.indirect_symbol %s\n", p->name);
+                       printf(PRTPREF "\t.long 0\n");
+               }
+
+       }
+#endif
+
+       printf(PRTPREF "\t.ident \"PCC: %s\"\n", VERSSTR);
+}
+
+void
+bjobcode(void)
+{
+#ifdef os_sunos
+       astypnames[SHORT] = astypnames[USHORT] = "\t.2byte";
+#endif
+       astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
+#if defined(MACHOABI)
+       DLIST_INIT(&stublist, link);
+       DLIST_INIT(&nlplist, link);
+#endif
+#if defined(__GNUC__) || defined(__PCC__)
+       /* Be sure that the compiler uses full x87 */
+       /* XXX cross-compiling will fail here */
+       int fcw;
+       __asm("fstcw (%0)" : : "r"(&fcw));
+       fcw |= 0x300;
+       __asm("fldcw (%0)" : : "r"(&fcw));
+#endif
+}
+
+/*
+ * Convert FUNARG to assign in case of regparm.
+ */
+static int regcvt, rparg, fcall;
+static void
+addreg(NODE *p)
+{
+       TWORD t;
+       NODE *q;
+       int sz, r;
+
+       sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR;
+       sz = (sz + 3) >> 2;     /* sz in regs */
+       if ((regcvt+sz) > rparg) {
+               regcvt = rparg;
+               return;
+       }
+       if (sz > 2)
+               uerror("cannot put struct in 3 regs (yet)");
+
+       if (sz == 2)
+               r = regcvt == 0 ? EAXEDX : EDXECX;
+       else if (fcall)
+               r = regcvt == 0 ? ECX : EDX;
+       else
+               r = regcvt == 0 ? EAX : regcvt == 1 ? EDX : ECX;
+
+       if (p->n_op == FUNARG) {
+               /* at most 2 regs */
+               if (p->n_type < INT) {
+                       p->n_left = ccast(p->n_left, INT, 0, 0, 0);
+                       p->n_type = INT;
+               }
+
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+       } else if (p->n_op == STARG) {
+               /* convert to ptr, put in reg */
+               q = p->n_left;
+               t = sz == 2 ? LONGLONG : INT;
+               q = cast(q, INCREF(t), 0);
+               q = buildtree(UMUL, q, NIL);
+               p->n_op = ASSIGN;
+               p->n_type = t;
+               p->n_right = q;
+       } else
+               cerror("addreg");
+       p->n_left = block(REG, 0, 0, p->n_type, 0, 0);
+       regno(p->n_left) = r;
+       regcvt += sz;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
+ */
+NODE *
+funcode(NODE *p)
+{
+       extern int gotnr;
+       struct attr *ap;
+       NODE *r, *l;
+       TWORD t = DECREF(DECREF(p->n_left->n_type));
+       int stcall;
+
+       stcall = ISSOU(t);
+       /*
+        * We may have to prepend:
+        * - Hidden arg0 for struct return (in reg or on stack).
+        * - ebx in case of PIC code.
+        */
+
+       /* Fix function call arguments. On x86, just add funarg */
+       for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+               if (r->n_right->n_op != STARG)
+                       r->n_right = block(FUNARG, r->n_right, NIL,
+                           r->n_right->n_type, r->n_right->n_df,
+                           r->n_right->n_ap);
+       }
+       if (r->n_op != STARG) {
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_type = l->n_type;
+       }
+#ifdef os_openbsd
+       if (stcall && (ap = strattr(p->n_left->n_ap)) &&
+           ap->amsize != SZCHAR && ap->amsize != SZSHORT &&
+           ap->amsize != SZINT && ap->amsize != SZLONGLONG)
+#else
+       if (stcall &&
+           (attr_find(p->n_left->n_ap, ATTR_COMPLEX) == 0 ||
+            ((ap = strattr(p->n_left->n_ap)) && ap->amsize > SZLONGLONG)))
+#endif
+       {
+               /* Prepend a placeholder for struct address. */
+               /* Use EBP, can never show up under normal circumstances */
+               l = talloc();
+               *l = *r;
+               r->n_op = CM;
+               r->n_right = l;
+               r->n_type = INT;
+               l = block(REG, 0, 0, INCREF(VOID), 0, 0);
+               regno(l) = EBP;
+               l = block(FUNARG, l, 0, INCREF(VOID), 0, 0);
+               r->n_left = l;
+       }
+
+#ifdef GCC_COMPAT
+       fcall = 0;
+       if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM)))
+               rparg = ap->iarg(0);
+       else if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_FASTCALL)))
+               fcall = rparg = 2;
+       else
+#endif
+               rparg = 0;
+
+       regcvt = 0;
+       if (rparg)
+               p1listf(p->n_right, addreg);
+
+       if (kflag == 0)
+               return p;
+
+#if defined(ELFABI)
+       /* Create an ASSIGN node for ebx */
+       l = block(REG, NIL, NIL, INT, 0, 0);
+       l->n_rval = EBX;
+       l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
+       if (p->n_right->n_op != CM) {
+               p->n_right = block(CM, l, p->n_right, INT, 0, 0);
+       } else {
+               for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
+                       ;
+               r->n_left = block(CM, l, r->n_left, INT, 0, 0);
+       }
+#endif
+       return p;
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+NODE * 
+builtin_return_address(const struct bitable *bt, NODE *a)
+{      
+       int nframes;
+       NODE *f; 
+       
+       if (a->n_op != ICON)
+               goto bad;
+
+       nframes = (int)glval(a);
+  
+       p1tfree(a);     
+                       
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+                                   
+       f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, 0);
+       f = buildtree(UMUL, f, NIL);    
+   
+       return f;
+bad:                                           
+       uerror("bad argument to __builtin_return_address");
+       return bcon(0);
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+       if (a->n_op != ICON)
+               goto bad;
+
+       nframes = (int)glval(a);
+
+       p1tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+
+       return f;
+bad:
+       uerror("bad argument to __builtin_frame_address");
+       return bcon(0);
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       uerror("missing builtin_cfa");
+       return bcon(0);
+}
+
diff --git a/lang/pcc/pcc/arch/i386/flocal.c b/lang/pcc/pcc/arch/i386/flocal.c
new file mode 100644 (file)
index 0000000..91f08e2
--- /dev/null
@@ -0,0 +1,231 @@
+/*     $Id: flocal.c,v 1.17 2012/04/22 21:07:40 plunky Exp $   */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void
+prchars(int *s)
+{
+       printf("\t.byte 0%o,0%o\n", s[0], s[1]);
+}
+
+void
+setloc(int l)
+{
+       static int lastloc = -1;
+       static char *loctbl[] =
+           { "text", "data", "section .rodata", "section .rodata", "bss" };
+       if (l == lastloc)
+               return;
+       printf("\t.%s\n", loctbl[l]);
+       lastloc = l;
+}
+
+#ifdef FCOM
+
+
+/*
+       PDP11-780/VAX - SPECIFIC PRINTING ROUTINES
+*/
+
+/*
+ * Called just before return from a subroutine.
+ */
+void
+goret(int type)
+{
+}
+
+/*
+ * Print out a label.
+ */
+void
+prlabel(int k)
+{
+       printf(LABFMT ":\n", k);
+}
+
+/*
+ * Print naming for location.
+ * name[0] is location type.
+ */
+void
+prnloc(char *name)
+{
+       if (*name == '0')
+               setloc(DATA);
+       else
+               fatal("unhandled prnloc %c", *name);
+       printf("%s:\n", name+1);
+}
+
+/*
+ * Print integer constant.
+ */
+void
+prconi(FILE *fp, int type, ftnint n)
+{
+       fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n);
+}
+
+/*
+ * Print address constant, given as a label number.
+ */
+void
+prcona(ftnint a)
+{
+       printf("\t.long\t" LABFMT "\n", (int)a);
+}
+
+/*
+ * Print out a floating constant.
+ */
+void
+prconr(FILE *fp, int type, double x)
+{
+       fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x);
+}
+
+void
+preven(int k)
+{
+       if (k > 1)
+               printf("\t.align\t%d\n", k);
+}
+
+/*
+ * Convert a tag and offset into the symtab table to a string.
+ * An external string is never longer than XL bytes.
+ */
+char *
+memname(int stg, int mem)
+{
+#define        MLEN    (XL + 10)
+       char *s = malloc(MLEN);
+
+       switch(stg) {
+       case STGCOMMON:
+       case STGEXT:
+               snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname));
+               break;
+
+       case STGBSS:
+       case STGINIT:
+               snprintf(s, MLEN, "v.%d", mem);
+               break;
+
+       case STGCONST:
+               snprintf(s, MLEN, ".L%d", mem);
+               break;
+
+       case STGEQUIV:
+               snprintf(s, MLEN, "q.%d", mem);
+               break;
+
+       default:
+               fatal1("memname: invalid vstg %d", stg);
+       }
+       return(s);
+}
+
+void
+prlocvar(char *s, ftnint len)
+{
+       printf("\t.lcomm\t%s,%ld\n", s, len);
+}
+
+
+void
+prext(char *name, ftnint leng, int init)
+{
+       if(leng == 0)
+               printf("\t.globl\t%s\n", name);
+       else
+               printf("\t.comm\t%s,%ld\n", name, leng);
+}
+
+void
+prendproc(void)
+{
+}
+
+void
+prtail(void)
+{
+}
+
+void
+prolog(struct entrypoint *ep, struct bigblock *argvec)
+{
+       /* Ignore for now.  ENTRY is not supported */
+}
+
+void
+prdbginfo(void)
+{
+}
+
+static void
+fcheck(NODE *p, void *arg)
+{
+       NODE *r, *l;
+
+       switch (p->n_op) {
+       case CALL: /* fix arguments */
+               for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+                       r->n_right = mkunode(FUNARG, r->n_right, 0,
+                           r->n_right->n_type);
+               }
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_type = l->n_type;
+               break;
+       }
+}
+
+/*
+ * Called just before the tree is written out to pass2.
+ */
+void p2tree(NODE *p);
+void
+p2tree(NODE *p)
+{
+       walkf(p, fcheck, 0);
+}
+#endif /* FCOM */
diff --git a/lang/pcc/pcc/arch/i386/local.c b/lang/pcc/pcc/arch/i386/local.c
new file mode 100644 (file)
index 0000000..b276cb0
--- /dev/null
@@ -0,0 +1,1319 @@
+/*     $Id: local.c,v 1.200 2016/03/05 15:31:24 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#undef NIL
+#define        NIL NULL
+
+#ifdef LANG_CXX
+#define        P1ND NODE
+#define        p1nfree nfree
+#define        p1fwalk fwalk
+#define        p1tcopy tcopy
+#endif
+
+/*     this file contains code which is dependent on the target machine */
+
+#ifdef notyet
+/*
+ * Check if a constant is too large for a type.
+ */
+static int
+toolarge(TWORD t, CONSZ con)
+{
+       U_CONSZ ucon = con;
+
+       switch (t) {
+       case ULONGLONG:
+       case LONGLONG:
+               break; /* cannot be too large */
+#define        SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break
+#define        UCHK(i) case i: if (ucon > MAX_##i) return 1; break
+       SCHK(INT);
+       SCHK(SHORT);
+       case BOOL:
+       SCHK(CHAR);
+       UCHK(UNSIGNED);
+       UCHK(USHORT);
+       UCHK(UCHAR);
+       default:
+               cerror("toolarge");
+       }
+       return 0;
+}
+#endif
+
+static char *
+getsoname(struct symtab *sp)
+{
+       struct attr *ap;
+       return (ap = attr_find(sp->sap, ATTR_SONAME)) ?
+           ap->sarg(0) : sp->sname;
+       
+}
+
+#if defined(MACHOABI)
+
+/*
+ *  Keep track of PIC stubs.
+ */
+
+void
+addstub(struct stub *list, char *name)
+{
+        struct stub *s;
+
+        DLIST_FOREACH(s, list, link) {
+                if (strcmp(s->name, name) == 0)
+                        return;
+        }
+
+        s = permalloc(sizeof(struct stub));
+       s->name = newstring(name, strlen(name));
+        DLIST_INSERT_BEFORE(list, s, link);
+}
+
+#endif
+
+#define        IALLOC(sz)      (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+       struct symtab *sp = IALLOC(sizeof(struct symtab));
+       size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+       
+       sp->sname = IALLOC(len);
+       strlcpy(sp->sname, p, len);
+       strlcat(sp->sname, s, len);
+       strlcat(sp->sname, s2, len);
+       sp->sap = attr_new(ATTR_SONAME, 1);
+       sp->sap->sarg(0) = sp->sname;
+       sp->sclass = EXTERN;
+       sp->sflags = sp->slevel = 0;
+       sp->stype = 0xdeadbeef;
+       return sp;
+}
+
+#ifdef PECOFFABI
+static P1ND *
+import(P1ND *p)
+{
+       struct attr *ap;
+       P1ND *q;
+       char *name;
+       struct symtab *sp;
+
+       name = getexname(p->n_sp);
+
+       sp = picsymtab("__imp_", name, "");
+       q = xbcon(0, sp, PTR+VOID);
+       q = block(UMUL, q, 0, PTR|VOID, 0, 0);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       p1nfree(p);
+
+       return q;
+}
+#endif
+
+int gotnr; /* tempnum for GOT register */
+int argstacksize;
+
+/*
+ * Create a reference for an extern variable.
+ */
+static P1ND *
+picext(P1ND *p)
+{
+       struct attr *ap;
+
+#if defined(ELFABI)
+       P1ND *q, *r;
+       struct symtab *sp;
+       char *name;
+
+       q = tempnode(gotnr, PTR|VOID, 0, 0);
+       name = getexname(p->n_sp);
+
+#ifdef GCC_COMPAT
+       if ((ap = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) &&
+           strcmp(ap->sarg(0), "hidden") == 0) {
+               /* For hidden vars use GOTOFF */
+               sp = picsymtab("", name, "@GOTOFF");
+               r = xbcon(0, sp, INT);
+               q = buildtree(PLUS, q, r);
+               q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+               q->n_sp = p->n_sp; /* for init */
+               p1nfree(p);
+               return q;
+       }
+#endif
+
+       sp = picsymtab("", name, "@GOT");
+#ifdef GCC_COMPAT
+       if (attr_find(p->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
+               p->n_sp->sflags |= SSTDCALL;
+#endif
+       sp->sflags = p->n_sp->sflags & SSTDCALL;
+       sp->sap = attr_add(p->n_sp->sap, sp->sap);
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, PTR|VOID, 0, 0);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       p1nfree(p);
+       return q;
+
+#elif defined(MACHOABI)
+
+       P1ND *q, *r;
+       struct symtab *sp;
+       char buf2[256], *name, *pspn;
+
+       name = getsoname(cftnsp);
+       pspn = getexname(p->n_sp);
+
+       if (p->n_sp->sclass == EXTDEF) {
+               snprintf(buf2, 256, "-L%s$pb", name);
+               sp = picsymtab("", pspn, buf2);
+       } else {
+               snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name);
+               sp = picsymtab("L", pspn, buf2);
+               addstub(&nlplist, pspn);
+       }
+
+       sp->stype = p->n_sp->stype;
+
+       q = tempnode(gotnr, PTR+VOID, 0, 0);
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+
+       if (p->n_sp->sclass != EXTDEF)
+               q = block(UMUL, q, 0, PTR+VOID, 0, 0);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       p1nfree(p);
+       return q;
+
+#else /* defined(PECOFFABI) || defined(AOUTABI) */
+
+       return p;
+
+#endif
+
+}
+
+/*
+ * Create a reference for a static variable.
+ */
+static P1ND *
+picstatic(P1ND *p)
+{
+#if defined(ELFABI)
+
+       P1ND *q, *r;
+       struct symtab *sp;
+
+       q = tempnode(gotnr, PTR|VOID, 0, 0);
+       if (p->n_sp->slevel > 0) {
+               char buf[32];
+               if ((p->n_sp->sflags & SMASK) == SSTRING)
+                       p->n_sp->sflags |= SASG;
+               snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
+               sp = picsymtab("", buf, "@GOTOFF");
+       } else
+               sp = picsymtab("", getsoname(p->n_sp), "@GOTOFF");
+       
+       sp->sclass = STATIC;
+       sp->stype = p->n_sp->stype;
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       p1nfree(p);
+       return q;
+
+#elif defined(MACHOABI)
+
+       P1ND *q, *r;
+       struct symtab *sp;
+       char buf2[256];
+
+       snprintf(buf2, 256, "-L%s$pb",
+           cftnsp->soname ? cftnsp->soname : cftnsp->sname);
+
+       if (p->n_sp->slevel > 0) {
+               char buf1[32];
+               snprintf(buf1, 32, LABFMT, (int)p->n_sp->soffset);
+               sp = picsymtab("", buf1, buf2);
+       } else  {
+               char *name = getexname(p->n_sp);
+               sp = picsymtab("", name, buf2);
+       }
+       sp->sclass = STATIC;
+       sp->stype = p->n_sp->stype;
+       q = tempnode(gotnr, PTR+VOID, 0, 0);
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp;
+       p1nfree(p);
+       return q;
+
+#else /* defined(PECOFFABI) || defined(AOUTABI) */
+
+       return p;
+
+#endif
+
+}
+
+#ifdef TLS
+/*
+ * Create a reference for a TLS variable.
+ */
+static P1ND *
+tlspic(P1ND *p)
+{
+       P1ND *q, *r;
+       struct symtab *sp, *sp2;
+       char *name;
+
+       /*
+        * creates:
+        *   leal var@TLSGD(%ebx),%eax
+        *   call ___tls_get_addr@PLT
+        */
+
+       /* calc address of var@TLSGD */
+       q = tempnode(gotnr, PTR|VOID, 0, 0);
+       name = getsoname(p->n_sp);
+       sp = picsymtab("", name, "@TLSGD");
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+
+       /* assign to %eax */
+       r = block(REG, NIL, NIL, PTR|VOID, 0, 0);
+       r->n_rval = EAX;
+       q = buildtree(ASSIGN, r, q);
+
+       /* call ___tls_get_addr */
+       sp2 = lookup("___tls_get_addr@PLT", 0);
+       sp2->stype = EXTERN|INT|FTN;
+       r = nametree(sp2);
+       r = buildtree(ADDROF, r, NIL);
+       r = block(UCALL, r, NIL, INT, 0, 0);
+
+       /* fusion both parts together */
+       q = buildtree(COMOP, q, r);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+
+       p1nfree(p);
+       return q;
+}
+
+static P1ND *
+tlsnonpic(P1ND *p)
+{
+       P1ND *q, *r;
+       struct symtab *sp, *sp2;
+       int ext = p->n_sp->sclass;
+       char *name;
+
+       name = getsoname(p->n_sp);
+       sp = picsymtab("", name,
+           ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF");
+       q = xbcon(0, sp, INT);
+       if (ext == EXTERN)
+               q = block(UMUL, q, NIL, PTR|VOID, 0, 0);
+
+       sp2 = lookup("%gs:0", 0);
+       sp2->stype = EXTERN|INT;
+       r = nametree(sp2);
+
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+
+       p1nfree(p);
+       return q;
+}
+
+static P1ND *
+tlsref(P1ND *p)
+{
+       if (kflag)
+               return (tlspic(p));
+       else
+               return (tlsnonpic(p));
+}
+#endif
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+P1ND *
+clocal(P1ND *p)
+{
+
+       struct attr *ap;
+       register struct symtab *q;
+       register P1ND *r, *l, *n, *s;
+       register int o;
+       register int m;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               p1fwalk(p, eprint, 0);
+       }
+#endif
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       slval(r, 0);
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case USTATIC:
+                       if (kflag == 0)
+                               break;
+                       /* FALLTHROUGH */
+               case STATIC:
+#ifdef TLS
+                       if (q->sflags & STLS) {
+                               p = tlsref(p);
+                               break;
+                       }
+#endif
+                       if (kflag == 0) {
+                               if (q->slevel == 0)
+                                       break;
+                       } else if (kflag && !statinit && blevel > 0 &&
+#ifdef GCC_COMPAT
+                           attr_find(q->sap, GCC_ATYP_WEAKREF)) {
+#else
+                           0) {
+#endif
+                               /* extern call */
+                               p = picext(p);
+                       } else if (blevel > 0 && !statinit)
+                               p = picstatic(p);
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       slval(p, 0);
+                       p->n_rval = q->soffset;
+                       break;
+
+               case EXTERN:
+               case EXTDEF:
+#ifdef TLS
+                       if (q->sflags & STLS) {
+                               p = tlsref(p);
+                               break;
+                       }
+#endif
+
+#ifdef PECOFFABI
+                       if (q->sflags & SDLLINDIRECT)
+                               p = import(p);
+#endif
+#ifdef GCC_COMPAT
+                       if ((ap = attr_find(q->sap,
+                           GCC_ATYP_VISIBILITY)) != NULL &&
+                           strcmp(ap->sarg(0), "hidden") == 0)
+                               printf(PRTPREF "\t.hidden %s\n", getsoname(q));
+#endif
+                       if (kflag == 0)
+                               break;
+                       if (blevel > 0 && !statinit)
+                               p = picext(p);
+                       break;
+               }
+               break;
+
+       case ADDROF:
+               if (kflag == 0 || blevel == 0 || statinit)
+                       break;
+               /* char arrays may end up here */
+               l = p->n_left;
+               if (l->n_op != NAME ||
+                   (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
+                       break;
+               l = p;
+               p = picstatic(p->n_left);
+               p1nfree(l);
+               if (p->n_op != UMUL)
+                       cerror("ADDROF error");
+               l = p;
+               p = p->n_left;
+               p1nfree(l);
+               break;
+
+       case UCALL:
+               if (kflag == 0)
+                       break;
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               l->n_rval = EBX;
+               p->n_right = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
+               p->n_op -= (UCALL-CALL);
+               break;
+
+       case USTCALL:
+#if defined(os_openbsd)
+               ap = strattr(p->n_left->n_ap);
+               if (ap->amsize == SZCHAR || ap->amsize == SZSHORT ||
+                   ap->amsize == SZINT || ap->amsize == SZLONGLONG)
+#else
+               if (attr_find(p->n_left->n_ap, ATTR_COMPLEX) &&
+                   (ap = strattr(p->n_left->n_ap)) &&
+                   ap->amsize == SZLONGLONG)
+#endif
+               {
+                       /* float complex */
+                       /* fake one arg to make pass2 happy */
+                       p->n_right = block(FUNARG, bcon(0), NIL, INT, 0, 0);
+                       p->n_op -= (UCALL-CALL);
+                       break;
+               }
+
+               /* Add hidden arg0 */
+               r = block(REG, NIL, NIL, INCREF(VOID), 0, 0);
+               regno(r) = EBP;
+#ifdef GCC_COMPAT
+               if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL &&
+                   ap->iarg(0) > 0) {
+                       l = block(REG, NIL, NIL, INCREF(VOID), 0, 0);
+                       regno(l) = EAX;
+                       p->n_right = buildtree(ASSIGN, l, r);
+               } else
+#endif
+                       p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0);
+               p->n_op -= (UCALL-CALL);
+
+               if (kflag == 0)
+                       break;
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               regno(l) = EBX;
+               r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
+               p->n_right = block(CM, r, p->n_right, INT, 0, 0);
+               break;
+       
+       /* FALLTHROUGH */
+#if defined(MACHOABI)
+       case CALL:
+       case STCALL:
+               if (p->n_type == VOID)
+                       break;
+
+               r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               l = tcopy(r);
+               p = buildtree(COMOP, buildtree(ASSIGN, r, p), l);
+#endif
+                       
+               break;
+
+#ifdef notyet
+       /* XXX breaks sometimes */
+       case CBRANCH:
+               l = p->n_left;
+
+               /*
+                * Remove unnecessary conversion ops.
+                */
+               if (!clogop(l->n_op) || l->n_left->n_op != SCONV)
+                       break;
+               if (coptype(l->n_op) != BITYPE)
+                       break;
+               if (l->n_right->n_op != ICON)
+                       break;
+               r = l->n_left->n_left;
+               if (r->n_type >= FLOAT)
+                       break;
+               if (toolarge(r->n_type, l->n_right->n_lval))
+                       break;
+               l->n_right->n_type = r->n_type;
+               if (l->n_op >= ULE && l->n_op <= UGT)
+                       l->n_op -= (UGT-ULE);
+               p->n_left = buildtree(l->n_op, r, l->n_right);
+               p1nfree(l->n_left);
+               p1nfree(l);
+               break;
+#endif
+
+       case PCONV:
+               l = p->n_left;
+
+               /* Make int type before pointer */
+               if (l->n_type < INT || l->n_type == LONGLONG || 
+                   l->n_type == ULONGLONG || l->n_type == BOOL) {
+                       /* float etc? */
+                       p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
+               }
+               break;
+
+       case SCONV:
+               if (p->n_left->n_op == COMOP)
+                       break;  /* may propagate wrong type later */
+               l = p->n_left;
+
+               if (p->n_type == l->n_type) {
+                       p1nfree(p);
+                       return l;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) ==
+                   tsize(l->n_type, l->n_df, l->n_ap)) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       p1nfree(p);
+                                       return l;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
+                   l->n_op != QUEST && l->n_op != ASSIGN) {
+                       l->n_type = p->n_type;
+                       p1nfree(p);
+                       return l;
+               }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       /*
+                        * Can only end up here if o is an address,
+                        * and in that case the only compile-time conversion
+                        * possible is to int.
+                        */
+                       if ((TMASK & l->n_type) == 0 && l->n_sp == NULL)
+                               cerror("SCONV ICON");
+                       if (l->n_sp == 0) {
+                               p->n_type = UNSIGNED;
+                               concast(l, m);
+                       } else if (m != INT && m != UNSIGNED)
+                               break;
+                       l->n_type = m;
+                       l->n_ap = 0;
+                       p1nfree(p);
+                       return l;
+               } else if (l->n_op == FCON)
+                       cerror("SCONV FCON");
+               if ((p->n_type == CHAR || p->n_type == UCHAR ||
+                   p->n_type == SHORT || p->n_type == USHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = makety(p->n_left, INT, 0, 0, 0);
+               p->n_right = makety(p->n_right, INT, 0, 0, 0);
+               o = p->n_type;
+               p->n_type = INT;
+               p = makety(p, o, 0, 0, 0);
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(CHAR) : RETREG(p->n_type);
+               break;
+
+       case LS:
+       case RS:
+               /* shift count must be in a char */
+               if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+                       break;
+               p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0);
+               break;
+
+               /* If not using pcc struct return */
+       case STASG:
+               r = p->n_right;
+               if (r->n_op != STCALL && r->n_op != USTCALL)
+                       break;
+               m = tsize(BTYPE(r->n_type), r->n_df, r->n_ap);
+               if (m == SZCHAR)
+                       m = CHAR;
+               else if (m == SZSHORT)
+                       m = SHORT;
+               else if (m == SZINT)
+                       m = INT;
+               else if (m == SZLONGLONG)
+                       m = LONGLONG;
+               else
+                       break;
+#if !defined(os_openbsd)
+               if (attr_find(r->n_ap, ATTR_COMPLEX) == 0)
+                       break;  /* float _Complex always in regs */
+#endif
+               l = buildtree(ADDROF, p->n_left, NIL);
+               p1nfree(p);
+
+               r->n_op -= (STCALL-CALL);
+               r->n_type = m;
+
+               /* r = long, l = &struct */
+
+               n = tempnode(0, m, r->n_df, r->n_ap);
+               r = buildtree(ASSIGN, p1tcopy(n), r);
+
+               s = tempnode(0, l->n_type, l->n_df, l->n_ap);
+               l = buildtree(ASSIGN, p1tcopy(s), l);
+
+               p = buildtree(COMOP, r, l);
+
+               l = buildtree(CAST,
+                   block(NAME, NIL, NIL, m|PTR, 0, 0), p1tcopy(s));
+               r = l->n_right;
+               p1nfree(l->n_left);
+               p1nfree(l);
+
+               r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n);
+               p = buildtree(COMOP, p, r);
+               p = buildtree(COMOP, p, s);
+               break;
+       }
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               p1fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+/*
+ * Change CALL references to either direct (static) or PLT.
+ */
+static void
+fixnames(P1ND *p, void *arg)
+{
+#if defined(ELFABI) || defined(MACHOABI)
+
+       struct symtab *sp;
+       struct attr *ap, *ap2;
+       P1ND *q;
+       char *c;
+       int isu;
+
+       if ((cdope(p->n_op) & CALLFLG) == 0)
+               return;
+       isu = 0;
+       q = p->n_left;
+       ap = q->n_ap;
+       if (q->n_op == UMUL)
+               q = q->n_left, isu = 1;
+
+       if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
+           q->n_right->n_op == ICON) {
+               sp = q->n_right->n_sp;
+
+               if (sp == NULL)
+                       return; /* nothing to do */
+               if (sp->sclass == STATIC && !ISFTN(sp->stype))
+                       return; /* function pointer */
+
+               if (sp->sclass != STATIC && sp->sclass != EXTERN &&
+                   sp->sclass != EXTDEF)
+                       cerror("fixnames");
+               c = NULL;
+#if defined(ELFABI)
+
+               if ((ap2 = attr_find(sp->sap, ATTR_SONAME)) == NULL ||
+                   (c = strstr(ap2->sarg(0), "@GOT")) == NULL)
+                       cerror("fixnames2: %p %s", ap2, c);
+               if (isu) {
+                       memcpy(c, "@PLT", sizeof("@PLT"));
+               } else
+                       *c = 0;
+
+#elif defined(MACHOABI)
+
+               if (sp->soname == NULL ||
+                   ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL &&
+                   (c = strstr(sp->soname, "-L")) == NULL))
+                               cerror("fixnames2");
+
+               if (!ISFTN(sp->stype))
+                       return; /* function pointer */
+
+               if (isu) {
+                       *c = 0;
+                       addstub(&stublist, sp->soname+1);
+                       memcpy(c, "$stub", sizeof("$stub"));
+               } else 
+                       *c = 0;
+
+#endif
+
+               p1nfree(q->n_left);
+               q = q->n_right;
+               if (isu)
+                       p1nfree(p->n_left->n_left);
+               p1nfree(p->n_left);
+               p->n_left = q;
+               q->n_ap = ap;
+       }
+#endif
+}
+
+static void mangle(P1ND *p);
+
+void
+myp2tree(P1ND *p)
+{
+       struct symtab *sp;
+
+       if (kflag)
+               fixnames(p, 0);
+
+       mangle(p);
+
+       if ((p->n_op == STCALL || p->n_op == USTCALL) && 
+           attr_find(p->n_ap, ATTR_COMPLEX) &&
+           strmemb(p->n_ap)->stype == FLOAT)
+               p->n_ap = attr_add(p->n_ap, attr_new(ATTR_I386_FCMPLRET, 1));
+
+       if (p->n_op != FCON)
+               return;
+
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+       sp->sname = NULL;
+
+       locctr(DATA, sp);
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       slval(p, 0);
+       p->n_sp = sp;
+
+       if (kflag) {
+               P1ND *q = optim(picstatic(p1tcopy(p)));
+               *p = *q;
+               p1nfree(q);
+       }
+}
+
+/*ARGSUSED*/
+int
+andable(P1ND *p)
+{
+       return(1);      /* all names can have & taken on them */
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return 0; /* not yet */
+       return 1;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(P1ND *t, P1ND *p, OFFSZ off)
+{
+       P1ND *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       slval(sp, 0);
+       sp->n_rval = STKREG;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+#ifdef MACHOABI        
+       /* align to 16 bytes */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(PLUSEQ, sp, bcon(15)));
+       
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(RSEQ, sp, bcon(4)));
+       
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(LSEQ, sp, bcon(4)));
+#endif
+       
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       slval(sp, 0);
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, P1ND *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+       int i;
+
+       switch (p->n_type) {
+       case LONGLONG:
+       case ULONGLONG:
+               i = (int)(glval(p) >> 32);
+               slval(p, glval(p) & 0xffffffff);
+               p->n_type = INT;
+               inval(off, 32, p);
+               slval(p, i);
+               inval(off+32, 32, p);
+               break;
+       case LDOUBLE:
+               u.i[2] = 0;
+               u.l = (long double)((FLT *)p->n_dcon)->fp;
+#if defined(HOST_BIG_ENDIAN)
+               printf(PRTPREF "\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
+#else
+               printf(PRTPREF "\t.long\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777);
+#endif
+               break;
+       case DOUBLE:
+               u.d = (double)((FLT *)p->n_dcon)->fp;
+#if defined(HOST_BIG_ENDIAN)
+               printf(PRTPREF "\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
+               printf(PRTPREF "\t.long\t%d,%d\n", u.i[0], u.i[1]);
+#endif
+               break;
+       case FLOAT:
+               u.f = (float)((FLT *)p->n_dcon)->fp;
+               printf(PRTPREF "\t.long\t%d\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#if !defined(ELFABI)
+
+#define NCHNAM  256
+       static char text[NCHNAM+1];
+       int i;
+
+       if (p == NULL)
+               return "";
+
+       text[0] = '_';
+       for (i=1; *p && i<NCHNAM; ++i)
+               text[i] = *p++;
+
+       text[i] = '\0';
+       text[NCHNAM] = '\0';  /* truncate */
+
+       return (text);
+
+#else
+
+       return (p == NULL ? "" : p);
+
+#endif
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+
+       }
+       return (type);
+}
+
+void
+calldec(P1ND *p, P1ND *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off;
+       int al;
+       char *name;
+
+       name = getexname(sp);
+       al = talign(sp->stype, sp->sap)/SZCHAR;
+       off = (int)tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+#if defined(MACHOABI) || defined(PECOFFABI)/* && binutils>2.20 */
+       al = ispow2(al);
+       if (sp->sclass == STATIC) {
+               if (sp->slevel == 0)
+                       printf(PRTPREF "\t.lcomm %s,0%o,%d\n", name, off, al);
+               else
+                       printf(PRTPREF "\t.lcomm  " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+       } else {
+               if (sp->slevel == 0)
+                       printf(PRTPREF "\t.comm %s,0%o,%d\n", name, off, al);
+               else
+                       printf(PRTPREF "\t.comm  " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+       }
+#elif defined(ELFABI)
+#ifdef GCC_COMPAT
+       if (attr_find(sp->sap, GCC_ATYP_WEAKREF) != NULL)
+               return;
+#endif
+       if (sp->sclass == STATIC) {
+               if (sp->slevel == 0) {
+                       printf(PRTPREF "\t.local %s\n", name);
+               } else
+                       printf(PRTPREF "\t.local " LABFMT "\n", sp->soffset);
+       }
+       if (sp->slevel == 0)
+               printf(PRTPREF "\t.comm %s,0%o,%d\n", name, off, al);
+       else
+               printf(PRTPREF "\t.comm  " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+#else
+       if (attr_find(sp->sap, GCC_ATYP_WEAKREF) != NULL)
+               return;
+       if (sp->slevel == 0)
+               printf(PRTPREF "\t.%scomm %s,0%o\n",
+                       sp->sclass == STATIC ? "l" : "", name, off);
+       else
+               printf(PRTPREF "\t.%scomm  " LABFMT ",0%o\n", 
+                       sp->sclass == STATIC ? "l" : "", sp->soffset, off);
+#endif
+}
+
+#ifdef TLS
+static int gottls;
+#endif
+#ifdef PECOFFABI
+static int dllindirect;
+#endif
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       char *a2 = pragtok(NULL);
+
+#ifdef TLS
+       if (strcmp(str, "tls") == 0 && a2 == NULL) {
+               gottls = 1;
+               return 1;
+       }
+#endif
+#ifdef PECOFFABI
+       if (strcmp(str, "dllimport") == 0) {
+               dllindirect = 1;
+               return 1;
+       }
+       if (strcmp(str, "dllexport") == 0) {
+               dllindirect = 1;
+               return 1;
+       }
+#endif
+#ifndef AOUTABI
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+#endif
+       if (strcmp(str, "alias") == 0 && a2 != NULL) {
+               alias = tmpstrdup(a2);
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+#ifdef GCC_COMPAT
+       struct attr *ap;
+#endif
+
+#ifdef TLS
+       /* may have sanity checks here */
+       if (gottls)
+               sp->sflags |= STLS;
+       gottls = 0;
+#endif
+#ifdef GCC_COMPAT
+#ifdef HAVE_WEAKREF
+       /* not many as'es have this directive */
+       if ((ap = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
+               char *wr = ap->sarg(0);
+               char *sn = getsoname(sp);
+               if (sp->sclass != STATIC && sp->sclass != USTATIC)
+                       uerror("weakref %s must be static", sp->sname);
+               if (wr == NULL) {
+                       if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS))) {
+                               wr = ap->sarg(0);
+                       }
+               }
+               if (wr == NULL)
+                       printf(PRTPREF "\t.weak %s\n", sn);
+               else
+                       printf(PRTPREF "\t.weakref %s,%s\n", sn, wr);
+       } else
+#endif
+           if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
+               char *an = ap->sarg(0);  
+               char *v;
+               char *sn = getsoname(sp);
+
+               v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
+               printf(PRTPREF "\t.%s %s\n", v, sn);
+               printf(PRTPREF "\t.set %s,%s\n", sn, an);
+       }       
+#endif
+       if (alias != NULL && (sp->sclass != PARAM)) {
+               char *name = getexname(sp);
+               printf(PRTPREF "\t.globl %s\n", name);
+               printf(PRTPREF "%s = ", name);
+               printf("%s\n", exname(alias));
+               alias = NULL;
+       }
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+#if defined(ELFABI)
+               printf(PRTPREF "\t.section .%ctors,\"aw\",@progbits\n",
+                   constructor ? 'c' : 'd');
+#elif defined(PECOFFABI)
+               printf(PRTPREF "\t.section .%ctors,\"w\"\n",
+                   constructor ? 'c' : 'd');
+#elif defined(MACHOABI)
+               if (kflag) {
+                       if (constructor)
+                               printf(PRTPREF "\t.mod_init_func\n");
+                       else
+                               printf(PRTPREF "\t.mod_term_func\n");
+               } else {
+                       if (constructor)
+                               printf(PRTPREF "\t.constructor\n");
+                       else
+                               printf(PRTPREF "\t.destructor\n");
+               }
+#elif defined(AOUTABI)
+               uerror("constructor/destructor are not supported for this target");
+#endif
+               printf(PRTPREF "\t.p2align 2\n");
+               printf(PRTPREF "\t.long %s\n", exname(sp->sname));
+#if defined(ELFABI)
+               printf(PRTPREF "\t.previous\n");
+#else
+               printf(PRTPREF "\t.text\n");
+#endif
+               constructor = destructor = 0;
+       }
+#ifdef PECOFFABI
+       if (dllindirect && (sp->sclass != PARAM)) {
+               sp->sflags |= SDLLINDIRECT;
+               dllindirect = 0;
+       }
+#endif
+}
+
+/*
+ *  Postfix external functions with the arguments size.
+ */
+static void
+mangle(P1ND *p)
+{
+       P1ND *l;
+
+       if (p->n_op != CALL && p->n_op != STCALL &&
+           p->n_op != UCALL && p->n_op != USTCALL)
+               return;
+
+       l = p->n_left;
+       while (cdope(l->n_op) & CALLFLG)
+               l = l->n_left;
+       if (l->n_op == TEMP)
+               return;
+       if (l->n_op == ADDROF)
+               l = l->n_left;
+       if (l->n_sp == NULL)
+               return;
+#ifdef GCC_COMPAT
+       if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
+               l->n_sp->sflags |= SSTDCALL;
+#endif
+#ifdef PECOFFABI
+       if (l->n_sp->sflags & SSTDCALL) {
+               if (strchr(l->n_name, '@') == NULL) {
+                       int size = 0;
+                       char buf[256];
+                       P1ND *r;
+                       TWORD t;
+
+                       if (p->n_op == CALL || p->n_op == STCALL) {
+                               for (r = p->n_right;    
+                                   r->n_op == CM; r = r->n_left) {
+                                       t = r->n_type;
+                                       if (t == STRTY || t == UNIONTY)
+                                               size += tsize(t, r->n_df, r->n_ap);
+                                       else
+                                               size += szty(t) * SZINT / SZCHAR;
+                               }
+                               t = r->n_type;
+                               if (t == STRTY || t == UNIONTY)
+                                       size += tsize(t, r->n_df, r->n_ap);
+                               else
+                                       size += szty(t) * SZINT / SZCHAR;
+                       }
+                       size = snprintf(buf, 256, "%s@%d", l->n_name, size) + 1;
+                       l->n_name = IALLOC(size);
+                       memcpy(l->n_name, buf, size);
+               }
+       }
+#endif
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+       if (ip->type == IP_NODE &&
+           (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) &&
+           ISFTY(ip->ip_node->n_type))
+               ip->ip_node->n_ap = attr_add(ip->ip_node->n_ap,
+                   attr_new(ATTR_I386_FPPOP, 1));
+       if (ip->type == IP_EPILOG) {
+               struct interpass_prolog *ipp = (struct interpass_prolog *)ip;
+               ipp->ipp_argstacksize = argstacksize;
+       }
+}
+
+#ifdef PASS1
+void
+mflags(char *s)
+{
+}
+#endif
diff --git a/lang/pcc/pcc/arch/i386/local2.c b/lang/pcc/pcc/arch/i386/local2.c
new file mode 100644 (file)
index 0000000..4957ff7
--- /dev/null
@@ -0,0 +1,1555 @@
+/*     $Id: local2.c,v 1.187 2016/03/13 10:14:25 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+#if defined(PECOFFABI) || defined(MACHOABI) || defined(AOUTABI)
+#define EXPREFIX       "_"
+#else
+#define EXPREFIX       ""
+#endif
+
+int msettings = MI686;
+static int stkpos;
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static int regoff[7];
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+       int i;
+
+#if 1
+#if defined(MACHOABI)
+       addto += 8;
+#endif
+       if (addto == 0 || addto > 65535) {
+               printf("        pushl %%ebp\n\tmovl %%esp,%%ebp\n");
+               if (addto)
+                       printf("        subl $%d,%%esp\n", addto);
+       } else
+               printf("        enter $%d,$0\n", addto);
+#endif
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i))
+                       printf("        movl %s,-%d(%s)\n",
+                           rnames[i], regoff[i], rnames[FPREG]);
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+       int i, addto;
+
+       addto = p2maxautooff;
+       if (addto >= AUTOINIT/SZCHAR)
+               addto -= AUTOINIT/SZCHAR;
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       addto += SZINT/SZCHAR;
+                       regoff[i] = addto;
+               }
+       return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+
+       ftype = ipp->ipp_type;
+
+#ifdef LANG_F77
+       if (ipp->ipp_vis)
+               printf("        .globl %s\n", ipp->ipp_name);
+       printf("        .align 4\n");
+       printf("%s:\n", ipp->ipp_name);
+#endif
+       /*
+        * We here know what register to save and how much to 
+        * add to the stack.
+        */
+       addto = offcalc(ipp);
+#if defined(MACHOABI)
+       addto = (addto + 15) & ~15;     /* stack alignment */
+#endif
+       prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       int i;
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       /* return from function code */
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i))
+                       printf("        movl -%d(%s),%s\n",
+                           regoff[i], rnames[FPREG], rnames[i]);
+
+       /* struct return needs special treatment */
+       if (ftype == STRTY || ftype == UNIONTY) {
+               printf("        movl 8(%%ebp),%%eax\n");
+               printf("        leave\n");
+               printf("        ret $%d\n", 4 + ipp->ipp_argstacksize);
+       } else {
+               printf("        leave\n");
+               if (ipp->ipp_argstacksize)
+                       printf("        ret $%d\n", ipp->ipp_argstacksize);
+               else
+                       printf("        ret\n");
+       }
+
+#if defined(ELFABI)
+       printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name,
+           ipp->ipp_name);
+#endif
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int u;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       u = p->n_op;
+       switch (p->n_op) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               u += (ULE-LE);
+               /* FALLTHROUGH */
+       case ULE:
+       case ULT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               u += (ULE-LE);
+               /* FALLTHROUGH */
+       case UGE:
+       case UGT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       expand(p, 0, "  cmpl UR,UL\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+       expand(p, 0, "  cmpl AR,AL\n");
+       cbgen(u, e);
+       deflab(s);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       comperr("fldexpand");
+       return 0;
+}
+
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+       struct attr *ap;
+       NODE *q = p->n_left;
+
+       ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+       printf("        subl $%d,%%esp\n", (ap->iarg(0) + 3) & ~3);
+       p->n_left = mklnode(OREG, 0, ESP, INT);
+       zzzcode(p, 'Q');
+       tfree(p->n_left);
+       p->n_left = q;
+}
+
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p)  
+{
+       static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
+
+       if (msettings & MI686) {
+               if ((p->n_su & DORIGHT) == 0)
+                       expand(p, 0, "\tfxch\n");
+               expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn  */
+               expand(p, 0, "\tfstp %st(0)\n");        /* pop fromstack */
+
+               if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
+                       expand(p, 0, "\tjp LC\n");
+               else if (p->n_op == EQ)
+                       printf("\tjp 1f\n");
+               printf("        %s ", fpcb[p->n_op - EQ]);
+               expand(p, 0, "LC\n");
+               if (p->n_op == EQ)
+                       printf("1:\n");
+       } else {
+               int swap = ((p->n_su & DORIGHT) == 0);
+
+               if (p->n_op == GT || p->n_op == GE)
+                       swap ^= 1;
+               if (swap)
+                       expand(p, 0, "\tfxch\n");
+
+               /*
+                * Flags for x87:
+                * C3 C2 C0
+                * 0  0  0      st0 > st1
+                * 0  0  1      st0 < st1
+                * 1  0  0      st0 = st1
+                * 1  1  1      unordered
+                */
+
+               /* ax avoided in nspecial() */
+               printf("\tfucompp\n\tfnstsw %%ax\n");
+               if (p->n_op == GE || p->n_op == LE) {
+                       printf("\ttestb $0x45,%%ah\n");
+               } else if (p->n_op == GT || p->n_op == LT) {
+                       printf("\ttestb $0x05,%%ah\n");
+               } else if (p->n_op == NE) {
+                       printf("\tandb $0x45,%%ah\n");
+                       printf("\txorb $0x40,%%ah\n");
+               } else if (p->n_op == EQ) {
+                       printf("\tandb $0x45,%%ah\n");
+                       printf("\tcmpb $0x40,%%ah\n");
+               }
+               if (p->n_op == EQ) {
+                       expand(p, 0, "\tje LC\n");
+               } else
+                       expand(p, 0, "\tjne LC\n");
+       }
+}
+
+/*
+ * Convert an unsigned long long to floating point number.
+ */
+static void
+ulltofp(NODE *p)
+{
+       int jmplab;
+
+#if defined(ELFABI) || defined(PECOFFABI) || defined(AOUTABI)
+       static int loadlab;
+
+       if (loadlab == 0) {
+               loadlab = getlab2();
+               expand(p, 0, "  .data\n");
+               printf(LABFMT ":        .long 0,0x80000000,0x403f\n", loadlab);
+               expand(p, 0, "  .text\n");
+       }
+#endif
+
+       jmplab = getlab2();
+       expand(p, 0, "  pushl UL\n      pushl AL\n");
+       expand(p, 0, "  fildq (%esp)\n");
+       expand(p, 0, "  addl $8,%esp\n");
+       expand(p, 0, "  cmpl $0,UL\n");
+       printf("        jge " LABFMT "\n", jmplab);
+
+#if defined(ELFABI) || defined(AOUTABI)
+       printf("        fldt " LABFMT "%s\n", loadlab, kflag ? "@GOTOFF" : "");
+#elif defined(MACHOABI)
+       printf("\tpushl 0x5f800000\n");
+       printf("\tfadds (%%esp)\n");
+       printf("\taddl $4,%%esp\n");
+#else
+#error incomplete implementation
+#endif
+
+       printf("        faddp %%st,%%st(1)\n");
+       printf(LABFMT ":\n", jmplab);
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (t < LONGLONG || t == FLOAT || t > BTMASK)
+               return 4;
+       if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+               return 8;
+       if (t == LDOUBLE)
+               return 12;
+       if (t == STRTY || t == UNIONTY)
+               return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) & ~3;
+       comperr("argsiz");
+       return 0;
+}
+
+static void
+fcast(NODE *p)
+{
+       TWORD t = p->n_type;
+       int sz, c;
+
+       if (t >= p->n_left->n_type)
+               return; /* cast to more precision */
+       if (t == FLOAT)
+               sz = 4, c = 's';
+       else
+               sz = 8, c = 'l';
+
+       printf("        sub $%d,%%esp\n", sz);
+       printf("        fstp%c (%%esp)\n", c);
+       printf("        fld%c (%%esp)\n", c);
+       printf("        add $%d,%%esp\n", sz);
+}
+
+static void
+llshft(NODE *p)
+{
+       char *d[3];
+
+       if (p->n_op == LS) {
+               d[0] = "l", d[1] = "%eax", d[2] = "%edx";
+       } else
+               d[0] = "r", d[1] = "%edx", d[2] = "%eax";
+
+       printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]);
+       printf("\ts%s%sl %%cl,%s\n", p->n_op == RS &&
+           p->n_left->n_type == ULONGLONG ? "h" : "a", d[0], d[1]);
+       printf("\ttestb $32,%%cl\n");
+       printf("\tje 1f\n");
+       printf("\tmovl %s,%s\n", d[1], d[2]);
+       if (p->n_op == RS && p->n_left->n_type == LONGLONG)
+               printf("\tsarl $31,%%edx\n");
+       else
+               printf("\txorl %s,%s\n",d[1],d[1]);
+       printf("1:\n");
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       struct attr *ap;
+       NODE *l;
+       int pr, lr;
+       char *ch;
+
+       switch (c) {
+       case 'A': /* swap st0 and st1 if right is evaluated second */
+               if ((p->n_su & DORIGHT) == 0) {
+                       if (logop(p->n_op))
+                               printf("        fxch\n");
+                       else
+                               printf("r");
+               }
+               break;
+
+       case 'C':  /* remove from stack after subroutine call */
+#ifdef GCC_COMPAT
+               if (attr_find(p->n_left->n_ap, GCC_ATYP_STDCALL))
+                       break;
+#endif
+               pr = p->n_qual;
+               if (attr_find(p->n_ap, ATTR_I386_FPPOP))
+                       printf("        fstp    %%st(0)\n");
+               if (p->n_op == UCALL)
+                       return; /* XXX remove ZC from UCALL */
+               if (pr)
+                       printf("        addl $%d, %s\n", pr, rnames[ESP]);
+#if defined(os_openbsd)
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               if (p->n_op == STCALL && (ap->iarg(0) == 1 ||
+                   ap->iarg(0) == 2 || ap->iarg(0) == 4 || 
+                   ap->iarg(0) == 8)) {
+                       /* save on stack */
+                       printf("\tmovl %%eax,-%d(%%ebp)\n", stkpos);
+                       printf("\tmovl %%edx,-%d(%%ebp)\n", stkpos+4);
+                       printf("\tleal -%d(%%ebp),%%eax\n", stkpos);
+               }
+#endif
+               break;
+
+       case 'D': /* Long long comparision */
+               twollcomp(p);
+               break;
+
+       case 'F': /* Structure argument */
+               starg(p);
+               break;
+
+       case 'G': /* Floating point compare */
+               fcomp(p);
+               break;
+
+       case 'H': /* assign of longlong between regs */
+               rmove(DECRA(p->n_right->n_reg, 0),
+                   DECRA(p->n_left->n_reg, 0), LONGLONG);
+               break;
+
+       case 'I': /* float casts */
+               fcast(p);
+               break;
+
+       case 'J': /* convert unsigned long long to floating point */
+               ulltofp(p);
+               break;
+
+       case 'K': /* Load longlong reg into another reg */
+               rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
+               break;
+
+       case 'M': /* Output sconv move, if needed */
+               l = getlr(p, 'L');
+               /* XXX fixneed: regnum */
+               pr = DECRA(p->n_reg, 0);
+               lr = DECRA(l->n_reg, 0);
+               if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
+                   (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
+                       ;
+               else
+                       printf("        movb %%%cl,%s\n",
+                           rnames[lr][2], rnames[pr]);
+               l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
+               break;
+
+       case 'N': /* output extended reg name */
+               printf("%s", rnames[getlr(p, '1')->n_rval]);
+               break;
+
+       case 'O': /* print out emulated ops */
+               pr = 16;
+               if (p->n_op == RS || p->n_op == LS) {
+                       llshft(p);
+                       break;
+               } else if (p->n_op == MUL) {
+                       printf("\timull %%ecx, %%edx\n");
+                       printf("\timull %%eax, %%esi\n");
+                       printf("\taddl %%edx, %%esi\n");
+                       printf("\tmull %%ecx\n");
+                       printf("\taddl %%esi, %%edx\n");
+                       break;
+               }
+               expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
+               expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
+               if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
+               else if (p->n_op == DIV) ch = "div";
+               else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
+               else if (p->n_op == MOD) ch = "mod";
+               else ch = 0, comperr("ZO");
+#ifdef ELFABI
+               printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n",
+                       ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]);
+#else
+               printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
+                       ch, pr, rnames[ESP]);
+#endif
+                break;
+
+       case 'Q': /* emit struct assign */
+               /*
+                * Put out some combination of movs{b,w,l}
+                * esi/edi/ecx are available.
+                */
+               expand(p, INAREG, "     leal AL,%edi\n");
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               if (ap->iarg(0) < 32) {
+                       int i = ap->iarg(0) >> 2;
+                       while (i) {
+                               expand(p, INAREG, "     movsl\n");
+                               i--;
+                       }
+               } else {
+                       printf("\tmovl $%d,%%ecx\n", ap->iarg(0) >> 2);
+                       printf("        rep movsl\n");
+               }
+               if (ap->iarg(0) & 2)
+                       printf("        movsw\n");
+               if (ap->iarg(0) & 1)
+                       printf("        movsb\n");
+               break;
+
+       case 'S': /* emit eventual move after cast from longlong */
+               pr = DECRA(p->n_reg, 0);
+               lr = p->n_left->n_rval;
+               switch (p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
+                           rnames[pr][1] == rnames[lr][1])
+                               break;
+                       if (rnames[lr][2] == 'x') {
+                               printf("\tmovb %%%cl,%s\n",
+                                   rnames[lr][1], rnames[pr]);
+                               break;
+                       }
+                       /* Must go via stack */
+                       expand(p, INAREG, "\tmovl AL,A2\n");
+                       expand(p, INBREG, "\tmovb A2,A1\n");
+#ifdef notdef
+                       /* cannot use freetemp() in instruction emission */
+                       s = freetemp(1);
+                       printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
+                       printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
+#endif
+                       break;
+
+               case SHORT:
+               case USHORT:
+                       if (rnames[lr][1] == rnames[pr][2] &&
+                           rnames[lr][2] == rnames[pr][3])
+                               break;
+                       printf("\tmovw %%%c%c,%%%s\n",
+                           rnames[lr][1], rnames[lr][2], rnames[pr]+2);
+                       break;
+               case INT:
+               case UNSIGNED:
+                       if (rnames[lr][1] == rnames[pr][2] &&
+                           rnames[lr][2] == rnames[pr][3])
+                               break;
+                       printf("\tmovl %%e%c%c,%s\n",
+                                   rnames[lr][1], rnames[lr][2], rnames[pr]);
+                       break;
+
+               default:
+                       if (rnames[lr][1] == rnames[pr][2] &&
+                           rnames[lr][2] == rnames[pr][3])
+                               break;
+                       comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
+                       break;
+               }
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       comperr("flshape");
+       return 0;
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = (int)getlval(p);
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+%d", val);
+               } else
+                       fprintf(fp, "%d", val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%%%s", &rnames[p->n_rval][3]);
+               break;
+
+       case NAME:
+       case OREG:
+               setlval(p, getlval(p) + size);
+               adrput(stdout, p);
+               setlval(p, getlval(p) - size);
+               break;
+       case ICON:
+               printf("$" CONFMT, getlval(p) >> 32);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       int r;
+       /* output an address, with offsets, from p */
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       fputs(p->n_name, io);
+                       if (getlval(p) != 0)
+                               fprintf(io, "+" CONFMT, getlval(p));
+               } else
+                       fprintf(io, CONFMT, getlval(p));
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               if (p->n_name[0])
+                       printf("%s%s", p->n_name, getlval(p) ? "+" : "");
+               if (getlval(p))
+                       fprintf(io, "%d", (int)getlval(p));
+               if (R2TEST(r)) {
+                       fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)],
+                           rnames[R2UPK2(r)]);
+               } else
+                       fprintf(io, "(%s)", rnames[p->n_rval]);
+               return;
+       case ICON:
+#ifdef PCC_DEBUG
+               /* Sanitycheck for PIC, to catch adressable constants */
+               if (kflag && p->n_name[0] && 0) {
+                       static int foo;
+
+                       if (foo++ == 0) {
+                               printf("\nfailing...\n");
+                               fwalk(p, e2print, 0);
+                               comperr("pass2 conput");
+                       }
+               }
+#endif
+               /* addressable value of the constant */
+               fputc('$', io);
+               conput(io, p);
+               return;
+
+       case REG:
+               switch (p->n_type) {
+               case LONGLONG:
+               case ULONGLONG:
+                       fprintf(io, "%%%c%c%c", rnames[p->n_rval][0],
+                           rnames[p->n_rval][1], rnames[p->n_rval][2]);
+                       break;
+               case SHORT:
+               case USHORT:
+                       fprintf(io, "%%%s", &rnames[p->n_rval][2]);
+                       break;
+               default:
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               }
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+static char *
+ccbranches[] = {
+       "je",           /* jumpe */
+       "jne",          /* jumpn */
+       "jle",          /* jumple */
+       "jl",           /* jumpl */
+       "jge",          /* jumpge */
+       "jg",           /* jumpg */
+       "jbe",          /* jumple (jlequ) */
+       "jb",           /* jumpl (jlssu) */
+       "jae",          /* jumpge (jgequ) */
+       "ja",           /* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("        %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static void
+fixcalls(NODE *p, void *arg)
+{
+       struct attr *ap;
+
+       /* Prepare for struct return by allocating bounce space on stack */
+       switch (p->n_op) {
+       case STCALL:
+       case USTCALL:
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               if (ap->iarg(0)+p2autooff > stkpos)
+                       stkpos = ap->iarg(0)+p2autooff;
+               if (8+p2autooff > stkpos)
+                       stkpos = ap->iarg(0)+p2autooff;
+               break;
+       case LS:
+       case RS:
+               if (p->n_type != LONGLONG && p->n_type != ULONGLONG)
+                       break;
+               if (p->n_right->n_op == ICON) /* constants must be char */
+                       p->n_right->n_type = CHAR;
+               break;
+       }
+}
+
+/*
+ * Must store floats in memory if there are two function calls involved.
+ */
+static int
+storefloat(struct interpass *ip, NODE *p)
+{
+       int l, r;
+
+       switch (optype(p->n_op)) {
+       case BITYPE:
+               l = storefloat(ip, p->n_left);
+               r = storefloat(ip, p->n_right);
+               if (p->n_op == CM)
+                       return 0; /* arguments, don't care */
+               if (callop(p->n_op))
+                       return 1; /* found one */
+#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
+       (p)->n_type == LDOUBLE)
+               if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
+                       /* must store one. store left */
+                       struct interpass *nip;
+                       TWORD t = p->n_left->n_type;
+                       NODE *ll;
+                       int off;
+
+                       off = freetemp(szty(t));
+                       ll = mklnode(OREG, off, FPREG, t);
+                       nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
+                       p->n_left = mklnode(OREG, off, FPREG, t);
+                       DLIST_INSERT_BEFORE(ip, nip, qelem);
+               }
+               return l|r;
+
+       case UTYPE:
+               l = storefloat(ip, p->n_left);
+               if (callop(p->n_op))
+                       l = 1;
+               return l;
+       default:
+               return 0;
+       }
+}
+
+static void
+outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
+{
+       struct interpass *ip2;
+       NODE *q, *r;
+       int i;
+
+       for (i = 0; i < num; i++)
+               if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT)))
+                       break;
+       if (i == num)
+               return;
+       q = ary[i]->n_left;
+       r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
+       ary[i]->n_left = tcopy(r);
+       ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type));
+       DLIST_INSERT_AFTER(ip, ip2, qelem);
+}
+
+static void
+infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
+{
+       struct interpass *ip2;
+       NODE *q, *r;
+       int i;
+
+       for (i = 0; i < num; i++)
+               if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0)
+                       break;
+       if (i == num)
+               return;
+       q = ary[i]->n_left;
+       q = (cwp[i] & XASMINOUT) ? tcopy(q) : q;
+       r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
+       if ((cwp[i] & XASMINOUT) == 0)
+               ary[i]->n_left = tcopy(r);
+       ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type));
+       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+}
+
+/*
+ * Extract float args to XASM and ensure that they are put on the stack
+ * in correct order.
+ * This should be done sow other way.
+ */
+static void
+fixxfloat(struct interpass *ip, NODE *p)
+{
+       NODE *w, **ary;
+       int nn, i, c, *cwp;
+
+       nn = 1;
+       w = p->n_left;
+       if (w->n_op == ICON && w->n_type == STRTY)
+               return;
+       /* index all xasm args first */
+       for (; w->n_op == CM; w = w->n_left)
+               nn++;
+       ary = tmpcalloc(nn * sizeof(NODE *));
+       cwp = tmpcalloc(nn * sizeof(int));
+       for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) {
+               ary[i] = w->n_right;
+               cwp[i] = xasmcode(ary[i]->n_name);
+               i++;
+       }
+       ary[i] = w;
+       cwp[i] = xasmcode(ary[i]->n_name);
+       for (i = 0; i < nn; i++)
+               if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u')
+                       break;
+       if (i == nn)
+               return;
+
+       for (i = 0; i < nn; i++) {
+               c = XASMVAL(cwp[i]);
+               if (c >= '0' && c <= '9')
+                       cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']);
+       }
+       infargs(ip, ary, nn, cwp, 'u');
+       infargs(ip, ary, nn, cwp, 't');
+       outfargs(ip, ary, nn, cwp, 't');
+       outfargs(ip, ary, nn, cwp, 'u');
+}
+
+static NODE *
+lptr(NODE *p)
+{
+       if (p->n_op == ASSIGN && p->n_right->n_op == REG &&
+           regno(p->n_right) == EBP)
+               return p->n_right;
+       if (p->n_op == FUNARG && p->n_left->n_op == REG &&
+           regno(p->n_left) == EBP)
+               return p->n_left;
+       return NIL;
+}
+
+/*
+ * Find arg reg that should be struct reference instead.
+ */
+static void
+updatereg(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op != STCALL)
+               return;
+#if defined(os_openbsd)
+       struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+       if (ap->iarg(0) == 1 || ap->iarg(0) == 2 || ap->iarg(0) == 4 || 
+           ap->iarg(0) == 8)
+               return;
+#endif
+       if (attr_find(p->n_ap, ATTR_I386_FCMPLRET))
+               return;
+
+       if (p->n_right->n_op != CM)
+               p = p->n_right;
+       else for (p = p->n_right;
+           p->n_op == CM && p->n_left->n_op == CM; p = p->n_left)
+               ;
+       if (p->n_op == CM) {
+               if ((q = lptr(p->n_left)))
+                       ;
+               else
+                       q = lptr(p->n_right);
+       } else
+               q = lptr(p);
+       if (q == NIL)
+               comperr("bad STCALL hidden reg");
+
+       /* q is now the hidden arg */
+       q->n_op = MINUS;
+       q->n_type = INCREF(CHAR);
+       q->n_left = mklnode(REG, 0, EBP, INCREF(CHAR));
+       q->n_right = mklnode(ICON, stkpos, 0, INT);
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       stkpos = p2autooff;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, fixcalls, 0);
+               storefloat(ip, ip->ip_node);
+               if (ip->ip_node->n_op == XASM)
+                       fixxfloat(ip, ip->ip_node);
+       }
+       if (stkpos != p2autooff) {
+               DLIST_FOREACH(ip, ipole, qelem) {
+                       if (ip->type != IP_NODE)
+                               continue;
+                       walkf(ip->ip_node, updatereg, 0);
+               }
+       }
+       if (stkpos > p2autooff)
+               p2autooff = stkpos;
+       if (stkpos > p2maxautooff)
+               p2maxautooff = stkpos;
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+static char rl[] =
+  { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI };
+static char rh[] =
+  { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI };
+
+void
+rmove(int s, int d, TWORD t)
+{
+       int sl, sh, dl, dh;
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+#if 1
+               sl = rl[s-EAXEDX];
+               sh = rh[s-EAXEDX];
+               dl = rl[d-EAXEDX];
+               dh = rh[d-EAXEDX];
+
+               /* sanity checks, remove when satisfied */
+               if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
+                   memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
+                       comperr("rmove source error");
+               if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
+                   memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
+                       comperr("rmove dest error");
+#define        SW(x,y) { int i = x; x = y; y = i; }
+               if (sh == dl) {
+                       /* Swap if overwriting */
+                       SW(sl, sh);
+                       SW(dl, dh);
+               }
+               if (sl != dl)
+                       printf("        movl %s,%s\n", rnames[sl], rnames[dl]);
+               if (sh != dh)
+                       printf("        movl %s,%s\n", rnames[sh], rnames[dh]);
+#else
+               if (memcmp(rnames[s], rnames[d], 3) != 0)
+                       printf("        movl %%%c%c%c,%%%c%c%c\n",
+                           rnames[s][0],rnames[s][1],rnames[s][2],
+                           rnames[d][0],rnames[d][1],rnames[d][2]);
+               if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0)
+                       printf("        movl %%%c%c%c,%%%c%c%c\n",
+                           rnames[s][3],rnames[s][4],rnames[s][5],
+                           rnames[d][3],rnames[d][4],rnames[d][5]);
+#endif
+               break;
+       case CHAR:
+       case UCHAR:
+               printf("        movb %s,%s\n", rnames[s], rnames[d]);
+               break;
+       case FLOAT:
+       case DOUBLE:
+       case LDOUBLE:
+#ifdef notdef
+               /* a=b()*c(); will generate this */
+               comperr("bad float rmove: %d %d", s, d);
+#endif
+               break;
+       default:
+               printf("        movl %s,%s\n", rnames[s], rnames[d]);
+       }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num;
+
+       switch (c) {
+       case CLASSA:
+               num = r[CLASSB] > 4 ? 4 : r[CLASSB];
+               num += 2*r[CLASSC];
+               num += r[CLASSA];
+               return num < 6;
+       case CLASSB:
+               num = r[CLASSA];
+               num += 2*r[CLASSC];
+               num += r[CLASSB];
+               return num < 4;
+       case CLASSC:
+               num = r[CLASSA];
+               num += r[CLASSB] > 4 ? 4 : r[CLASSB];
+               num += 2*r[CLASSC];
+               return num < 5;
+       case CLASSD:
+               return r[CLASSD] < DREGCNT;
+       }
+       return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+       "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
+       "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh",
+       "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx",
+       "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi",
+       "ebxesi", "ebxedi", "esiedi",
+       "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == CHAR || t == UCHAR)
+               return CLASSB;
+       if (t == LONGLONG || t == ULONGLONG)
+               return CLASSC;
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return CLASSD;
+       return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int nr = 0, size = 0;
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left) { 
+               if (p->n_right->n_op != ASSIGN)
+                       size += argsiz(p->n_right);
+               else
+                       nr = 1;
+       }
+       if (p->n_op != ASSIGN)
+               size += argsiz(p);
+       else
+               nr++;
+       if (op->n_op == STCALL) {
+               if (kflag)
+                       nr--;
+               if (nr == 0)
+                       size -= 4; /* XXX OpenBSD? */
+       }
+
+#if defined(MACHOABI)
+       int newsize = (size + 15) & ~15;        /* stack alignment */
+       int align = newsize-size;
+
+       if (align != 0)
+               printf("        subl $%d,%%esp\n", align);
+
+       size=newsize;
+#endif
+       
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       int o = p->n_op;
+
+       switch (shape) {
+       case SFUNCALL:
+               if (o == STCALL || o == USTCALL)
+                       return SRREG;
+               break;
+       case SPCON:
+               if (o != ICON || p->n_name[0] ||
+                   getlval(p) < 0 || getlval(p) > 0x7fffffff)
+                       break;
+               return SRDIR;
+       case SMIXOR:
+               return tshape(p, SZERO);
+       case SMILWXOR:
+               if (o != ICON || p->n_name[0] ||
+                   getlval(p) == 0 || getlval(p) & 0xffffffff)
+                       break;
+               return SRDIR;
+       case SMIHWXOR:
+               if (o != ICON || p->n_name[0] ||
+                    getlval(p) == 0 || (getlval(p) >> 32) != 0)
+                       break;
+               return SRDIR;
+       }
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+#define        MSET(s,a) if (strcmp(str, s) == 0) \
+       msettings = (msettings & ~MCPUMSK) | a
+
+       MSET("arch=i386",MI386);
+       MSET("arch=i486",MI486);
+       MSET("arch=i586",MI586);
+       MSET("arch=i686",MI686);
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       struct interpass *ip2;
+       int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
+       NODE *in = 0, *ut = 0;
+       TWORD t;
+       char *w;
+       int reg;
+       int c, cw;
+       CONSZ v;
+
+       cw = xasmcode(p->n_name);
+       if (cw & (XASMASG|XASMINOUT))
+               ut = p->n_left;
+       if ((cw & XASMASG) == 0)
+               in = p->n_left;
+
+       c = XASMVAL(cw);
+       switch (c) {
+       case 'D': reg = EDI; break;
+       case 'S': reg = ESI; break;
+       case 'a': reg = EAX; break;
+       case 'b': reg = EBX; break;
+       case 'c': reg = ECX; break;
+       case 'd': reg = EDX; break;
+
+       case 't':
+       case 'u':
+               p->n_name = tmpstrdup(p->n_name);
+               w = strchr(p->n_name, XASMVAL(cw));
+               *w = 'r'; /* now reg */
+               return 1;
+
+       case 'A': reg = EAXEDX; break;
+       case 'q': {
+               /* Set edges in MYSETXARG */
+               if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
+                       return 1;
+               t = p->n_left->n_type;
+               if (in && ut)
+                       in = tcopy(in);
+               p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
+               if (ut) {
+                       ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+                       DLIST_INSERT_AFTER(ip, ip2, qelem);
+               }
+               if (in) {
+                       ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+                       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+               }
+               return 1;
+       }
+
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+               if (p->n_left->n_op != ICON) {
+                       if ((c = XASMVAL1(cw)) != 0) {
+                               p->n_name++;
+                               return 0; /* Try again */
+                       }
+                       uerror("xasm arg not constant");
+               }
+               v = getlval(p->n_left);
+               if ((c == 'K' && v < -128) ||
+                   (c == 'L' && v != 0xff && v != 0xffff) ||
+                   (c != 'K' && v < 0) ||
+                   (v > Cmax[c-'I']))
+                       uerror("xasm val out of range");
+               p->n_name = "i";
+               return 1;
+
+       default:
+               return 0;
+       }
+       /* If there are requested either memory or register, delete memory */
+       w = p->n_name = tmpstrdup(p->n_name);
+       if (*w == '=')
+               w++;
+       *w++ = 'r';
+       *w = 0;
+
+       t = p->n_left->n_type;
+       if (reg == EAXEDX) {
+               ;
+       } else {
+               if (t == CHAR || t == UCHAR) {
+                       reg = reg * 2 + 8;
+               }
+       }
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
+               reg += 037;
+       }
+
+       if (in && ut)
+               in = tcopy(in);
+       p->n_left = mklnode(REG, 0, reg, t);
+       if (ut) {
+               ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+               DLIST_INSERT_AFTER(ip, ip2, qelem);
+       }
+       if (in) {
+               ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+               DLIST_INSERT_BEFORE(ip, ip2, qelem);
+       }
+       return 1;
+}
+
+void
+targarg(char *w, void *arg)
+{
+       NODE **ary = arg;
+       NODE *p, *q;
+
+       if (ary[(int)w[1]-'0'] == 0)
+               p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */
+       else
+               p = ary[(int)w[1]-'0']->n_left;
+       if (optype(p->n_op) != LTYPE)
+               comperr("bad xarg op %d", p->n_op);
+       q = tcopy(p);
+       if (q->n_op == REG) {
+               if (*w == 'k') {
+                       q->n_type = INT;
+               } else if (*w != 'w') {
+                       if (q->n_type > UCHAR) {
+                               regno(q) = regno(q)*2+8;
+                               if (*w == 'h')
+                                       regno(q)++;
+                       }
+                       q->n_type = INT;
+               } else
+                       q->n_type = SHORT;
+       }
+       adrput(stdout, q);
+       tfree(q);
+}
+
+/*
+ * target-specific conversion of numeric arguments.
+ */
+int
+numconv(void *ip, void *p1, void *q1)
+{
+       NODE *p = p1, *q = q1;
+       int cw = xasmcode(q->n_name);
+
+       switch (XASMVAL(cw)) {
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+               p->n_name = tmpcalloc(2);
+               p->n_name[0] = (char)XASMVAL(cw);
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static struct {
+       char *name; int num;
+} xcr[] = {
+       { "eax", EAX },
+       { "ebx", EBX },
+       { "ecx", ECX },
+       { "edx", EDX },
+       { "esi", ESI },
+       { "edi", EDI },
+       { "ax", EAX },
+       { "bx", EBX },
+       { "cx", ECX },
+       { "dx", EDX },
+       { NULL, 0 },
+};
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+int xasmconstregs(char *s)
+{
+       int i;
+
+       if (strncmp(s, "st", 2) == 0) {
+               int off =0;
+               if (s[2] == '(' && s[4] == ')')
+                       off = s[3] - '0';
+               return ESIEDI + 1 + off;
+       }
+
+       for (i = 0; xcr[i].name; i++)
+               if (strcmp(xcr[i].name, s) == 0)
+                       return xcr[i].num;
+       return -1;
+}
+
diff --git a/lang/pcc/pcc/arch/i386/macdefs.h b/lang/pcc/pcc/arch/i386/macdefs.h
new file mode 100644 (file)
index 0000000..fb2e533
--- /dev/null
@@ -0,0 +1,371 @@
+/*     $Id: macdefs.h,v 1.94 2016/03/05 15:31:24 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT                64      /* # bits above fp where arguments start */
+#define AUTOINIT       0       /* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         8
+#define SZINT          32
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#ifdef MACHOABI
+#define SZLDOUBLE      128
+#else
+#define SZLDOUBLE      96
+#endif
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         8
+#define ALINT          32
+#define ALFLOAT                32
+#define ALDOUBLE       32
+#ifdef MACHOABI
+#define ALLDOUBLE      128
+#else
+#define ALLDOUBLE      32
+#endif
+#define ALLONG         32
+#define ALLONGLONG     32
+#define ALSHORT                16
+#define ALPOINT                32
+#undef ALSTRUCT                /* Not defined if ELF ABI */
+#define ALSTACK                32 
+#define        ALMAX           128     /* not yet supported type */
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         (-0x7fffffff-1)
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffff
+#define        MIN_LONG        MIN_INT
+#define        MAX_LONG        MAX_INT
+#define        MAX_ULONG       MAX_UNSIGNED
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+/* Default char is signed */
+#undef CHAR_UNSIGNED
+#define        BOOL_TYPE       UCHAR   /* what used to store _Bool */
+#undef UNALIGNED_ACCESS
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#if defined(ELFABI)
+#define LABFMT ".L%d"          /* format for printing labels */
+#define        STABLBL ".LL%d"         /* format for stab (debugging) labels */
+#else
+#define LABFMT "L%d"           /* format for printing labels */
+#define        STABLBL "LL%d"          /* format for stab (debugging) labels */
+#endif
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define        AUTOREG EBP
+#define        ARGREG  EBP
+#define ARGOFFSET 8
+#endif
+
+#ifdef MACHOABI
+#define STAB_LINE_ABSOLUTE     /* S_LINE fields use absolute addresses */
+#define        MYALIGN                 /* user power-of-2 alignment */
+#endif
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_LE
+
+#define FINDMOPS       /* i386 has instructions that modifies memory */
+#define        CC_DIV_0        /* division by zero is safe in the compiler */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)  gencall(a,b)
+
+#define        szty(t) (((t) == DOUBLE || (t) == FLOAT || \
+       (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1)
+
+/*
+ * The x86 has a bunch of register classes, most of them interfering
+ * with each other.  All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ * Class membership and overlaps are defined in the macros RSTATUS
+ * and ROVERLAP below.
+ *
+ * The classes used on x86 are:
+ *     A - short and int regs
+ *     B - char regs
+ *     C - long long regs
+ *     D - floating point
+ */
+#define        EAX     000     /* Scratch and return register */
+#define        EDX     001     /* Scratch and secondary return register */
+#define        ECX     002     /* Scratch (and shift count) register */
+#define        EBX     003     /* GDT pointer or callee-saved temporary register */
+#define        ESI     004     /* Callee-saved temporary register */
+#define        EDI     005     /* Callee-saved temporary register */
+#define        EBP     006     /* Frame pointer */
+#define        ESP     007     /* Stack pointer */
+
+#define        AL      010
+#define        AH      011
+#define        DL      012
+#define        DH      013
+#define        CL      014
+#define        CH      015
+#define        BL      016
+#define        BH      017
+
+#define        EAXEDX  020
+#define        EAXECX  021
+#define        EAXEBX  022
+#define        EAXESI  023
+#define        EAXEDI  024
+#define        EDXECX  025
+#define        EDXEBX  026
+#define        EDXESI  027
+#define        EDXEDI  030
+#define        ECXEBX  031
+#define        ECXESI  032
+#define        ECXEDI  033
+#define        EBXESI  034
+#define        EBXEDI  035
+#define        ESIEDI  036
+
+/* The 8 math registers in class D lacks names */
+
+#define        MAXREGS 047     /* 39 registers */
+
+#define        RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, 0, 0,                             \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,                \
+       SDREG, SDREG, SDREG, SDREG,  SDREG, SDREG, SDREG, SDREG,
+
+#define        ROVERLAP \
+       /* 8 basic registers */\
+       { AL, AH, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+       { DL, DH, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+       { CL, CH, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+       { BL, BH, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+       { EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+       { EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+       { -1 },\
+       { -1 },\
+\
+       /* 8 char registers */\
+       { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+       { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+       { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+       { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+       { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+       { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+       { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+       { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+\
+       /* 15 long-long-emulating registers */\
+       { EAX, AL, AH, EDX, DL, DH, EAXECX, EAXEBX, EAXESI,     /* eaxedx */\
+         EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\
+       { EAX, AL, AH, ECX, CL, CH, EAXEDX, EAXEBX, EAXESI,     /* eaxecx */\
+         EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+       { EAX, AL, AH, EBX, BL, BH, EAXEDX, EAXECX, EAXESI,     /* eaxebx */\
+         EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+       { EAX, AL, AH, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI,     /* eaxesi */\
+         EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+       { EAX, AL, AH, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI,     /* eaxedi */\
+         EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+       { EDX, DL, DH, ECX, CL, CH, EAXEDX, EAXECX, EDXEBX,     /* edxecx */\
+         EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\
+       { EDX, DL, DH, EBX, BL, BH, EAXEDX, EDXECX, EDXESI,     /* edxebx */\
+         EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+       { EDX, DL, DH, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI,     /* edxesi */\
+         EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+       { EDX, DL, DH, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI,     /* edxedi */\
+         EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+       { ECX, CL, CH, EBX, BL, BH, EAXECX, EDXECX, ECXESI,     /* ecxebx */\
+         ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\
+       { ECX, CL, CH, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI,     /* ecxesi */\
+         EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\
+       { ECX, CL, CH, EDI, EAXECX, EDXECX, ECXEBX, ECXESI,     /* ecxedi */\
+         EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\
+       { EBX, BL, BH, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI,     /* ebxesi */\
+         EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\
+       { EBX, BL, BH, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI,     /* ebxedi */\
+         EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\
+       { ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI,             /* esiedi */\
+         EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\
+\
+       /* The fp registers do not overlap with anything */\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },
+
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \
+                 (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \
+                 (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG)))
+
+#define        NUMCLASS        4       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define        GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD)
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define        ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 6)      /* A1 */
+#define ENCRA2(x)      ((x) << 12)     /* A2 */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+/* XXX - return char in al? */
+#define        RETREG(x)       (x == CHAR || x == UCHAR ? AL : \
+                        x == LONGLONG || x == ULONGLONG ? EAXEDX : \
+                        x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX)
+
+#if 0
+#define R2REGS 1       /* permit double indexing */
+#endif
+
+/* XXX - to die */
+#define FPREG  EBP     /* frame pointer */
+#define STKREG ESP     /* stack pointer */
+
+#define        SHSTR           (MAXSPECIAL+1)  /* short struct */
+#define        SFUNCALL        (MAXSPECIAL+2)  /* struct assign after function call */
+#define        SPCON           (MAXSPECIAL+3)  /* positive nonnamed constant */
+
+/*
+ * Specials that indicate the applicability of machine idioms.
+ */
+#define SMIXOR         (MAXSPECIAL+4)
+#define SMILWXOR       (MAXSPECIAL+5)
+#define SMIHWXOR       (MAXSPECIAL+6)
+
+/*
+ * i386-specific symbol table flags.
+ */
+#define        SSECTION        SLOCAL1
+#define SSTDCALL       SLOCAL2 
+#define SDLLINDIRECT   SLOCAL3
+
+/*
+ * i386-specific interpass stuff.
+ */
+
+#define TARGET_IPP_MEMBERS                     \
+       int ipp_argstacksize;
+
+#define        target_members_print_prolog(ipp) printf("%d", ipp->ipp_argstacksize)
+#define        target_members_print_epilog(ipp) printf("%d", ipp->ipp_argstacksize)
+#define target_members_read_prolog(ipp) ipp->ipp_argstacksize = rdint(&p)
+#define target_members_read_epilog(ipp) ipp->ipp_argstacksize = rdint(&p)
+
+#define        HAVE_WEAKREF
+#define        TARGET_FLT_EVAL_METHOD  2       /* all as long double */
+
+/*
+ * Extended assembler macros.
+ */
+void targarg(char *w, void *arg);
+#define        XASM_TARGARG(w, ary)    \
+       (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \
+       w++, targarg(w, ary), 1 : 0)
+int numconv(void *ip, void *p, void *q);
+#define        XASM_NUMCONV(ip, p, q)  numconv(ip, p, q)
+int xasmconstregs(char *);
+#define        XASMCONSTREGS(x) xasmconstregs(x)
+#define        MYSETXARG if (XASMVAL(cw) == 'q') {     \
+       c = 'r'; addalledges(&ablock[ESI]); addalledges(&ablock[EDI]); }
+
+#if defined(MACHOABI)
+struct stub {
+       struct { struct stub *q_forw, *q_back; } link;
+       char *name;
+};    
+extern struct stub stublist;
+extern struct stub nlplist;
+void addstub(struct stub *list, char *name);
+#endif
+
+/* -m flags */
+extern int msettings;
+#define        MI386   0x001
+#define        MI486   0x002
+#define        MI586   0x004
+#define        MI686   0x008
+#define        MCPUMSK 0x00f
+
+/* target specific attributes */
+#define        ATTR_MI_TARGET  ATTR_I386_FCMPLRET, ATTR_I386_FPPOP
diff --git a/lang/pcc/pcc/arch/i386/order.c b/lang/pcc/pcc/arch/i386/order.c
new file mode 100644 (file)
index 0000000..6f2c834
--- /dev/null
@@ -0,0 +1,313 @@
+/*     $Id: order.c,v 1.63 2015/11/17 19:19:40 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *r;
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+       r = p->n_right;
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( r->n_op == ICON ){
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+               if (r->n_op == LS && r->n_right->n_op == ICON &&
+                   getlval(r->n_right) == 2 && p->n_op == PLUS) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       if (isreg(r->n_left) == 0)
+                               (void)geninsn(r->n_left, INAREG);
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+       NODE *p, *r;
+
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+
+       p = q->n_left;
+       if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
+           r->n_right->n_op == ICON && getlval(r->n_right) == 2 &&
+           p->n_left->n_op == REG && r->n_left->n_op == REG) {
+               q->n_op = OREG;
+               setlval(q, 0);
+               q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0);
+               tfree(p);
+       }
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on x86 */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case OPLOG:
+               {
+                       static struct rspecial s[] = { { NEVER, EAX }, { 0 } };
+                       return s;
+               }
+
+       case STASG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, EDI }, { NEVER, ESI },
+                               { NRIGHT, ESI }, { NOLEFT, ESI },
+                               { NOLEFT, ECX }, { NORIGHT, ECX },
+                               { NEVER, ECX }, { 0 } };
+                       return s;
+               }
+
+       case STARG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, EDI }, { NEVER, ECX },
+                               { NLEFT, ESI }, { 0 } };
+                       return s;
+               }
+
+       case SCONV:
+               if ((q->ltype & (TINT|TUNSIGNED|TSHORT|TUSHORT)) && 
+                   q->rtype == (TCHAR|TUCHAR)) {
+                       static struct rspecial s[] = { 
+                               { NOLEFT, ESI }, { NOLEFT, EDI }, { 0 } };
+                       return s;
+               } else if ((q->ltype & TINT) &&
+                   q->rtype == (TLONGLONG|TULONGLONG)) {
+                       static struct rspecial s[] = {
+                               { NLEFT, EAX }, { NRES, EAXEDX },
+                               { NEVER, EAX }, { NEVER, EDX }, { 0 } };
+                       return s;
+               } else if (q->ltype == TSHORT &&
+                   q->rtype == (TLONGLONG|TULONGLONG)) {
+                       static struct rspecial s[] = {
+                               { NRES, EAXEDX },
+                               { NEVER, EAX }, { NEVER, EDX }, { 0 } };
+                       return s;
+               } else if (q->ltype == TCHAR &&
+                   q->rtype == (TLONGLONG|TULONGLONG)) {
+                       static struct rspecial s[] = {
+                               { NRES, EAXEDX },
+                               { NEVER, EAX }, { NEVER, EDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case DIV:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AL }, { NEVER, AH },
+                               { NLEFT, AL }, { NRES, AL },
+                               { NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+                               return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, EAX }, { NEVER, EDX },
+                               { NLEFT, EAX }, { NRES, EAX },
+                               { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } };
+                       return s;
+               } else if (q->lshape & SCREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, EAX }, { NEVER, EDX },
+                               { NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case MOD:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AL }, { NEVER, AH },
+                               { NLEFT, AL }, { NRES, AH },
+                               { NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, EAX }, { NEVER, EDX },
+                               { NLEFT, EAX }, { NRES, EDX },
+                               { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } };
+                       return s;
+               } else if (q->lshape & SCREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, EAX }, { NEVER, EDX },
+                               { NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case MUL:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AL }, { NEVER, AH },
+                               { NLEFT, AL }, { NRES, AL }, { 0 } };
+                       return s;
+               } else if (q->lshape & SCREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, EAXEDX }, { NRIGHT, ECXESI },
+                               { NEVER, ESI }, { NRES, EAXEDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case LS:
+       case RS:
+               if (q->visit & (INAREG|INBREG)) {
+                       static struct rspecial s[] = {
+                               { NRIGHT, CL }, { NOLEFT, ECX }, { 0 } };
+                       return s;
+               } else if (q->visit & INCREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, EAXEDX }, { NRIGHT, CL },
+                               { NRES, EAXEDX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       default:
+               break;
+       }
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on x86 */
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[] = { EAX, EBX, -1 };
+       int off = 1;
+
+#ifdef TLS
+       if (p->n_left->n_op == ICON &&
+           strcmp(p->n_left->n_name, "___tls_get_addr@PLT") == 0)
+               off--;
+#endif
+
+       return kflag ? &r[off] : &r[2];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/i386/table.c b/lang/pcc/pcc/arch/i386/table.c
new file mode 100644 (file)
index 0000000..7f2c287
--- /dev/null
@@ -0,0 +1,1622 @@
+/*     $Id: table.c,v 1.144 2015/10/07 11:30:21 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+# define TLL TLONGLONG|TULONGLONG
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED|TULONG
+# define TSWORD TINT|TLONG
+# define TWORD TUWORD|TSWORD
+#define         SHINT  SAREG   /* short and int */
+#define         ININT  INAREG
+#define         SHCH   SBREG   /* shape for char */
+#define         INCH   INBREG
+#define         SHLL   SCREG   /* shape for long long */
+#define         INLL   INCREG
+#define         SHFL   SDREG   /* shape for float/double */
+#define         INFL   INDREG  /* shape for float/double */
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV,       INCH,
+       SHCH,   TCHAR|TUCHAR,
+       SHCH,   TCHAR|TUCHAR,
+               0,      RLEFT,
+               "", },
+
+/* convert pointers to int. */
+{ SCONV,       ININT,
+       SHINT,  TPOINT|TWORD,
+       SANY,   TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV,       INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               0,      RLEFT,
+               "", },
+
+/* convert between float/double/long double. */
+{ SCONV,       INFL,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "ZI", },
+
+/* convert pointers to pointers. */
+{ SCONV,       ININT,
+       SHINT,  TPOINT,
+       SANY,   TPOINT,
+               0,      RLEFT,
+               "", },
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV,       ININT,
+       SBREG|SOREG|SNAME,      TCHAR,
+       SAREG,  TSHORT|TUSHORT,
+               NASL|NAREG,     RESC1,
+               "       movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV,       ININT,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SAREG,  TSHORT|TUSHORT,
+               NASL|NAREG,     RESC1,
+               "       movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV,       ININT,
+       SHCH|SOREG|SNAME,       TCHAR,
+       SAREG,  TWORD|TPOINT,
+               NASL|NAREG,     RESC1,
+               "       movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV,       ININT,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV,       INLL,
+       SHCH|SOREG|SNAME,       TCHAR,
+       SANY,   TLL,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "       movsbl AL,%eax\n        cltd\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,       INLL,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SANY,                   TLL,
+               NCREG|NCSL,     RESC1,
+               "       movzbl AL,A1\n  xorl U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+{ SCONV,       INFL,
+       SHCH|SOREG|SNAME,       TCHAR,
+       SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG,       RESC2,
+               "       movsbl AL,A1\n  pushl A1\n"
+               "       fildl (%esp)\n  addl $4,%esp\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+{ SCONV,       INFL,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG,       RESC2,
+               "       movzbl AL,A1\n  pushl A1\n"
+               "       fildl (%esp)\n  addl $4,%esp\n", },
+
+/* short to something */
+
+/* convert (u)short to (u)short. */
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               0,      RLEFT,
+               "", },
+
+/* convert short (in memory) to char */
+{ SCONV,       INCH,
+       SNAME|SOREG,    TSHORT|TUSHORT,
+       SHCH,           TCHAR|TUCHAR,
+               NBREG|NBSL,     RESC1,
+               "       movb AL,A1\n", },
+
+/* convert short (in reg) to char. */
+{ SCONV,       INCH,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZM", },
+
+/* convert short to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV,       INLL,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SHLL,                   TLL,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "       movswl AL,%eax\n        cltd\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,       INLL,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SHLL,                   TLL,
+               NCREG|NCSL,     RESC1,
+               "       movzwl AL,A1\n  xorl U1,U1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV,       INFL,
+       SOREG|SNAME,    TSHORT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       fild AL\n", },
+
+/* convert short (in register) to float/double */
+{ SCONV,       INFL,
+       SAREG,  TSHORT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,    RESC1,
+               "       pushw AL\n      fild (%esp)\n   addl $2,%esp\n", },
+
+/* convert unsigned short to double XXX - use NTEMP */
+{ SCONV,       INFL,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG|NTEMP, RESC2,
+               "       movzwl AL,A1\n  pushl A1\n"
+               "       fildl (%esp)\n  addl $4,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV,       INCH,
+       SAREG,  TWORD|TPOINT,
+       SANY,   TCHAR|TUCHAR,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZM", },
+
+/* convert int to short. Nothing to do */
+{ SCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SANY,   TSHORT|TUSHORT,
+               0,      RLEFT,
+               "", },
+
+/* convert signed int to (u)long long */
+{ SCONV,       INLL,
+       SHINT,  TSWORD,
+       SHLL,   TLL,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "       cltd\n", },
+
+/* convert unsigned int to (u)long long */
+{ SCONV,       INLL,
+       SHINT|SOREG|SNAME,      TUWORD|TPOINT,
+       SHLL,   TLL,
+               NCSL|NCREG,     RESC1,
+               "       movl AL,A1\n    xorl U1,U1\n", },
+
+/* convert signed int (in memory) to double */
+{ SCONV,       INFL,
+       SOREG|SNAME,    TSWORD,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       fildl AL\n", },
+
+/* convert signed int (in register) to double */
+{ SCONV,       INFL,
+       SAREG,  TSWORD,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       pushl AL\n      fildl (%esp)\n  addl $4,%esp\n", },
+
+/* convert unsigned int (reg&mem) to double */
+{ SCONV,       INFL,
+       SOREG|SNAME|SAREG,      TUWORD,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       pushl $0\n"
+               "       pushl AL\n"
+               "       fildq (%esp)\n"
+               "       addl $8,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV,       INCH,
+       SOREG|SNAME,    TLL,
+       SANY,   TCHAR|TUCHAR,
+               NBREG|NBSL,     RESC1,
+               "       movb AL,A1\n", },
+
+/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV,       INCH,
+       SHLL,   TLL,
+       SANY,   TCHAR|TUCHAR,
+               NBREG|NBSL|NTEMP,       RESC1,
+               "ZS", },
+
+/* convert (u)long long to (u)short (mem->reg) */
+{ SCONV,       INAREG,
+       SOREG|SNAME,    TLL,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       movw AL,A1\n", },
+
+/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */
+{ SCONV,       INAREG,
+       SHLL|SOREG|SNAME,       TLL,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NASL|NTEMP,       RESC1,
+               "ZS", },
+
+/* convert long long to int (mem->reg) */
+{ SCONV,       INAREG,
+       SOREG|SNAME,    TLL,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+/* convert long long to int (reg->reg, hopefully nothing) */
+{ SCONV,       INAREG,
+       SHLL|SOREG|SNAME,       TLL,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL|NTEMP,       RESC1,
+               "ZS", },
+
+/* convert long long (in memory) to floating */
+{ SCONV,       INFL,
+       SOREG|SNAME,    TLONGLONG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV,       INFL,
+       SHLL,   TLONGLONG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,    RESC1,
+               "       pushl UL\n      pushl AL\n"
+               "       fildq (%esp)\n  addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV,       INFL,
+       SCREG,  TULONGLONG,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV,       INCH,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHCH,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "       subl $4,%esp\n  fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV,       INCH,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHCH,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NCREG,  RESC1,
+               "       subl $4,%esp\n  fistpl (%esp)\n popl A1\n", },
+#endif
+
+/* convert float/double to int. XXX should use NTEMP here */
+{ SCONV,       INAREG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SAREG,  TSWORD,
+               NAREG,  RESC1,
+               "       subl $12,%esp\n"
+               "       fnstcw (%esp)\n"
+               "       fnstcw 4(%esp)\n"
+               "       movb $12,1(%esp)\n"
+               "       fldcw (%esp)\n"
+               "       fistpl 8(%esp)\n"
+               "       movl 8(%esp),A1\n"
+               "       fldcw 4(%esp)\n"
+               "       addl $12,%esp\n", },
+
+/* convert float/double to unsigned int. XXX should use NTEMP here */
+{ SCONV,       INAREG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SAREG,  TUWORD,
+               NAREG,  RESC1,
+               "       subl $16,%esp\n"
+               "       fnstcw (%esp)\n"
+               "       fnstcw 4(%esp)\n"
+               "       movb $12,1(%esp)\n"
+               "       fldcw (%esp)\n"
+               "       fistpq 8(%esp)\n"
+               "       movl 8(%esp),A1\n"
+               "       fldcw 4(%esp)\n"
+               "       addl $16,%esp\n", },
+
+/* convert float/double (in register) to long long */
+{ SCONV,       INLL,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHLL,   TLONGLONG,
+               NCREG,  RESC1,
+               "       subl $16,%esp\n"
+               "       fnstcw (%esp)\n"
+               "       fnstcw 4(%esp)\n"
+               "       movb $12,1(%esp)\n"
+               "       fldcw (%esp)\n"
+               "       fistpq 8(%esp)\n"
+               "       movl 8(%esp),A1\n"
+               "       movl 12(%esp),U1\n"
+               "       fldcw 4(%esp)\n"
+               "       addl $16,%esp\n", },
+
+/* convert float/double (in register) to unsigned long long */
+{ SCONV,       INLL,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHLL,   TULONGLONG,
+               NCREG,  RESC1,
+               "       subl $16,%esp\n"
+               "       fnstcw (%esp)\n"
+               "       fnstcw 4(%esp)\n"
+               "       movb $7,1(%esp)\n"      /* 64-bit, round down  */
+               "       fldcw (%esp)\n"
+               "       movl $0x5f000000, 8(%esp)\n"    /* (float)(1<<63) */
+               "       fsubs 8(%esp)\n"        /* keep in range of fistpq */
+               "       fistpq 8(%esp)\n"
+               "       xorb $0x80,15(%esp)\n"  /* addq $1>>63 to 8(%esp) */
+               "       movl 8(%esp),A1\n"
+               "       movl 12(%esp),U1\n"
+               "       fldcw 4(%esp)\n"
+               "       addl $16,%esp\n", },
+
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call CL\nZC", },
+
+{ CALL,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call CL\nZC", },
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SAREG,  TWORD|TPOINT,
+               0,      0,
+               "       call CL\nZC", },
+
+{ CALL,        INAREG,
+       SCON,   TANY,
+       SAREG,  TSHORT|TUSHORT|TWORD|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SAREG,  TSHORT|TUSHORT|TWORD|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,        INBREG,
+       SCON,   TANY,
+       SBREG,  TCHAR|TUCHAR,
+               NBREG,  RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TCHAR|TUCHAR,
+               NBREG,  RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,                INCREG,
+       SCON,   TANY,
+       SCREG,  TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INCREG,
+       SCON,   TANY,
+       SCREG,  TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,        INDREG,
+       SCON,   TANY,
+       SDREG,  TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INDREG,
+       SCON,   TANY,
+       SDREG,  TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INCREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INCREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INDREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INDREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ STCALL,      FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     0,
+               "       call CL\nZC", },
+
+{ STCALL,      INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ STCALL,      INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Special treatment for long long */
+{ PLUS,                INLL|FOREFF,
+       SHLL,           TLL,
+       SHLL|SNAME|SOREG,       TLL,
+               0,      RLEFT,
+               "       addl AR,AL\n    adcl UR,UL\n", },
+
+{ PLUS,                INLL|FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SHLL|SCON,              TLL,
+               0,      RLEFT,
+               "       addl AR,AL\n    adcl UR,UL\n", },
+
+/* Special treatment for long long  XXX - fix commutative check */
+{ PLUS,                INLL|FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SHLL,                   TLL,
+               0,      RRIGHT,
+               "       addl AL,AR\n    adcl UL,UR\n", },
+
+{ PLUS,                INFL,
+       SHFL,           TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       faddl AR\n", },
+
+{ PLUS,                INFL|FOREFF,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       faddp\n", },
+
+{ PLUS,                INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incl AL\n", },
+
+{ PLUS,                INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incw AL\n", },
+
+{ PLUS,                INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incb AL\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               NAREG|NASL|NASR,        RESC1,
+               "       leal (AL,AR),A1\n", },
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SONE,                   TANY,
+               0,      RLEFT,
+               "       decl AL\n", },
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SONE,                   TANY,
+               0,      RLEFT,
+               "       decw AL\n", },
+
+{ MINUS,       INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       decb AL\n", },
+
+/* address as register offset, negative */
+{ MINUS,       INLL|FOREFF,
+       SHLL,   TLL,
+       SHLL|SNAME|SOREG,       TLL,
+               0,      RLEFT,
+               "       subl AR,AL\n    sbbl UR,UL\n", },
+
+{ MINUS,       INLL|FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SHLL|SCON,      TLL,
+               0,      RLEFT,
+               "       subl AR,AL\n    sbbl UR,UL\n", },
+
+{ MINUS,       INFL,
+       SHFL,   TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       fsubl AR\n", },
+
+{ MINUS,       INFL|FOREFF,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+/* m/r |= r */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SAREG,                  TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "       Ol AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "       Ol AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+       SHINT,          TSHORT|TUSHORT,
+               0,      RLEFT|RESCC,
+               "       Ow AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SHINT,          TSHORT|TUSHORT,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+               0,      RLEFT|RESCC,
+               "       Ow AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,      INCH|FOREFF|FORCC,
+       SHCH,           TCHAR|TUCHAR,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "       Ob AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INCH|FOREFF|FORCC,
+       SHCH,           TCHAR|TUCHAR,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "       Ob AR,AL\n", },
+
+/* m/r |= const */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SCON,   TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "       Ol AR,AL\n", },
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,   TANY,
+               0,      RLEFT|RESCC,
+               "       Ow AR,AL\n", },
+
+{ OPSIMP,      INCH|FOREFF|FORCC,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SCON,   TANY,
+               0,      RLEFT|RESCC,
+               "       Ob AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INLL|FOREFF,
+       SHLL,   TLL,
+       SHLL|SNAME|SOREG,       TLL,
+               0,      RLEFT,
+               "       Ol AR,AL\n      Ol UR,UL\n", },
+
+/* m/r |= r/const */
+{ OPSIMP,      INLL|FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SHLL|SCON,      TLL,
+               0,      RLEFT,
+               "       Ol AR,AL\n      Ol UR,UL\n", },
+
+/* Try use-reg instructions first */
+{ PLUS,                INAREG,
+       SAREG,  TWORD|TPOINT,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       leal CR(AL),A1\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       leal -CR(AL),A1\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)longlong left shift is emulated */
+{ LS,  INCREG,
+       SCREG,  TLL,
+       SHCH,   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "ZO", },
+
+/* r/m <<= r */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SHCH,           TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sall AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       sall AR,AL\n", },
+
+/* r/m <<= r */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shlw AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       shlw AR,AL\n", },
+
+{ LS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       salb AR,AL\n", },
+
+{ LS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SCON,                   TANY,
+               0,      RLEFT,
+               "       salb AR,AL\n", },
+
+/* (u)longlong right shift is emulated */
+{ RS,  INCREG,
+       SCREG,  TLL,
+       SHCH,   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "ZO", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSWORD,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSWORD,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUWORD,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUWORD,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrw AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarb AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarb AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TUCHAR,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrb AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TUCHAR,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN,      FORCC|FOREFF|INLL,
+       SHLL,           TLL,
+       SMIXOR,         TANY,
+               0,      RDEST,
+               "       xorl AL,AL\n    xorl UL,UL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INLL,
+       SHLL,           TLL,
+       SMILWXOR,       TANY,
+               0,      RDEST,
+               "       xorl AL,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INLL,
+       SHLL,           TLL,
+       SMIHWXOR,       TANY,
+               0,      RDEST,
+               "       movl AR,AL\n    xorl UL,UL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SHLL,           TLL,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movl AR,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SCON,           TANY,
+               0,      0,
+               "       movl AR,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SMIXOR,         TANY,
+               0,      RDEST,
+               "       xorl AL,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SCON,           TANY,
+               0,      0,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SMIXOR,         TANY,
+               0,      RDEST,
+               "       xorw AL,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,           TANY,
+               0,      0,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      0,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCH,
+       SHCH,           TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SNAME|SOREG,    TLL,
+       SHLL,           TLL,
+               0,      RDEST,
+               "       movl AR,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               0,      RDEST,
+               "ZH", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SAREG,          TWORD|TPOINT,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RDEST,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCH,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SHCH,           TCHAR|TUCHAR|TWORD,
+               0,      RDEST,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      INDREG|FOREFF,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TLDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fstpt AL\n      fldt AL\n", }, /* XXX */
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TLDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       fstpt AL\n", },
+
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fstl AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       fstpl AL\n", },
+
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TFLOAT,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fsts AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TFLOAT,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       fstps AL\n", },
+/* end very important order */
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TLDOUBLE,
+       SHFL|SOREG|SNAME,       TLDOUBLE,
+               0,      RDEST,
+               "       fldt AR\n", },
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TDOUBLE,
+       SHFL|SOREG|SNAME,       TDOUBLE,
+               0,      RDEST,
+               "       fldl AR\n", },
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TFLOAT,
+       SHFL|SOREG|SNAME,       TFLOAT,
+               0,      RDEST,
+               "       flds AR\n", },
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME|SAREG,      TPTRTO|TSTRUCT,
+       SFUNCALL,       TPTRTO|TSTRUCT,
+               0,      RRIGHT,
+               "", },
+#endif
+
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SAREG,          TPTRTO|TANY,
+               NSPECIAL|NAREG, RDEST,
+               "F      movl %esi,A1\nZQF       movl A1,%esi\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* long long div is emulated */
+{ DIV, INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SCREG|SNAME|SOREG|SCON, TLL,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ DIV, INAREG,
+       SAREG,                  TSWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               NSPECIAL,       RDEST,
+               "       cltd\n  idivl AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TUWORD|TPOINT,
+               NSPECIAL,       RDEST,
+               "       xorl %edx,%edx\n        divl AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUSHORT,
+       SAREG|SNAME|SOREG,      TUSHORT,
+               NSPECIAL,       RDEST,
+               "       xorl %edx,%edx\n        divw AR\n", },
+
+{ DIV, INCH,
+       SHCH,                   TUCHAR,
+       SHCH|SNAME|SOREG,       TUCHAR,
+               NSPECIAL,       RDEST,
+               "       xorb %ah,%ah\n  divb AR\n", },
+
+{ DIV, INFL,
+       SHFL,           TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       fdivl AR\n", },
+
+{ DIV, INFL,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fdivZAp\n", },
+
+/* (u)longlong mod is emulated */
+{ MOD, INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SCREG|SNAME|SOREG|SCON, TLL,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ MOD, INAREG,
+       SAREG,                  TSWORD,
+       SAREG|SNAME|SOREG,      TSWORD,
+               NAREG|NSPECIAL, RESC1,
+               "       cltd\n  idivl AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TUWORD|TPOINT,
+               NAREG|NSPECIAL, RESC1,
+               "       xorl %edx,%edx\n        divl AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TUSHORT,
+       SAREG|SNAME|SOREG,      TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       xorl %edx,%edx\n        divw AR\n", },
+
+{ MOD, INCH,
+       SHCH,                   TUCHAR,
+       SHCH|SNAME|SOREG,       TUCHAR,
+               NBREG|NSPECIAL, RESC1,
+               "       xorb %ah,%ah\n  divb AR\n", },
+
+/* (u)longlong mul is emulated */
+{ MUL, INCREG,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               NSPECIAL,       RDEST,
+               "ZO", },
+
+{ MUL, INAREG,
+       SAREG,                          TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON,         TWORD|TPOINT,
+               0,      RLEFT,
+               "       imull AR,AL\n", },
+
+{ MUL, INAREG,
+       SAREG,                  TSHORT|TUSHORT,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       imulw AR,AL\n", },
+
+{ MUL, INCH,
+       SHCH,                   TCHAR|TUCHAR,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+               NSPECIAL,       RDEST,
+               "       imulb AR\n", },
+
+{ MUL, INFL,
+       SHFL,           TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       fmull AR\n", },
+
+{ MUL, INFL,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,        INLL,
+       SANY,   TANY,
+       SOREG,  TLL,
+               NCREG,  RESC1,
+               "       movl UL,U1\n    movl AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ UMUL,        INCH,
+       SANY,   TANY,
+       SOREG,  TCHAR|TUCHAR,
+               NBREG|NBSL,     RESC1,
+               "       movb AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SOREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       movw AL,A1\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TLDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "       fldt AL\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "       fldl AL\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TFLOAT,
+               NDREG|NDSL,     RESC1,
+               "       flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG,       FORCC,
+       SHLL|SOREG|SNAME,       TLL,
+       SHLL,                   TLL,
+               0,      0,
+               "ZD", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TWORD|TPOINT,
+       SCON|SAREG,     TWORD|TPOINT,
+               0,      RESCC,
+               "       cmpl AR,AL\n", },
+
+#if 0
+{ OPLOG,       FORCC,
+       SCON|SAREG,     TWORD|TPOINT,
+       SAREG|SOREG|SNAME,      TWORD|TPOINT,
+               0,      RESCC,
+               "       cmpl AR,AL\n", },
+#endif
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+       SCON|SAREG,     TANY,
+               0,      RESCC,
+               "       cmpw AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SBREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       SCON|SBREG,     TANY,
+               0,      RESCC,
+               "       cmpb AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NSPECIAL,       RNOP,
+               "ZG", },
+
+{ OPLOG,       FORCC,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND, INAREG|FOREFF,
+       SAREG|SOREG|SNAME,      TWORD,
+       SCON|SAREG,             TWORD,
+               0,      RLEFT,
+               "       andl AR,AL\n", },
+
+{ AND, INCREG|FOREFF,
+       SCREG,                  TLL,
+       SCREG|SOREG|SNAME,      TLL,
+               0,      RLEFT,
+               "       andl AR,AL\n    andl UR,UL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG,                  TWORD,
+       SAREG|SOREG|SNAME,      TWORD,
+               0,      RLEFT,
+               "       andl AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+       SCON|SAREG,             TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       andw AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+       SAREG,                  TSHORT|TUSHORT,
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       andw AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+       SBREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       SCON|SBREG,             TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       andb AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+       SBREG,                  TCHAR|TUCHAR,
+       SBREG|SOREG|SNAME,      TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp LL\n", },
+
+#if defined(GCC_COMPAT) || defined(LANG_F77)
+{ GOTO,        FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,     FORCC|INLL,
+       SCREG,  TLL,
+       SMIXOR, TANY,
+               NCREG,  RESC1,
+               "       xorl U1,U1\n    xorl A1,A1\n", },
+
+{ OPLTYPE,     FORCC|INLL,
+       SCREG,  TLL,
+       SMILWXOR,       TANY,
+               NCREG,  RESC1,
+               "       movl UL,U1\n    xorl A1,A1\n", },
+
+{ OPLTYPE,     FORCC|INLL,
+       SCREG,  TLL,
+       SMIHWXOR,       TANY,
+               NCREG,  RESC1,
+               "       xorl U1,U1\n    movl AL,A1\n", },
+
+{ OPLTYPE,     INLL,
+       SANY,   TANY,
+       SCREG,  TLL,
+               NCREG,  RESC1,
+               "ZK", },
+
+{ OPLTYPE,     INLL,
+       SANY,   TANY,
+       SCON|SOREG|SNAME,       TLL,
+               NCREG,  RESC1,
+               "       movl UL,U1\n    movl AL,A1\n", },
+
+{ OPLTYPE,     FORCC|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SMIXOR, TANY,
+               NAREG|NASL,     RESC1,
+               "       xorl A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "       movb AL,A1\n", },
+
+{ OPLTYPE,     FORCC|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SMIXOR, TANY,
+               NAREG,  RESC1,
+               "       xorw A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT,
+               NAREG,  RESC1,
+               "       movw AL,A1\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TLDOUBLE,
+       SOREG|SNAME,    TLDOUBLE,
+               NDREG,  RESC1,
+               "       fldt AL\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TDOUBLE,
+       SOREG|SNAME,    TDOUBLE,
+               NDREG,  RESC1,
+               "       fldl AL\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TFLOAT,
+       SOREG|SNAME,    TFLOAT,
+               NDREG,  RESC1,
+               "       flds AL\n", },
+
+/* Only used in ?: constructs. The stack already contains correct value */
+{ OPLTYPE,     INDREG,
+       SANY,   TFLOAT|TDOUBLE|TLDOUBLE,
+       SDREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      INCREG|FOREFF,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RLEFT,
+               "       negl AL\n       adcl $0,UL\n    negl UL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "       negl AL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       negw AL\n", },
+
+{ UMINUS,      INBREG|FOREFF,
+       SBREG,  TCHAR|TUCHAR,
+       SBREG,  TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       negb AL\n", },
+
+{ UMINUS,      INFL|FOREFF,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fchs\n", },
+
+{ COMPL,       INCREG,
+       SCREG,  TLL,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notl AL\n       notl UL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notl AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notw AL\n", },
+
+{ COMPL,       INBREG,
+       SBREG,  TCHAR|TUCHAR,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notb AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,      FOREFF,
+       SCON|SCREG|SNAME|SOREG, TLL,
+       SANY,   TLL,
+               0,      RNULL,
+               "       pushl UL\n      pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+       SANY,   TWORD|TPOINT,
+               0,      RNULL,
+               "       pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SANY,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               0,      RNULL,
+               "       pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SANY,   TSHORT,
+               NAREG,  0,
+               "       movswl AL,ZN\n  pushl ZN\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SANY,   TUSHORT,
+               NAREG,  0,
+               "       movzwl AL,ZN\n  pushl ZN\n", },
+
+{ FUNARG,      FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR,
+       SANY,                   TCHAR,
+               NAREG,  0,
+               "       movsbl AL,A1\n  pushl A1\n", },
+
+{ FUNARG,      FOREFF,
+       SHCH|SNAME|SOREG,       TUCHAR,
+       SANY,   TUCHAR,
+               NAREG,  0,
+               "       movzbl AL,A1\n  pushl A1\n", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SOREG,    TDOUBLE,
+       SANY,   TDOUBLE,
+               0,      0,
+               "       pushl UL\n      pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TDOUBLE,
+       SANY,           TDOUBLE,
+               0,      0,
+               "       subl $8,%esp\n  fstpl (%esp)\n", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SOREG,    TFLOAT,
+       SANY,           TFLOAT,
+               0,      0,
+               "       pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TFLOAT,
+       SANY,           TFLOAT,
+               0,      0,
+               "       subl $4,%esp\n  fstps (%esp)\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TLDOUBLE,
+       SANY,           TLDOUBLE,
+               0,      0,
+               "       subl $12,%esp\n fstpt (%esp)\n", },
+
+{ STARG,       FOREFF,
+       SAREG,  TPTRTO|TSTRUCT,
+       SANY,   TSTRUCT,
+               NSPECIAL,       0,
+               "ZF", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/i86/TODO b/lang/pcc/pcc/arch/i86/TODO
new file mode 100644 (file)
index 0000000..8edba2b
--- /dev/null
@@ -0,0 +1,93 @@
+
+
+8086/80186
+----------
+Add CPU options
+Make push immediate, imul, shift immediate and enter/leave 186 specific
+Optimise >> 8 and friends as register moves (note that the core compiler
+code also goes off and turns * 256 into << 8)
+
+Unstarted
+---------
+Float
+
+Struct/Union testing
+
+Maths optimisation. Div/mul on 8086 are *slow* so generate stack/double and
+other optimised forms
+
+Long helper methods (out of line 32bit mul etc) 
+
+Make long long a class E with 64bit types and four virtual registers
+rewritten as memory.
+
+Other call formats
+
+Optimisation
+------------
+Avoid sp,bp set up if we can on entry/exit
+
+Delayed sp adjustments
+
+Don't adjust sp then reload it from bp!
+
+Register constant tracking (especially important as we often know where a
+zero word or byte is and we can use it for push immediate #0)
+
+Spotting two halves of a 32bit value being the same and merging
+
+Allow moves between half registers and their full shadow (al->ax) for char
+to short etc. How to balance compilers tendancy to allocate AL, AH, etc
+which is good for register freedom and bad for chars ?
+
+Better uchar handling - if we allocated xL before xH somehow in all cases
+then we would be able to do xL -> xX efficiently.
+
+We get very poor code because the compiler doesn't understand that type
+converting al does not destroy al, only ah and the al/ax relationship. In
+particular with char args it loves to write crap like
+
+
+       mov bl, 1
+       ...
+       mov al, bl
+       cbw
+       push ax
+       mov al, bl
+       cbw
+       inc ax
+       push ax
+
+not
+       mov al, 1
+       cbw
+       push ax
+       inc al
+       cbw
+       push ax
+
+
+
+
+
+
+
+Questions
+---------
+An assembler programmer would not 
+
+       mov al, #14
+       cbw
+
+but would
+
+       mov ax, #0014
+
+not obvious how we do that optimisation with pcc in all cases but its important
+
+Can we optimise compare with zero cases ?
+
+How do we make use of rep and loopXX, these are rather useful on 8086 but
+need indexes to tend to use the right register
+
+Should there be a CPU type/feature match in table.c ?
\ No newline at end of file
diff --git a/lang/pcc/pcc/arch/i86/code.c b/lang/pcc/pcc/arch/i86/code.c
new file mode 100644 (file)
index 0000000..02a221e
--- /dev/null
@@ -0,0 +1,455 @@
+/*     $Id: code.c,v 1.2 2014/11/11 07:43:07 ragge Exp $       */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".TEXT"; break;
+       case DATA:
+       case LDATA: name = ".DATA"; break;
+       case UDATA: break;
+       case STRNG:
+       case RDATA: name = ".DATA"; break;
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+       if (sp->sclass == EXTDEF) {
+               printf("        .globl %s\n", name);
+       }
+       if (sp->slevel == 0)
+               printf("%s:\n", name);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+int structrettemp;
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       extern int gotnr;
+       NODE *p, *q;
+
+       gotnr = 0;      /* new number for next fun */
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+       /* Create struct assignment */
+       q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap);
+       q = buildtree(UMUL, q, NIL);
+       p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       p = buildtree(UMUL, p, NIL);
+       p = buildtree(ASSIGN, q, p);
+       ecomp(p);
+
+       /* put hidden arg in ax on return */
+       q = tempnode(structrettemp, INT, 0, 0);
+       p = block(REG, NIL, NIL, INT, 0, 0);
+       regno(p) = AX;
+       ecomp(buildtree(ASSIGN, p, q));
+}
+
+static TWORD longregs[] = { AXDX, DXCX };
+static TWORD regpregs[] = { AX, DX, CX };
+static TWORD charregs[] = { AL, DL, CL };
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ *
+ * Classifying args on i386; not simple:
+ * - Args may be on stack or in registers (regparm)
+ * - There may be a hidden first arg, unless OpenBSD struct return.
+ * - Regparm syntax is not well documented.
+ * - There may be stdcall functions, where the called function pops stack
+ * - ...probably more
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       extern int argstacksize;
+#ifdef GCC_COMPAT
+       struct attr *ap;
+#endif
+       struct symtab *sp2;
+       extern int gotnr;
+       NODE *n, *p;
+       int i, regparmarg;
+       int argbase, nrarg, sz;
+
+       argbase = ARGINIT;
+       nrarg = regparmarg = 0;
+
+#ifdef GCC_COMPAT
+        if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
+                cftnsp->sflags |= SSTDCALL;
+        if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM)))
+                regparmarg = ap->iarg(0);
+#endif
+
+       /* Function returns struct, create return arg node */
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               {
+                       if (regparmarg) {
+                               n = block(REG, 0, 0, INT, 0, 0);
+                               regno(n) = regpregs[nrarg++];
+                       } else {
+                               n = block(OREG, 0, 0, INT, 0, 0);
+                               n->n_lval = argbase/SZCHAR;
+                               argbase += SZINT;
+                               regno(n) = FPREG;
+                       }
+                       p = tempnode(0, INT, 0, 0);
+                       structrettemp = regno(p);
+                       p = buildtree(ASSIGN, p, n);
+                       ecomp(p);
+               }
+       }
+
+       /*
+        * Find where all params are so that they end up at the right place.
+        * At the same time recalculate their arg offset on stack.
+        * We also get the "pop size" for stdcall.
+        */
+       for (i = 0; i < cnt; i++) {
+               sp2 = sp[i];
+               sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
+               
+               SETOFF(sz, SZINT);
+
+               if (cisreg(sp2->stype) == 0 ||
+                   ((regparmarg - nrarg) * SZINT < sz)) {      /* not in reg */
+                       sp2->soffset = argbase;
+                       argbase += sz;
+                       nrarg = regparmarg;     /* no more in reg either */
+               } else {                                        /* in reg */
+                       sp2->soffset = nrarg;
+                       nrarg += sz/SZINT;
+                       sp2->sclass = REGISTER;
+               }
+       }
+
+       /*
+        * Now (argbase - ARGINIT) is used space on stack.
+        * Move (if necessary) the args to something new.
+        */
+       for (i = 0; i < cnt; i++) {
+               int reg, j;
+
+               sp2 = sp[i];
+
+               if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) {
+                       /* must move to stack */
+                       sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
+                       SETOFF(sz, SZINT);
+                       SETOFF(autooff, SZINT);
+                       reg = sp2->soffset;
+                       sp2->sclass = AUTO;
+                       sp2->soffset = NOOFFSET;
+                       oalloc(sp2, &autooff);
+                        for (j = 0; j < sz/SZCHAR; j += 4) {
+                                p = block(OREG, 0, 0, INT, 0, 0);
+                                p->n_lval = sp2->soffset/SZCHAR + j;
+                                regno(p) = FPREG;
+                                n = block(REG, 0, 0, INT, 0, 0);
+                                regno(n) = regpregs[reg++];
+                                p = block(ASSIGN, p, n, INT, 0, 0);
+                                ecomp(p);
+                        }
+               } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) &&
+                   ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) {
+                       /* just put rest in temps */
+                       if (sp2->sclass == REGISTER) {
+                               n = block(REG, 0, 0, sp2->stype,
+                                   sp2->sdf, sp2->sap);
+                               if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG)
+                                       regno(n) = longregs[sp2->soffset];
+                               else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL)
+                                       regno(n) = charregs[sp2->soffset];
+                               else
+                                       regno(n) = regpregs[sp2->soffset];
+                       } else {
+                                n = block(OREG, 0, 0, sp2->stype,
+                                   sp2->sdf, sp2->sap);
+                                n->n_lval = sp2->soffset/SZCHAR;
+                                regno(n) = FPREG;
+                       }
+                       p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap);
+                       sp2->soffset = regno(p);
+                       sp2->sflags |= STNODE;
+                       n = buildtree(ASSIGN, p, n);
+                       ecomp(n);
+               }
+       }
+
+        argstacksize = 0;
+        if (cftnsp->sflags & SSTDCALL) {
+               argstacksize = (argbase - ARGINIT)/SZCHAR;
+        }
+
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+       printf("\t.asciz \"PCC: %s\"\n", VERSSTR);
+}
+
+void
+bjobcode(void)
+{
+       astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
+}
+
+/*
+ * Convert FUNARG to assign in case of regparm.
+ */
+static int regcvt, rparg;
+static void
+addreg(NODE *p)
+{
+       TWORD t;
+       NODE *q;
+       int sz, r;
+
+       sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR;
+       sz = (sz + 3) >> 2;     /* sz in regs */
+       if ((regcvt+sz) > rparg) {
+               regcvt = rparg;
+               return;
+       }
+       if (sz > 2)
+               uerror("cannot put struct in 3 regs (yet)");
+
+       if (sz == 2)
+               r = regcvt == 0 ? AXDX : DXCX;
+       else
+               r = regcvt == 0 ? AX : regcvt == 1 ? DX : CX;
+
+       if (p->n_op == FUNARG) {
+               /* at most 2 regs */
+               if (p->n_type < INT) {
+                       p->n_left = ccast(p->n_left, INT, 0, 0, 0);
+                       p->n_type = INT;
+               }
+
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+       } else if (p->n_op == STARG) {
+               /* convert to ptr, put in reg */
+               q = p->n_left;
+               t = sz == 2 ? LONGLONG : INT;
+               q = cast(q, INCREF(t), 0);
+               q = buildtree(UMUL, q, NIL);
+               p->n_op = ASSIGN;
+               p->n_type = t;
+               p->n_right = q;
+       } else
+               cerror("addreg");
+       p->n_left = block(REG, 0, 0, p->n_type, 0, 0);
+       regno(p->n_left) = r;
+       regcvt += sz;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
+ */
+NODE *
+funcode(NODE *p)
+{
+       extern int gotnr;
+#ifdef GCC_COMPAT
+       struct attr *ap;
+#endif
+       NODE *r, *l;
+       TWORD t = DECREF(DECREF(p->n_left->n_type));
+       int stcall;
+
+       stcall = ISSOU(t);
+       /*
+        * We may have to prepend:
+        * - Hidden arg0 for struct return (in reg or on stack).
+        * - ebx in case of PIC code.
+        */
+
+       /* Fix function call arguments. On x86, just add funarg */
+       for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+               if (r->n_right->n_op != STARG) {
+                       r->n_right = intprom(r->n_right);
+                       r->n_right = block(FUNARG, r->n_right, NIL,
+                           r->n_right->n_type, r->n_right->n_df,
+                           r->n_right->n_ap);
+               }
+       }
+       if (r->n_op != STARG) {
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_left = intprom(r->n_left);
+               r->n_type = r->n_left->n_type;
+       }
+       if (stcall) {
+               /* Prepend a placeholder for struct address. */
+               /* Use BP, can never show up under normal circumstances */
+               l = talloc();
+               *l = *r;
+               r->n_op = CM;
+               r->n_right = l;
+               r->n_type = INT;
+               l = block(REG, 0, 0, INCREF(VOID), 0, 0);
+               regno(l) = BP;
+               l = block(FUNARG, l, 0, INCREF(VOID), 0, 0);
+               r->n_left = l;
+       }
+
+#ifdef GCC_COMPAT
+       if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM)))
+               rparg = ap->iarg(0);
+       else
+#endif
+               rparg = 0;
+
+       regcvt = 0;
+       if (rparg)
+               listf(p->n_right, addreg);
+
+       return p;
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+NODE * 
+builtin_return_address(const struct bitable *bt, NODE *a)
+{      
+       int nframes;
+       NODE *f; 
+       
+       if (a->n_op != ICON)
+               goto bad;
+
+       nframes = (int)a->n_lval;
+  
+       tfree(a);       
+                       
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+                                   
+       f = block(PLUS, f, bcon(2), INCREF(PTR+VOID), 0, 0);
+       f = buildtree(UMUL, f, NIL);    
+   
+       return f;
+bad:                                           
+       uerror("bad argument to __builtin_return_address");
+       return bcon(0);
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+       if (a->n_op != ICON)
+               goto bad;
+
+       nframes = (int)a->n_lval;
+
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+
+       return f;
+bad:
+       uerror("bad argument to __builtin_frame_address");
+       return bcon(0);
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       uerror("missing builtin_cfa");
+       return bcon(0);
+}
+
diff --git a/lang/pcc/pcc/arch/i86/flocal.c b/lang/pcc/pcc/arch/i86/flocal.c
new file mode 100644 (file)
index 0000000..1cbe70e
--- /dev/null
@@ -0,0 +1,231 @@
+/*     $Id: flocal.c,v 1.1 2014/09/16 10:47:35 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void
+prchars(int *s)
+{
+       printf("\t.byte 0%o,0%o\n", s[0], s[1]);
+}
+
+void
+setloc(int l)
+{
+       static int lastloc = -1;
+       static char *loctbl[] =
+           { "text", "data", "data", "data", "bss" };
+       if (l == lastloc)
+               return;
+       printf("\t.%s\n", loctbl[l]);
+       lastloc = l;
+}
+
+#ifdef FCOM
+
+
+/*
+       8086 - SPECIFIC PRINTING ROUTINES
+*/
+
+/*
+ * Called just before return from a subroutine.
+ */
+void
+goret(int type)
+{
+}
+
+/*
+ * Print out a label.
+ */
+void
+prlabel(int k)
+{
+       printf(LABFMT ":\n", k);
+}
+
+/*
+ * Print naming for location.
+ * name[0] is location type.
+ */
+void
+prnloc(char *name)
+{
+       if (*name == '0')
+               setloc(DATA);
+       else
+               fatal("unhandled prnloc %c", *name);
+       printf("%s:\n", name+1);
+}
+
+/*
+ * Print integer constant.
+ */
+void
+prconi(FILE *fp, int type, ftnint n)
+{
+       fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n);
+}
+
+/*
+ * Print address constant, given as a label number.
+ */
+void
+prcona(ftnint a)
+{
+       printf("\t.long\t" LABFMT "\n", (int)a);
+}
+
+/*
+ * Print out a floating constant.
+ */
+void
+prconr(FILE *fp, int type, double x)
+{
+       fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x);
+}
+
+void
+preven(int k)
+{
+       if (k > 1)
+               printf("\t.align\t%d\n", k);
+}
+
+/*
+ * Convert a tag and offset into the symtab table to a string.
+ * An external string is never longer than XL bytes.
+ */
+char *
+memname(int stg, int mem)
+{
+#define        MLEN    (XL + 10)
+       char *s = malloc(MLEN);
+
+       switch(stg) {
+       case STGCOMMON:
+       case STGEXT:
+               snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname));
+               break;
+
+       case STGBSS:
+       case STGINIT:
+               snprintf(s, MLEN, "v.%d", mem);
+               break;
+
+       case STGCONST:
+               snprintf(s, MLEN, ".L%d", mem);
+               break;
+
+       case STGEQUIV:
+               snprintf(s, MLEN, "q.%d", mem);
+               break;
+
+       default:
+               fatal1("memname: invalid vstg %d", stg);
+       }
+       return(s);
+}
+
+void
+prlocvar(char *s, ftnint len)
+{
+       printf("%s:\t.blkb\t%ld\n", s, len);
+}
+
+
+void
+prext(char *name, ftnint leng, int init)
+{
+       if(leng == 0)
+               printf("\t.globl\t%s\n", name);
+       else
+               printf("%s:\t.blkb %ld\n", name, leng);
+}
+
+void
+prendproc(void)
+{
+}
+
+void
+prtail(void)
+{
+}
+
+void
+prolog(struct entrypoint *ep, struct bigblock *argvec)
+{
+       /* Ignore for now.  ENTRY is not supported */
+}
+
+void
+prdbginfo(void)
+{
+}
+
+static void
+fcheck(NODE *p, void *arg)
+{
+       NODE *r, *l;
+
+       switch (p->n_op) {
+       case CALL: /* fix arguments */
+               for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+                       r->n_right = mkunode(FUNARG, r->n_right, 0,
+                           r->n_right->n_type);
+               }
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_type = l->n_type;
+               break;
+       }
+}
+
+/*
+ * Called just before the tree is written out to pass2.
+ */
+void p2tree(NODE *p);
+void
+p2tree(NODE *p)
+{
+       walkf(p, fcheck, 0);
+}
+#endif /* FCOM */
diff --git a/lang/pcc/pcc/arch/i86/local.c b/lang/pcc/pcc/arch/i86/local.c
new file mode 100644 (file)
index 0000000..c55f7a9
--- /dev/null
@@ -0,0 +1,634 @@
+/*     $Id: local.c,v 1.3 2015/07/24 08:00:12 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+/*     this file contains code which is dependent on the target machine */
+
+#ifdef notyet
+/*
+ * Check if a constant is too large for a type.
+ */
+static int
+toolarge(TWORD t, CONSZ con)
+{
+       U_CONSZ ucon = con;
+
+       switch (t) {
+       case ULONGLONG:
+       case LONGLONG:
+               break; /* cannot be too large */
+#define        SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break
+#define        UCHK(i) case i: if (ucon > MAX_##i) return 1; break
+       SCHK(INT);
+       SCHK(SHORT);
+       case BOOL:
+       SCHK(CHAR);
+       UCHK(UNSIGNED);
+       UCHK(USHORT);
+       UCHK(UCHAR);
+       default:
+               cerror("toolarge");
+       }
+       return 0;
+}
+#endif
+
+#define        IALLOC(sz)      (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+
+int gotnr; /* tempnum for GOT register */
+int argstacksize;
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+       struct attr *ap;
+       register struct symtab *q;
+       register NODE *r, *l;
+       register int o;
+       register int m;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case USTATIC:
+                       break;
+               case STATIC:
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+               case EXTERN:
+               case EXTDEF:
+                       break;
+               }
+               break;
+
+       case ADDROF:
+               break;
+
+       case UCALL:
+               break;
+
+       case USTCALL:
+               /* Add hidden arg0 */
+               r = block(REG, NIL, NIL, INCREF(VOID), 0, 0);
+               regno(r) = BP;
+               if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL &&
+                   ap->iarg(0) > 0) {
+                       l = block(REG, NIL, NIL, INCREF(VOID), 0, 0);
+                       regno(l) = AX;
+                       p->n_right = buildtree(ASSIGN, l, r);
+               } else
+                       p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0);
+               p->n_op -= (UCALL-CALL);
+
+               if (kflag == 0)
+                       break;
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               regno(l) = BX;
+               r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
+               p->n_right = block(CM, r, p->n_right, INT, 0, 0);
+               break;
+
+#ifdef notyet
+       /* XXX breaks sometimes */
+       case CBRANCH:
+               l = p->n_left;
+
+               /*
+                * Remove unnecessary conversion ops.
+                */
+               if (!clogop(l->n_op) || l->n_left->n_op != SCONV)
+                       break;
+               if (coptype(l->n_op) != BITYPE)
+                       break;
+               if (l->n_right->n_op != ICON)
+                       break;
+               r = l->n_left->n_left;
+               if (r->n_type >= FLOAT)
+                       break;
+               if (toolarge(r->n_type, l->n_right->n_lval))
+                       break;
+               l->n_right->n_type = r->n_type;
+               if (l->n_op >= ULE && l->n_op <= UGT)
+                       l->n_op -= (UGT-ULE);
+               p->n_left = buildtree(l->n_op, r, l->n_right);
+               nfree(l->n_left);
+               nfree(l);
+               break;
+#endif
+
+       case PCONV:
+               l = p->n_left;
+
+               /* Make int type before pointer */
+               if (l->n_type < INT || l->n_type == LONGLONG || 
+                   l->n_type == ULONGLONG || l->n_type == BOOL) {
+                       /* float etc? */
+                       p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
+               }
+               break;
+
+       case SCONV:
+               if (p->n_left->n_op == COMOP)
+                       break;  /* may propagate wrong type later */
+               l = p->n_left;
+
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       return l;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) ==
+                   tsize(l->n_type, l->n_df, l->n_ap)) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       return l;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
+                   l->n_op != QUEST) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       return l;
+               }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       /*
+                        * Can only end up here if o is an address,
+                        * and in that case the only compile-time conversion
+                        * possible is to int.
+                        */
+                       if ((TMASK & l->n_type) == 0 && l->n_sp == NULL)
+                               cerror("SCONV ICON");
+                       if (l->n_sp == 0) {
+                               p->n_type = UNSIGNED;
+                               concast(l, m);
+                       } else if (m != INT && m != UNSIGNED)
+                               break;
+                       l->n_type = m;
+                       l->n_ap = 0;
+                       nfree(p);
+                       return l;
+               } else if (l->n_op == FCON)
+                       cerror("SCONV FCON");
+               if ((p->n_type == CHAR || p->n_type == UCHAR ||
+                   p->n_type == SHORT || p->n_type == USHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = makety(p->n_left, INT, 0, 0, 0);
+               p->n_right = makety(p->n_right, INT, 0, 0, 0);
+               o = p->n_type;
+               p->n_type = INT;
+               p = makety(p, o, 0, 0, 0);
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(CHAR) : RETREG(p->n_type);
+               break;
+
+       case LS:
+       case RS:
+               /* shift count must be in a char */
+               if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+                       break;
+               p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0);
+               break;
+       }
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+static void mangle(NODE *p);
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+
+       mangle(p);
+
+       if (p->n_op != FCON)
+               return;
+
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+       sp->sname = sp->soname = NULL;
+
+       locctr(DATA, sp);
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       p->n_lval = 0;
+       p->n_sp = sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);      /* all names can have & taken on them */
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return 0; /* not yet */
+       return 1;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+       int i;
+
+       switch (p->n_type) {
+       case LONGLONG:
+       case ULONGLONG:
+               i = (int)(p->n_lval >> 32);
+               p->n_lval &= 0xffffffff;
+               p->n_type = INT;
+               inval(off, 32, p);
+               p->n_lval = i;
+               inval(off+32, 32, p);
+               break;
+       case LDOUBLE:
+               u.i[2] = 0;
+               u.l = (long double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+               /* XXX probably broken on most hosts */
+               printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
+#else
+               printf("\t.long\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777);
+#endif
+               break;
+       case DOUBLE:
+               u.d = (double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+               printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
+               printf("\t.long\t%d,%d\n", u.i[0], u.i[1]);
+#endif
+               break;
+       case FLOAT:
+               u.f = (float)p->n_dcon;
+               printf("\t.long\t%d\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#define NCHNAM  256
+       static char text[NCHNAM+1];
+       int i;
+
+       if (p == NULL)
+               return "";
+
+       text[0] = '_';
+       for (i=1; *p && i<NCHNAM; ++i)
+               text[i] = *p++;
+
+       text[i] = '\0';
+       text[NCHNAM] = '\0';  /* truncate */
+
+       return (text);
+}
+
+/*
+ * map types which are not defined on the local machine
+ *
+ * For 8086 we map short/ushort onto int/unsigned int which
+ * removes some of the table stuff later on
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case SHORT:
+               MODTYPE(type,INT);
+               break;
+
+       case USHORT:
+               MODTYPE(type,UNSIGNED);
+
+       }
+       return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off;
+       int al;
+       char *name;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+       al = talign(sp->stype, sp->sap)/SZCHAR;
+       off = (int)tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+       printf("\t.align %d\n", al);
+       printf("%s:\t.blkb %d\n", name, off);
+}
+
+static int stdcall;
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       char *a2 = pragtok(NULL);
+
+       if (strcmp(str, "stdcall") == 0) {
+               stdcall = 1;
+               return 1;
+       }
+       if (strcmp(str, "cdecl") == 0) {
+               stdcall = 0;
+               return 1;
+       }
+#ifndef AOUTABI
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+#endif
+       if (strcmp(str, "alias") == 0 && a2 != NULL) {
+               alias = tmpstrdup(a2);
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+#ifdef GCC_COMPAT
+       struct attr *ap;
+#endif
+#ifdef GCC_COMPAT
+#ifdef HAVE_WEAKREF
+       /* not many as'es have this directive */
+       if ((ap = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
+               char *wr = ap->sarg(0);
+               char *sn = sp->soname ? sp->soname : sp->sname;
+               if (sp->sclass != STATIC && sp->sclass != USTATIC)
+                       uerror("weakref %s must be static", sp->sname);
+               if (wr == NULL) {
+                       if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS))) {
+                               wr = ap->sarg(0);
+                       }
+               }
+               if (wr == NULL)
+                       printf("\t.weak %s\n", sn);
+               else
+                       printf("\t.weakref %s,%s\n", sn, wr);
+       } else
+#endif
+           if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
+               char *an = ap->sarg(0);  
+               char *sn = sp->soname ? sp->soname : sp->sname; 
+               char *v;
+
+               v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
+               printf("\t.%s %s\n", v, sn);
+               printf("\t.set %s,%s\n", sn, an);
+       }       
+#endif
+       if (alias != NULL && (sp->sclass != PARAM)) {
+               char *name;
+               if ((name = sp->soname) == NULL)
+                       name = exname(sp->sname);
+               printf("\t.globl %s\n", name);
+               printf("%s = ", name);
+               printf("%s\n", exname(alias));
+               alias = NULL;
+       }
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+               printf("\t.section .%ctors,\"w\"\n",
+                   constructor ? 'c' : 'd');
+               printf("\t.p2align 2\n");
+               printf("\t.long %s\n", exname(sp->sname));
+               printf("\t.previous\n");
+               constructor = destructor = 0;
+       }
+       if (stdcall && (sp->sclass != PARAM)) {
+               sp->sflags |= SSTDCALL;
+               stdcall = 0;
+       }
+}
+
+/*
+ *  Postfix external functions with the arguments size.
+ */
+static void
+mangle(NODE *p)
+{
+       NODE *l;
+
+       if (p->n_op != CALL && p->n_op != STCALL &&
+           p->n_op != UCALL && p->n_op != USTCALL)
+               return;
+
+       l = p->n_left;
+       while (cdope(l->n_op) & CALLFLG)
+               l = l->n_left;
+       if (l->n_op == TEMP)
+               return;
+       if (l->n_op == ADDROF)
+               l = l->n_left;
+       if (l->n_sp == NULL)
+               return;
+#ifdef GCC_COMPAT
+       if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
+               l->n_sp->sflags |= SSTDCALL;
+#endif
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+       if (ip->type == IP_NODE &&
+           (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) &&
+           ISFTY(ip->ip_node->n_type))
+               ip->ip_node->n_ap = attr_add(ip->ip_node->n_ap,
+                   attr_new(ATTR_I86_FPPOP, 1));
+       if (ip->type == IP_EPILOG) {
+               struct interpass_prolog *ipp = (struct interpass_prolog *)ip;
+               ipp->ipp_argstacksize = argstacksize;
+       }
+}
diff --git a/lang/pcc/pcc/arch/i86/local2.c b/lang/pcc/pcc/arch/i86/local2.c
new file mode 100644 (file)
index 0000000..c32e8df
--- /dev/null
@@ -0,0 +1,1544 @@
+/*     $Id: local2.c,v 1.7 2015/07/24 08:00:12 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+#define EXPREFIX       "_"
+
+static int stkpos;
+
+static int suppress_type;              /* Don't display a type on the
+                                          next expansion */
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static int regoff[7];
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+       int i;
+
+#if 1
+       /* FIXME: can't use enter/leave if generating i8086 */
+       if (addto == 0 || addto > 65535 || 1) {
+               printf("        push bp\n\tmov bp,sp\n");
+               if (addto)
+                       printf("        sub sp,#%d\n", addto);
+       } else
+               printf("        enter %d,0\n", addto);
+#endif
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i))
+                       printf("        mov -%d[%s],%s\n",
+                            regoff[i], rnames[FPREG], rnames[i]);
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+       int i, addto;
+
+       addto = p2maxautooff;
+       if (addto >= AUTOINIT/SZCHAR)
+               addto -= AUTOINIT/SZCHAR;
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       addto += SZINT/SZCHAR;
+                       regoff[i] = addto;
+               }
+       return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+
+       ftype = ipp->ipp_type;
+
+#ifdef LANG_F77
+       if (ipp->ipp_vis)
+               printf("        .globl %s\n", ipp->ipp_name);
+       printf("        .align 4\n");
+       printf("%s:\n", ipp->ipp_name);
+#endif
+       /*
+        * We here know what register to save and how much to 
+        * add to the stack.
+        */
+       addto = offcalc(ipp);
+       prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       int i;
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       /* return from function code */
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i))
+                       printf("        mov %s,-%d[%s]\n",
+                           rnames[i],regoff[i], rnames[FPREG]);
+
+       /* struct return needs special treatment */
+       if (ftype == STRTY || ftype == UNIONTY) {
+               printf("        mov ax, 8[bp]\n");
+               printf("        leave\n");
+               /* FIXME: ret n is not in 8086 */
+               printf("        ret %d\n", 4 + ipp->ipp_argstacksize);
+       } else {
+               printf("        mov sp, bp\n");
+               printf("        pop bp\n");
+               if (ipp->ipp_argstacksize)
+                       /* CHECK ME */
+                       printf("        add sp, #%d\n", ipp->ipp_argstacksize);
+               printf("        ret\n");
+       }
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s", str);      /* don't need %c f as far as I can see */
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+               case INT:
+               case UNSIGNED:
+                       return(SZINT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case LONG:
+               case ULONG:
+                       return(SZLONG/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Emit code to compare two long numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int u;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       u = p->n_op;
+       switch (p->n_op) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               u += (ULE-LE);
+               /* FALLTHROUGH */
+       case ULE:
+       case ULT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               u += (ULE-LE);
+               /* FALLTHROUGH */
+       case UGE:
+       case UGT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       expand(p, 0, "  cmp UL,UR\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+       expand(p, 0, "  cmp AL,AR\n");
+       cbgen(u, e);
+       deflab(s);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       comperr("fldexpand");
+       return 0;
+}
+
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+       NODE *q = p->n_left;
+       int s = (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + 1) & ~1;
+
+       if (s == 2)
+               printf("        dec sp\n        dec sp\n");
+       else
+               printf("        sub sp,#%d\n", s);
+       p->n_left = mklnode(OREG, 0, SP, INT);
+       zzzcode(p, 'Q');
+       tfree(p->n_left);
+       p->n_left = q;
+}
+
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p)  
+{
+       static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
+
+       if ((p->n_su & DORIGHT) == 0)
+               expand(p, 0, "\tfxch\n");
+       expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn  */
+       expand(p, 0, "\tfstp %st(0)\n");        /* pop fromstack */
+
+       if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
+               expand(p, 0, "\tjp LC\n");
+       else if (p->n_op == EQ)
+               printf("\tjp 1f\n");
+       printf("        %s ", fpcb[p->n_op - EQ]);
+       expand(p, 0, "LC\n");
+       if (p->n_op == EQ)
+               printf("1:\n");
+}
+
+/*
+ * Convert an unsigned long long to floating point number.
+ */
+static void
+ulltofp(NODE *p)
+{
+       int jmplab;
+
+       jmplab = getlab2();
+       expand(p, 0, "  push UL\n       push AL\n");
+       expand(p, 0, "  fildq [sp]\n");
+       expand(p, 0, "  add sp, #8\n");
+       expand(p, 0, "  cmp UL, #0\n");
+       printf("        jge " LABFMT "\n", jmplab);
+
+       printf("        faddp %%st,%%st(1)\n");
+       printf(LABFMT ":\n", jmplab);
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+       if (t < LONG)
+               return 2;
+       if (t == LONG || t == ULONG || t == LONGLONG || t == ULONGLONG)
+               return 4;
+       if (t == FLOAT)
+               return 4;
+       if (t > BTMASK)
+               return 2;
+       if (t == DOUBLE)
+               return 8;
+       if (t == LDOUBLE)
+               return 12;
+       if (t == STRTY || t == UNIONTY)
+               return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+1) & ~1;
+       comperr("argsiz");
+       return 0;
+}
+
+static void
+fcast(NODE *p)
+{
+       TWORD t = p->n_type;
+       int sz, c;
+
+       if (t >= p->n_left->n_type)
+               return; /* cast to more precision */
+       if (t == FLOAT)
+               sz = 4, c = 's';
+       else
+               sz = 8, c = 'l';
+
+       printf("        sub sp, #%d\n", sz);
+       printf("        fstp%c (%%sp)\n", c);
+       printf("        fld%c (%%sp)\n", c);
+       printf("        add sp, #%d\n", sz);
+}
+
+
+#if 0  
+
+static void
+llshft(NODE *p)
+{
+       NODE *r = p->n_right;
+       /* FIXME: we have sal/shl/sar/shr but we are limited to
+          shift right or left 1
+          shift right or left by CL */
+       char *d[3];
+       /* We ought to shortcut this earlier but it's not obivous how
+          to do a match and say 'any old register pair' FIXME */
+       if (r->n_op == ICON) {
+               /* FIXME: we need different versions of this for signed right
+                  shifting. Just test code - register setup needs checking
+                  for ordering etc yet */
+               if (r->n_lval == 16) {
+                       if (p->n_op == RS)
+                               printf("\tmov ax, dx\n\txor dx,dx\n");
+                       else
+                               printf("\tmov dx, ax\n\txor ax,ax\n");
+                       return;
+               }
+               if (r->n_lval == 8) {
+                       if (p->n_op == RS)
+                               printf("\tmov al, ah\n\tmov ah, dl\n\tmov dl, dh\n\txor dh,dh\n");
+                       else
+                               printf("\tmov ah, al\n\tmov dl, ah\n\tmov dh, dl\n\txor al, al\n");
+                       return;
+               } 
+               if (r->n_lval == 24) {
+                       if (p->n_op == RS)
+                               printf("\txor dx,dx\n\tmov al, dh\n\txor ax,ax\n");
+                       else
+                               printf("\txor ax,ax\n\tmov dh, al\n\txor dx,dx\n");
+                       return;
+               }
+       }
+       if (p->n_op == LS) {
+               d[0] = "l", d[1] = "ax", d[2] = "dx";
+       } else
+               d[0] = "r", d[1] = "dx", d[2] = "ax";
+
+       printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]);
+       printf("\ts%s%sl %%cl,%s\n", p->n_op == RS &&
+           (p->n_left->n_type == ULONG || p->n_left->n_type == ULONGLONG) ?
+                                       "h" : "a", d[0], d[1]);
+       printf("\ttestb $16,%%cl\n");
+       printf("\tje 1f\n");
+       printf("\tmov %s,%s\n", d[1], d[2]);
+       if (p->n_op == RS && (p->n_left->n_type == LONGLONG|| p->n_left->n_type == LONG))
+               printf("\tsarl $31,%%edx\n");
+       else
+               printf("\txor %s,%s\n",d[1],d[1]);
+       printf("1:\n");
+}
+#endif
+
+void
+zzzcode(NODE *p, int c)
+{
+       struct attr *ap;
+       NODE *l;
+       int pr, lr;
+       char *ch;
+       char sv;
+
+       switch (c) {
+       case 'A': /* swap st0 and st1 if right is evaluated second */
+               if ((p->n_su & DORIGHT) == 0) {
+                       if (logop(p->n_op))
+                               printf("        fxch\n");
+                       else
+                               printf("r");
+               }
+               break;
+
+       case 'C':  /* remove from stack after subroutine call */
+#ifdef notdef
+               if (p->n_left->n_flags & FSTDCALL)
+                       break;
+#endif
+               pr = p->n_qual;
+               if (attr_find(p->n_ap, ATTR_I86_FPPOP))
+                       printf("        fstp    st(0)\n");
+               if (p->n_op == UCALL)
+                       return; /* XXX remove ZC from UCALL */
+               if (pr) {
+                       if (pr == 2)
+                               printf("        inc sp\n        inc sp\n");
+                       else
+                               printf("        add sp,#%d\n", pr);
+               }
+               break;
+
+       case 'D': /* Long comparision */
+               twollcomp(p);
+               break;
+
+       case 'F': /* Structure argument */
+               starg(p);
+               break;
+
+       case 'G': /* Floating point compare */
+               fcomp(p);
+               break;
+
+       case 'H': /* assign of long between regs */
+               rmove(DECRA(p->n_right->n_reg, 0),
+                   DECRA(p->n_left->n_reg, 0), LONGLONG);
+               break;
+
+       case 'I': /* float casts */
+               fcast(p);
+               break;
+
+       case 'J': /* convert unsigned long long to floating point */
+               ulltofp(p);
+               break;
+
+       case 'K': /* Load long reg into another reg */
+               rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
+               break;
+
+       case 'M': /* Output sconv move, if needed */
+               l = getlr(p, 'L');
+               /* XXX fixneed: regnum */
+               pr = DECRA(p->n_reg, 0);
+               lr = DECRA(l->n_reg, 0);
+               if ((pr == AL && lr == AX) || (pr == BL && lr == BX) ||
+                   (pr == CL && lr == CX) || (pr == DL && lr == DX))
+                       ;
+               else
+                       printf("        mov %s, %cL\n",
+                           rnames[pr], rnames[lr][1]);
+               l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
+               break;
+
+       case 'N': /* output extended reg name */
+               printf("%s", rnames[getlr(p, '1')->n_rval]);
+               break;
+
+       case 'O': /* print out emulated ops */
+               pr = 8;
+               sv = 'l';
+#if 0          
+               if (p->n_op == RS || p->n_op == LS) {
+                       llshft(p);
+                       break;
+               }
+#endif
+               if (p->n_op != RS && p->n_op != LS) {
+                       /* For 64bit we will need to push pointers
+                          not u64 */
+                       expand(p, INCREG, "\tpush UR\n\tpush AR\n");
+                       expand(p, INCREG, "\tpush UL\n\tpush AL\n");
+               } else {
+                       /* AR is a BREG so this goes wrong.. need an AREG
+                          but putting an AREG in the table rule makes the
+                          compiler shit itself - FIXME */
+                       expand(p, INAREG, "\tpush AR\n");
+                       expand(p, INCREG, "\tpush UL\n\tpush AL\n");
+                       pr = 6;
+               }
+               
+               if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
+                       sv = 'L';
+               if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG))
+                       ch = "udiv";
+               else if (p->n_op == MUL && (p->n_type == ULONG || p->n_type == ULONGLONG))
+                       ch = "umul";
+               else if (p->n_op == DIV) ch = "div";
+               else if (p->n_op == MUL) ch = "mul";
+               else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == ULONGLONG))
+                       ch = "umod";
+               else if (p->n_op == MOD) ch = "mod";
+               else if (p->n_op == LS) ch = "ls";
+               else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == ULONGLONG))
+                       ch = "rs";
+               else if (p->n_op == RS) ch = "urs";
+               else ch = 0, comperr("ZO");
+               printf("\tcall " EXPREFIX "__%c%sdi3\n\tadd %s,#%d\n",
+                       sv, ch, rnames[SP], pr);
+                break;
+       
+       case 'P': /* typeless right hand */
+               suppress_type = 1;
+               break;
+
+       case 'Q': /* emit struct assign */
+               /*
+                * Put out some combination of movs{b,w}
+                * si/di/cx are available.
+                * FIXME: review es: and direction flag implications
+                */
+               expand(p, INAREG, "     lea al,di\n");
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               if (ap->iarg(0) < 32) {
+                       int i = ap->iarg(0) >> 1;
+                       while (i) {
+                               expand(p, INAREG, "     movsw\n");
+                               i--;
+                       }
+               } else {
+                       printf("\tmov cx, #%d\n", ap->iarg(0) >> 1);
+                       printf("        rep movsw\n");
+               }
+               if (ap->iarg(0) & 2)
+                       printf("        movsw\n");
+               if (ap->iarg(0) & 1)
+                       printf("        movsb\n");
+               break;
+
+       case 'S': /* emit eventual move after cast from long */
+               pr = DECRA(p->n_reg, 0);
+               lr = p->n_left->n_rval;
+               switch (p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       if (rnames[pr][1] == 'L' && rnames[lr][1] == 'X' &&
+                           rnames[pr][0] == rnames[lr][0])
+                               break;
+                       if (rnames[lr][1] == 'X') {
+                               printf("\tmov %s, %cL\n",
+                                   rnames[pr], rnames[lr][0]);
+                               break;
+                       }
+                       /* Must go via stack */
+                       expand(p, INAREG, "\tmov A2,AL\n");
+                       expand(p, INBREG, "\tmov A1,A2\n");
+#ifdef notdef
+                       /* cannot use freetemp() in instruction emission */
+                       s = freetemp(1);
+                       printf("\tmov %ci,%d(bp)\n", rnames[lr][0], s);
+                       printf("\tmov %s, %d(bp)\n", rnames[pr], s);
+#endif
+                       break;
+
+               case INT:
+               case UNSIGNED:
+                       if (rnames[lr][0] == rnames[pr][1] &&
+                           rnames[lr][1] == rnames[pr][2])
+                               break;
+                       printf("\tmov %s, %c%c\n",
+                                   rnames[pr], rnames[lr][0], rnames[lr][1]);
+                       break;
+
+               default:
+                       if (rnames[lr][0] == rnames[pr][1] &&
+                           rnames[lr][1] == rnames[pr][2])
+                               break;
+                       comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
+                       break;
+               }
+               break;
+       case 'T':
+               /* Conversions from unsigned char to int/ptr */
+               /* Cannot be in DI or SI */
+               l = getlr(p, 'L');
+               lr = regno(l);
+               pr = regno(getlr(p, '1'));
+               if (l->n_op != REG) { /* NAME or OREG */
+                       /* Need to force a mov into the low half, using
+                          a movw might fail in protected mode or with
+                          mmio spaces */
+                       printf("        mov %cl, ", rnames[pr][0]);
+                       expand(p, INAREG, "AL\n");
+               } else {
+                       if ((lr == AL && pr == AX) ||
+                           (lr == BL && pr == BX) ||
+                           (lr == CL && pr == CX) ||
+                           (lr == DL && pr == DX))
+                               ;
+                         else
+                               printf("        mov %cl,%cl\n",
+                                       rnames[pr][0],rnames[lr][0]);
+                }
+               printf("        xor %ch,%ch\n",
+                               rnames[pr][0], rnames[pr][0]);
+               break;
+                                                                                                                                                                                                                  break;
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       comperr("flshape");
+       return 0;
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = (int)p->n_lval;
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "#%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+%d", val);
+               } else
+                       fprintf(fp, "#%d", val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%s", &rnames[p->n_rval][2]);
+               break;
+
+       case NAME:
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+       case ICON:
+               printf("#"CONFMT, p->n_lval >> 16);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+static void do_adrput(FILE *io, NODE *p, int ut)
+{
+       int r;
+       /* output an address, with offsets, from p */
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (!ut) {
+                       switch (p->n_type) {
+                               case SHORT:
+                               case USHORT:
+                               case INT:
+                               case UNSIGNED:
+                                       printf("word ptr ");
+                                       break;
+                               case CHAR:
+                               case UCHAR:
+                                       printf("byte ptr ");
+                       }
+               }
+               if (p->n_name[0] != '\0') {
+                       fputs(p->n_name, io);
+                       if (p->n_lval != 0)
+                               fprintf(io, "+" CONFMT, p->n_lval);
+               } else
+                       fprintf(io, "#"CONFMT, p->n_lval);
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               if (p->n_name[0])
+                       printf("%s%s", p->n_name, p->n_lval ? "+" : "");
+               if (p->n_lval)
+                       fprintf(io, "%d", (int)p->n_lval);
+               printf("[");
+               if (R2TEST(r)) {
+                       fprintf(io, "%s,%s,4", rnames[R2UPK1(r)],
+                           rnames[R2UPK2(r)]);
+               } else
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               printf("]");
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               if (!ut) {
+                       switch (p->n_type) {
+                               case SHORT:
+                               case USHORT:
+                               case INT:
+                               case UNSIGNED:
+                                       printf("word ");
+                                       break;
+                                       case CHAR:
+                               case UCHAR:
+                                       printf("byte ");
+                       }
+               }
+               conput(io, p);
+               return;
+
+       case REG:
+               switch (p->n_type) {
+               case LONGLONG:
+               case ULONGLONG:
+               case LONG:
+               case ULONG:
+                       fprintf(io, "%c%c", rnames[p->n_rval][0],
+                           rnames[p->n_rval][1]);
+                       break;
+               default:
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               }
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+void adrput(FILE *io, NODE *p)
+{
+       do_adrput(io, p, suppress_type);
+       suppress_type = 0;
+}
+
+static char *
+ccbranches[] = {
+       "je",           /* jumpe */
+       "jne",          /* jumpn */
+       "jle",          /* jumple */
+       "jl",           /* jumpl */
+       "jge",          /* jumpge */
+       "jg",           /* jumpg */
+       "jbe",          /* jumple (jlequ) */
+       "jb",           /* jumpl (jlssu) */
+       "jae",          /* jumpge (jgequ) */
+       "ja",           /* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("        %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static void
+fixcalls(NODE *p, void *arg)
+{
+       /* Prepare for struct return by allocating bounce space on stack */
+       switch (p->n_op) {
+       case STCALL:
+       case USTCALL:
+               if (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+p2autooff > stkpos)
+                       stkpos = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+p2autooff;
+               break;
+       case LS:
+       case RS:
+               if (p->n_type != LONGLONG && p->n_type != ULONGLONG
+                   && p->n_type != LONG && p->n_type != ULONG)
+                       break;
+               if (p->n_right->n_op == ICON) /* constants must be char */
+                       p->n_right->n_type = CHAR;
+               break;
+       }
+}
+
+/*
+ * Must store floats in memory if there are two function calls involved.
+ */
+static int
+storefloat(struct interpass *ip, NODE *p)
+{
+       int l, r;
+
+       switch (optype(p->n_op)) {
+       case BITYPE:
+               l = storefloat(ip, p->n_left);
+               r = storefloat(ip, p->n_right);
+               if (p->n_op == CM)
+                       return 0; /* arguments, don't care */
+               if (callop(p->n_op))
+                       return 1; /* found one */
+#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
+       (p)->n_type == LDOUBLE)
+               if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
+                       /* must store one. store left */
+                       struct interpass *nip;
+                       TWORD t = p->n_left->n_type;
+                       NODE *ll;
+                       int off;
+
+                       off = freetemp(szty(t));
+                       ll = mklnode(OREG, off, FPREG, t);
+                       nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
+                       p->n_left = mklnode(OREG, off, FPREG, t);
+                       DLIST_INSERT_BEFORE(ip, nip, qelem);
+               }
+               return l|r;
+
+       case UTYPE:
+               l = storefloat(ip, p->n_left);
+               if (callop(p->n_op))
+                       l = 1;
+               return l;
+       default:
+               return 0;
+       }
+}
+
+static void
+outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
+{
+       struct interpass *ip2;
+       NODE *q, *r;
+       int i;
+
+       for (i = 0; i < num; i++)
+               if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT)))
+                       break;
+       if (i == num)
+               return;
+       q = ary[i]->n_left;
+       r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
+       ary[i]->n_left = tcopy(r);
+       ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type));
+       DLIST_INSERT_AFTER(ip, ip2, qelem);
+}
+
+static void
+infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
+{
+       struct interpass *ip2;
+       NODE *q, *r;
+       int i;
+
+       for (i = 0; i < num; i++)
+               if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0)
+                       break;
+       if (i == num)
+               return;
+       q = ary[i]->n_left;
+       q = (cwp[i] & XASMINOUT) ? tcopy(q) : q;
+       r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
+       if ((cwp[i] & XASMINOUT) == 0)
+               ary[i]->n_left = tcopy(r);
+       ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type));
+       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+}
+
+/*
+ * Extract float args to XASM and ensure that they are put on the stack
+ * in correct order.
+ * This should be done sow other way.
+ */
+static void
+fixxfloat(struct interpass *ip, NODE *p)
+{
+       NODE *w, **ary;
+       int nn, i, c, *cwp;
+
+       nn = 1;
+       w = p->n_left;
+       if (w->n_op == ICON && w->n_type == STRTY)
+               return;
+       /* index all xasm args first */
+       for (; w->n_op == CM; w = w->n_left)
+               nn++;
+       ary = tmpcalloc(nn * sizeof(NODE *));
+       cwp = tmpcalloc(nn * sizeof(int));
+       for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) {
+               ary[i] = w->n_right;
+               cwp[i] = xasmcode(ary[i]->n_name);
+               i++;
+       }
+       ary[i] = w;
+       cwp[i] = xasmcode(ary[i]->n_name);
+       for (i = 0; i < nn; i++)
+               if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u')
+                       break;
+       if (i == nn)
+               return;
+
+       for (i = 0; i < nn; i++) {
+               c = XASMVAL(cwp[i]);
+               if (c >= '0' && c <= '9')
+                       cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']);
+       }
+       infargs(ip, ary, nn, cwp, 'u');
+       infargs(ip, ary, nn, cwp, 't');
+       outfargs(ip, ary, nn, cwp, 't');
+       outfargs(ip, ary, nn, cwp, 'u');
+}
+
+static NODE *
+lptr(NODE *p)
+{
+       if (p->n_op == ASSIGN && p->n_right->n_op == REG &&
+           regno(p->n_right) == BP)
+               return p->n_right;
+       if (p->n_op == FUNARG && p->n_left->n_op == REG &&
+           regno(p->n_left) == BP)
+               return p->n_left;
+       return NIL;
+}
+
+/*
+ * Find arg reg that should be struct reference instead.
+ */
+static void
+updatereg(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op != STCALL)
+               return;
+       if (p->n_right->n_op != CM)
+               p = p->n_right;
+       else for (p = p->n_right;
+           p->n_op == CM && p->n_left->n_op == CM; p = p->n_left)
+               ;
+       if (p->n_op == CM) {
+               if ((q = lptr(p->n_left)))
+                       ;
+               else
+                       q = lptr(p->n_right);
+       } else
+               q = lptr(p);
+       if (q == NIL)
+               comperr("bad STCALL hidden reg");
+
+       /* q is now the hidden arg */
+       q->n_op = MINUS;
+       q->n_type = INCREF(CHAR);
+       q->n_left = mklnode(REG, 0, BP, INCREF(CHAR));
+       q->n_right = mklnode(ICON, stkpos, 0, INT);
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       stkpos = p2autooff;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, fixcalls, 0);
+               storefloat(ip, ip->ip_node);
+               if (ip->ip_node->n_op == XASM)
+                       fixxfloat(ip, ip->ip_node);
+       }
+       if (stkpos != p2autooff) {
+               DLIST_FOREACH(ip, ipole, qelem) {
+                       if (ip->type != IP_NODE)
+                               continue;
+                       walkf(ip->ip_node, updatereg, 0);
+               }
+       }
+       if (stkpos > p2autooff)
+               p2autooff = stkpos;
+       if (stkpos > p2maxautooff)
+               p2maxautooff = stkpos;
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+static char rl[] =
+  { AX, AX, AX, AX, AX, DX, DX, DX, DX, CX, CX, CX, BX, BX, SI };
+static char rh[] =
+  { DX, CX, BX, SI, DI, CX, BX, SI, DI, BX, SI, DI, SI, DI, DI };
+
+void
+rmove(int s, int d, TWORD t)
+{
+       int sl, sh, dl, dh;
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+       case LONG:
+       case ULONG:             /* ?? FIXME check */
+#if 1
+               sl = rl[s-AXDX];
+               sh = rh[s-AXDX];
+               dl = rl[d-AXDX];
+               dh = rh[d-AXDX];
+
+               /* sanity checks, remove when satisfied */
+               if (memcmp(rnames[s], rnames[sl], 2) != 0 ||
+                   memcmp(rnames[s]+2, rnames[sh], 2) != 0)
+                       comperr("rmove source error");
+               if (memcmp(rnames[d], rnames[dl], 2) != 0 ||
+                   memcmp(rnames[d]+2, rnames[dh], 2) != 0)
+                       comperr("rmove dest error");
+#define        SW(x,y) { int i = x; x = y; y = i; }
+               if (sh == dl) {
+                       /* Swap if overwriting */
+                       SW(sl, sh);
+                       SW(dl, dh);
+               }
+               if (sl != dl)
+                       printf("        mov %s,%s\n", rnames[dl], rnames[sl]);
+               if (sh != dh)
+                       printf("        mov %s,%s\n", rnames[dh], rnames[sh]);
+#else
+               if (memcmp(rnames[s], rnames[d], 2) != 0)
+                       printf("        mov %c%c,%c%c\n",
+                           rnames[d][0],rnames[d][1],
+                           rnames[s][0],rnames[s][1]);
+               if (memcmp(&rnames[s][2], &rnames[d][2], 2) != 0)
+                       printf("        mov %c%c,%c%c\n",
+                           rnames[d][2],rnames[d][3]
+                           rnames[s][2],rnames[s][3]);
+#endif
+               break;
+       case CHAR:
+       case UCHAR:
+               printf("        mov %s,%s\n", rnames[d], rnames[s]);
+               break;
+       case FLOAT:
+       case DOUBLE:
+       case LDOUBLE:
+#ifdef notdef
+               /* a=b()*c(); will generate this */
+               comperr("bad float rmove: %d %d", s, d);
+#endif
+               break;
+       default:
+               printf("        mov %s,%s\n", rnames[d], rnames[s]);
+       }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num;
+
+       switch (c) {
+       case CLASSA:
+               num = r[CLASSB] > 4 ? 4 : r[CLASSB];
+               num += 2*r[CLASSC];
+               num += r[CLASSA];
+               return num < 6;
+       case CLASSB:
+               num = r[CLASSA];
+               num += 2*r[CLASSC];
+               num += r[CLASSB];
+               return num < 4;
+       case CLASSC:
+               num = r[CLASSA];
+               num += r[CLASSB] > 4 ? 4 : r[CLASSB];
+               num += 2*r[CLASSC];
+               return num < 5;
+       case CLASSD:
+               return r[CLASSD] < DREGCNT;
+       }
+       return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+       "ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
+       "al", "ah", "dl", "dh", "cl", "ch", "bl", "bh",
+       "axdx", "axcx", "axbx", "axsi", "axdi", "dxcx",
+       "dxbx", "dxsi", "dxdi", "cxbx", "cxsi", "cxdi",
+       "bxsi", "bxdi", "sidi",
+       "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == CHAR || t == UCHAR)
+               return CLASSB;
+       if (t == LONGLONG || t == ULONGLONG || t == LONG || t == ULONG)
+               return CLASSC;
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return CLASSD;
+       return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left) { 
+               if (p->n_right->n_op != ASSIGN)
+                       size += argsiz(p->n_right);
+       }
+       if (p->n_op != ASSIGN)
+               size += argsiz(p);
+
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       int o = p->n_op;
+
+       switch (shape) {
+       case SFUNCALL:
+               if (o == STCALL || o == USTCALL)
+                       return SRREG;
+               break;
+       case SPCON:
+               if (o != ICON || p->n_name[0] ||
+                   p->n_lval < 0 || p->n_lval > 0x7fffffff)
+                       break;
+               return SRDIR;
+       case SMIXOR:
+               return tshape(p, SZERO);
+       case SMILWXOR:
+               if (o != ICON || p->n_name[0] ||
+                   p->n_lval == 0 || p->n_lval & 0xffffffff)
+                       break;
+               return SRDIR;
+       case SMIHWXOR:
+               if (o != ICON || p->n_name[0] ||
+                    p->n_lval == 0 || (p->n_lval >> 32) != 0)
+                       break;
+               return SRDIR;
+       case STWO:
+               if (o == ICON && p->n_name[0] == 0 && p->n_lval == 2)
+                       return SRDIR;
+               break;
+       case SMTWO:
+               if (o == ICON && p->n_name[0] == 0 && p->n_lval == -2)
+                       return SRDIR;
+               break;
+       }
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       struct interpass *ip2;
+       int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
+       NODE *in = 0, *ut = 0;
+       TWORD t;
+       char *w;
+       int reg;
+       int c, cw;
+       CONSZ v;
+
+       cw = xasmcode(p->n_name);
+       if (cw & (XASMASG|XASMINOUT))
+               ut = p->n_left;
+       if ((cw & XASMASG) == 0)
+               in = p->n_left;
+
+       c = XASMVAL(cw);
+       switch (c) {
+       case 'D': reg = DI; break;
+       case 'S': reg = SI; break;
+       case 'a': reg = AX; break;
+       case 'b': reg = BX; break;
+       case 'c': reg = CX; break;
+       case 'd': reg = DX; break;
+
+       case 't':
+       case 'u':
+               p->n_name = tmpstrdup(p->n_name);
+               w = strchr(p->n_name, XASMVAL(cw));
+               *w = 'r'; /* now reg */
+               return 1;
+
+       case 'A': reg = AXDX; break;
+       case 'q': {
+               /* Set edges in MYSETXARG */
+               if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
+                       return 1;
+               t = p->n_left->n_type;
+               if (in && ut)
+                       in = tcopy(in);
+               p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
+               if (ut) {
+                       ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+                       DLIST_INSERT_AFTER(ip, ip2, qelem);
+               }
+               if (in) {
+                       ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+                       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+               }
+               return 1;
+       }
+
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+               if (p->n_left->n_op != ICON) {
+                       if ((c = XASMVAL1(cw)) != 0) {
+                               p->n_name++;
+                               return 0; /* Try again */
+                       }
+                       uerror("xasm arg not constant");
+               }
+               v = p->n_left->n_lval;
+               if ((c == 'K' && v < -128) ||
+                   (c == 'L' && v != 0xff && v != 0xffff) ||
+                   (c != 'K' && v < 0) ||
+                   (v > Cmax[c-'I']))
+                       uerror("xasm val out of range");
+               p->n_name = "i";
+               return 1;
+
+       default:
+               return 0;
+       }
+       /* If there are requested either memory or register, delete memory */
+       w = p->n_name = tmpstrdup(p->n_name);
+       if (*w == '=')
+               w++;
+       *w++ = 'r';
+       *w = 0;
+
+       t = p->n_left->n_type;
+       if (reg == AXDX) {
+               ;
+       } else {
+               if (t == CHAR || t == UCHAR) {
+                       reg = reg * 2 + 8;
+               }
+       }
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
+               reg += 037;
+       }
+
+       if (in && ut)
+               in = tcopy(in);
+       p->n_left = mklnode(REG, 0, reg, t);
+       if (ut) {
+               ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+               DLIST_INSERT_AFTER(ip, ip2, qelem);
+       }
+       if (in) {
+               ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+               DLIST_INSERT_BEFORE(ip, ip2, qelem);
+       }
+       return 1;
+}
+
+void
+targarg(char *w, void *arg)
+{
+       NODE **ary = arg;
+       NODE *p, *q;
+
+       if (ary[(int)w[1]-'0'] == 0)
+               p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */
+       else
+               p = ary[(int)w[1]-'0']->n_left;
+       if (optype(p->n_op) != LTYPE)
+               comperr("bad xarg op %d", p->n_op);
+       q = tcopy(p);
+       if (q->n_op == REG) {
+               if (*w == 'k') {
+                       q->n_type = INT;
+               } else if (*w != 'w') {
+                       if (q->n_type > UCHAR) {
+                               regno(q) = regno(q)*2+8;
+                               if (*w == 'h')
+                                       regno(q)++;
+                       }
+                       q->n_type = INT;
+               } else
+                       q->n_type = SHORT;
+       }
+       adrput(stdout, q);
+       tfree(q);
+}
+
+/*
+ * target-specific conversion of numeric arguments.
+ */
+int
+numconv(void *ip, void *p1, void *q1)
+{
+       NODE *p = p1, *q = q1;
+       int cw = xasmcode(q->n_name);
+
+       switch (XASMVAL(cw)) {
+       case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+               p->n_name = tmpcalloc(2);
+               p->n_name[0] = (char)XASMVAL(cw);
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static struct {
+       char *name; int num;
+} xcr[] = {
+       { "ax", AX },
+       { "bx", BX },
+       { "cx", CX },
+       { "dx", DX },
+       { "si", SI },
+       { "di", DI },
+       { NULL, 0 },
+};
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+int xasmconstregs(char *s)
+{
+       int i;
+
+       if (strncmp(s, "st", 2) == 0) {
+               int off =0;
+               if (s[2] == '(' && s[4] == ')')
+                       off = s[3] - '0';
+               return SIDI + 1 + off;
+       }
+
+       for (i = 0; xcr[i].name; i++)
+               if (strcmp(xcr[i].name, s) == 0)
+                       return xcr[i].num;
+       return -1;
+}
+
diff --git a/lang/pcc/pcc/arch/i86/macdefs.h b/lang/pcc/pcc/arch/i86/macdefs.h
new file mode 100644 (file)
index 0000000..0574b15
--- /dev/null
@@ -0,0 +1,334 @@
+/*     $Id: macdefs.h,v 1.7 2016/03/05 15:53:04 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT                64      /* # bits above fp where arguments start */
+#define AUTOINIT       0       /* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         8
+#define SZINT          16
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      96
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64      /* Doesn't work usefully yet */
+#define SZPOINT(t)     16      /* FIXME: 32 for large model work */
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         8
+#define ALINT          16
+#define ALFLOAT                32
+#define ALDOUBLE       32
+#define ALLDOUBLE      32
+#define ALLONG         16
+#define ALLONGLONG     16
+#define ALSHORT                16
+#define ALPOINT                16
+#undef ALSTRUCT                /* Not defined if ELF ABI */
+#define ALSTACK                16 
+#define        ALMAX           128     /* not yet supported type */
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         MIN_SHORT
+#define        MAX_INT         MAX_SHORT
+#define        MAX_UNSIGNED    MAX_USHORT
+#define        MIN_LONG        (-0x7fffffff-1)
+#define        MAX_LONG        0x7fffffff
+#define        MAX_ULONG       0xffffffff
+#define        MIN_LONGLONG    MIN_LONG
+#define        MAX_LONGLONG    MAX_LONG
+#define        MAX_ULONGLONG   MAX_ULONG
+
+/* Default char is signed */
+#undef CHAR_UNSIGNED
+#define        BOOL_TYPE       UCHAR   /* what used to store _Bool */
+#undef UNALIGNED_ACCESS
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#define LABFMT "L%d"           /* format for printing labels */
+#define        STABLBL "LL%d"          /* format for stab (debugging) labels */
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define        AUTOREG BP
+#define        ARGREG  BP
+#define ARGOFFSET 4
+#endif
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_LE
+
+#define FINDMOPS       /* i86 has instructions that modifies memory */
+#define        CC_DIV_0        /* division by zero is safe in the compiler */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)  gencall(a,b)
+
+/* FIXME: float sizes wrong at this point ? */
+#define        szty(t) (((t) == DOUBLE || (t) == FLOAT || \
+       (t) == LONG || t == ULONG || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1)
+
+/*
+ * The x86 has a bunch of register classes, most of them interfering
+ * with each other.  All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ * Class membership and overlaps are defined in the macros RSTATUS
+ * and ROVERLAP below.
+ *
+ * The classes used on x86 are:
+ *     A - short and int regs
+ *     B - char regs
+ *     C - long and longlong regs
+ *     D - floating point
+ */
+#define        AX      000     /* Scratch and return register */
+#define        DX      001     /* Scratch and secondary return register */
+#define        CX      002     /* Scratch (and shift count) register */
+#define        BX      003     /* GDT pointer or callee-saved temporary register */
+#define        SI      004     /* Callee-saved temporary register */
+#define        DI      005     /* Callee-saved temporary register */
+#define        BP      006     /* Frame pointer */
+#define        SP      007     /* Stack pointer */
+
+#define        AL      010
+#define        AH      011
+#define        DL      012
+#define        DH      013
+#define        CL      014
+#define        CH      015
+#define        BL      016
+#define        BH      017
+
+#define        AXDX    020
+#define        AXCX    021
+#define        AXBX    022
+#define        AXSI    023
+#define        AXDI    024
+#define        DXCX    025
+#define        DXBX    026
+#define        DXSI    027
+#define        DXDI    030
+#define        CXBX    031
+#define        CXSI    032
+#define        CXDI    033
+#define        BXSI    034
+#define        BXDI    035
+#define        SIDI    036
+
+/* The 8 math registers in class D lacks names */
+
+#define        MAXREGS 047     /* 39 registers */
+
+#define        RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, 0, 0,                             \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,         \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,                \
+       SDREG, SDREG, SDREG, SDREG,  SDREG, SDREG, SDREG, SDREG,
+
+#define        ROVERLAP \
+       /* 8 basic registers */\
+       { AL, AH, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\
+       { DL, DH, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\
+       { CL, CH, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\
+       { BL, BH, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\
+       { AXSI, DXSI, CXSI, BXSI, SIDI, -1 },\
+       { AXDI, DXDI, CXDI, BXDI, SIDI, -1 },\
+       { -1 },\
+       { -1 },\
+\
+       /* 8 char registers */\
+       { AX, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\
+       { AX, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\
+       { DX, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\
+       { DX, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\
+       { CX, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\
+       { CX, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\
+       { BX, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\
+       { BX, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\
+\
+       /* 15 long emulating registers */\
+       { AX, AL, AH, DX, DL, DH, AXCX, AXBX, AXSI,     /* axdx */\
+         AXDI, DXCX, DXBX, DXSI, DXDI, -1, },\
+       { AX, AL, AH, CX, CL, CH, AXDX, AXBX, AXSI,     /* axcx */\
+         AXDI, DXCX, CXBX, CXSI, CXDI, -1 },\
+       { AX, AL, AH, BX, BL, BH, AXDX, AXCX, AXSI,     /* axbx */\
+         AXDI, DXBX, CXBX, BXSI, BXDI, -1 },\
+       { AX, AL, AH, SI, AXDX, AXCX, AXBX, AXDI,       /* axsi */\
+         DXSI, CXSI, BXSI, SIDI, -1 },\
+       { AX, AL, AH, DI, AXDX, AXCX, AXBX, AXSI,       /* axdi */\
+         DXDI, CXDI, BXDI, SIDI, -1 },\
+       { DX, DL, DH, CX, CL, CH, AXDX, AXCX, DXBX,     /* dxcx */\
+         DXSI, DXDI, CXBX, CXSI, CXDI, -1 },\
+       { DX, DL, DH, BX, BL, BH, AXDX, DXCX, DXSI,     /* dxbx */\
+         DXDI, AXBX, CXBX, BXSI, BXDI, -1 },\
+       { DX, DL, DH, SI, AXDX, DXCX, DXBX, DXDI,       /* dxsi */\
+         AXSI, CXSI, BXSI, SIDI, -1 },\
+       { DX, DL, DH, DI, AXDX, DXCX, DXBX, DXSI,       /* dxdi */\
+         AXDI, CXDI, BXDI, SIDI, -1 },\
+       { CX, CL, CH, BX, BL, BH, AXCX, DXCX, CXSI,     /* cxbx */\
+         CXDI, AXBX, DXBX, BXSI, BXDI, -1 },\
+       { CX, CL, CH, SI, AXCX, DXCX, CXBX, CXDI,       /* cxsi */\
+         AXSI, DXSI, BXSI, SIDI, -1 },\
+       { CX, CL, CH, DI, AXCX, DXCX, CXBX, CXSI,       /* cxdi */\
+         AXDI, DXDI, BXDI, SIDI, -1 },\
+       { BX, BL, BH, SI, AXBX, DXBX, CXBX, BXDI,       /* bxsi */\
+         AXSI, DXSI, CXSI, SIDI, -1 },\
+       { BX, BL, BH, DI, AXBX, DXBX, CXBX, BXSI,       /* bxdi */\
+         AXDI, DXDI, CXDI, SIDI, -1 },\
+       { SI, DI, AXSI, DXSI, CXSI, BXSI,               /* sidi */\
+         AXDI, DXDI, CXDI, BXDI, -1 },\
+\
+       /* The fp registers do not overlap with anything */\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },
+
+
+/* Return a register class based on the type of the node */
+/* FIXME: <= UCHAR includes long ?? check */
+#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \
+                 (p->n_type == LONG || p->n_type == ULONG || p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \
+                 (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG)))
+
+#define        NUMCLASS        4       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define        GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD)
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define        ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 6)      /* A1 */
+#define ENCRA2(x)      ((x) << 12)     /* A2 */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+/* XXX - return char in al? */
+#define        RETREG(x)       (x == CHAR || x == UCHAR ? AL : \
+                        x == LONG || x == ULONG || x == LONGLONG || x == ULONGLONG ? AXDX : \
+                        x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : AX)
+
+#if 0
+#define R2REGS 1       /* permit double indexing */
+#endif
+
+/* XXX - to die */
+#define FPREG  BP      /* frame pointer */
+#define STKREG SP      /* stack pointer */
+
+#define        SHSTR           (MAXSPECIAL+1)  /* short struct */
+#define        SFUNCALL        (MAXSPECIAL+2)  /* struct assign after function call */
+#define        SPCON           (MAXSPECIAL+3)  /* positive nonnamed constant */
+
+/*
+ * Specials that indicate the applicability of machine idioms.
+ */
+#define SMIXOR         (MAXSPECIAL+4)
+#define SMILWXOR       (MAXSPECIAL+5)
+#define SMIHWXOR       (MAXSPECIAL+6)
+#define        STWO            (MAXSPECIAL+7)  /* exactly two */
+#define        SMTWO           (MAXSPECIAL+8)  /* exactly minus two */
+
+/*
+ * i86-specific symbol table flags.
+ */
+#define        SSECTION        SLOCAL1
+#define SSTDCALL       SLOCAL2 
+#define SDLLINDIRECT   SLOCAL3
+
+/*
+ * i86-specific interpass stuff.
+ */
+
+#define TARGET_IPP_MEMBERS                     \
+       int ipp_argstacksize;
+
+#define        HAVE_WEAKREF
+#define        TARGET_FLT_EVAL_METHOD  2       /* all as long double */
+
+/*
+ * Extended assembler macros.
+ */
+void targarg(char *w, void *arg);
+#define        XASM_TARGARG(w, ary)    \
+       (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \
+       w++, targarg(w, ary), 1 : 0)
+int numconv(void *ip, void *p, void *q);
+#define        XASM_NUMCONV(ip, p, q)  numconv(ip, p, q)
+int xasmconstregs(char *);
+#define        XASMCONSTREGS(x) xasmconstregs(x)
+#define        MYSETXARG if (XASMVAL(cw) == 'q') {     \
+       c = 'r'; addalledges(&ablock[SI]); addalledges(&ablock[DI]); }
+
+/* target specific attributes */
+#define        ATTR_MI_TARGET  ATTR_I86_FPPOP
diff --git a/lang/pcc/pcc/arch/i86/order.c b/lang/pcc/pcc/arch/i86/order.c
new file mode 100644 (file)
index 0000000..e04bd0d
--- /dev/null
@@ -0,0 +1,334 @@
+/*     $Id: order.c,v 1.3 2014/12/27 21:18:19 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *r;
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+       r = p->n_right;
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( r->n_op == ICON ){
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+               if (r->n_op == LS && r->n_right->n_op == ICON &&
+                   r->n_right->n_lval == 2 && p->n_op == PLUS) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       if (isreg(r->n_left) == 0)
+                               (void)geninsn(r->n_left, INAREG);
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+       NODE *p, *r;
+
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+
+       p = q->n_left;
+       if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
+           r->n_right->n_op == ICON && r->n_right->n_lval == 2 &&
+           p->n_left->n_op == REG && r->n_left->n_op == REG) {
+               q->n_op = OREG;
+               q->n_lval = 0;
+               q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0);
+               tfree(p);
+       }
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on x86 */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ *
+ * FIXME: review 32bit specials, a lot can go as we use helpers
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case OPLOG:
+               {
+                       static struct rspecial s[] = { { NEVER, AX }, { 0 } };
+                       return s;
+               }
+
+       case STASG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, DI },
+                               { NRIGHT, SI }, { NOLEFT, SI },
+                               { NOLEFT, CX }, { NORIGHT, CX },
+                               { NEVER, CX }, { 0 } };
+                       return s;
+               }
+
+       case STARG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, DI }, { NEVER, CX },
+                               { NLEFT, SI }, { 0 } };
+                       return s;
+               }
+
+       case SCONV:
+               /* Force signed conversions into al/ax to use cbw */
+               if ((q->ltype & TCHAR) && 
+                   q->rtype == (TINT|TUNSIGNED)) {
+                       static struct rspecial s[] = { 
+                               { NLEFT, AL }, { NRES, AX },
+                               { NEVER, AX }, { NEVER, AH}, {NEVER, AL },
+                               { 0 } };
+                       return s;
+               }
+               /* FIXME: do we need this rule with and based moves ? */
+               /* Force signed unconversions to avoid si and di */
+               if ((q->ltype & TUCHAR) && 
+                   q->rtype == (TINT|TUNSIGNED)) {
+                       static struct rspecial s[] = { 
+                               { NEVER, SI }, { NEVER, DI },
+                               { 0 } };
+                       return s;
+               } else if ((q->ltype & (TINT|TUNSIGNED)) && 
+                   q->rtype == (TCHAR|TUCHAR)) {
+                       static struct rspecial s[] = { 
+                               { NOLEFT, SI }, { NOLEFT, DI }, { 0 } };
+                       return s;
+                /* Need to be able to use cwd */
+               } else if ((q->ltype & (TINT|TSHORT)) &&
+                   q->rtype == (TLONG|TULONG)) {
+                       static struct rspecial s[] = {
+                               { NLEFT, AX }, { NRES, AXDX },
+                               { NEVER, AX }, { NEVER, DX }, 
+                               { 0 } };
+                       return s;
+               /* Need to be use cbw cwd */
+               } else if (q->ltype == TCHAR &&
+                   q->rtype == (TLONG|TULONG)) {
+                       static struct rspecial s[] = {
+                               { NRES, AXDX }, { NLEFT, AL },
+                               { NEVER, AX }, { NEVER, DX },
+                               { NEVER, AH }, { NEVER, AL },
+                               { 0 } };
+                       return s;
+               }
+               break;
+       case DIV:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AL }, { NEVER, AH },
+                               { NLEFT, AL }, { NRES, AL },
+                               { NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+                               return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AX }, { NEVER, DX },
+                               { NLEFT, AX }, { NRES, AX },
+                               { NORIGHT, DX }, { NORIGHT, AX }, { 0 } };
+                       return s;
+               }
+/* using helpers */            
+                else if (q->lshape & SCREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AX }, { NEVER, DX },
+                               { NEVER, CX }, { NRES, AXDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case MOD:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AL }, { NEVER, AH },
+                               { NLEFT, AL }, { NRES, AH },
+                               { NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AX }, { NEVER, DX },
+                               { NLEFT, AX }, { NRES, DX },
+                               { NORIGHT, DX }, { NORIGHT, AX }, { 0 } };
+                       return s;
+               } else if (q->lshape & SCREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AX }, { NEVER, DX },
+                               { NEVER, CX }, { NRES, AXDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case MUL:
+               if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AX }, { NEVER, DX },
+                               { NLEFT, AX }, { NRES, AX },
+                               { NORIGHT, DX }, {NORIGHT, AX },
+                               { 0 } };
+                       return s;
+               }
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AL }, { NEVER, AH },
+                               { NLEFT, AL }, { NRES, AL }, { 0 } };
+                       return s;
+               } else if (q->lshape & SCREG) {
+                       static struct rspecial s[] = {
+                               { NEVER, AX }, { NEVER, DX },
+                               { NEVER, CX }, { NRES, AXDX }, { 0 } };
+                       return s;
+               }
+               break;
+       case LS:
+       case RS:
+               if (q->visit & (INAREG|INBREG)) {
+                       static struct rspecial s[] = {
+                               { NRIGHT, CL }, { NOLEFT, CX }, { 0 } };
+                       return s;
+               } else if (q->visit & INCREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, AXDX }, { NRIGHT, CL },
+                               { NRES, AXDX }, { 0 } };
+                       return s;
+               }
+               break;
+
+       default:
+               break;
+       }
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on x86 */
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[] = { AX, BX, -1 };
+       int off = 1;
+       return kflag ? &r[off] : &r[2];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/i86/table.c b/lang/pcc/pcc/arch/i86/table.c
new file mode 100644 (file)
index 0000000..3a6f489
--- /dev/null
@@ -0,0 +1,1564 @@
+/*     $Id: table.c,v 1.5 2014/12/27 21:18:19 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * Copyright (c) 2014 Alan Cox (alan@lxorguk.ukuu.org.uk).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+/*
+ * TODO
+ *  -  clean up TLL usage so we are ready for 64bit longlong (T32 and T64?)
+ *  -  Clean up all the SHINT SHCH etc oddities for clarity
+ *  -  Better optimisation of constant multiply/divide etc on 8086
+ *  -  some how lose the final bogus sp adjust we generate
+ *  -  write helper lib for long and longlong ops
+ *  -  add an E class and virtual 4 register longlong model
+ *  -   bcc fastcall format
+ *
+ *  -  How to do configurable code-gen
+ *     For 80186 we want to use the better shifts, push constant, mul/div
+ *     features and enter/leave
+ *     For 80286 it's not clear we need to do anything for real mode. However
+ *     for large data/huge models protected mode means minimising ds/es
+ *     reloads with the same data
+ *     With 80386 there is lots more - but who wants 80386/16bit optimised
+ *     code !
+ *
+ *  -  FPU has not been tackled. FPU/FPU should be fine (barring the odd
+ *     gnu style instruction forms), but FPU/other is quite different
+ *     because the 4 byte conversions are now long not int and two register
+ *     while 8 byte longlong ones are going to need some gymnastics once
+ *     we support the virtual 64bit registers
+ *
+ *  -  FPU/noFPU option. Assuming FPU present on 8086 is a bit obnoxious
+ *     as a default. Need to be able to generate entirely soft-float calls.
+ *
+ *  -   We can't currently do various conversions we'd like to have, notably
+ *     things like  "and ax, $ff"  to convert AL into AX from uchar to uint
+ *     (that needs core changes and also allocator changes to try and avoid
+ *     high bits being occupied by other users)
+ *
+ *  -  Shifts should be optimised for 8/16/24/32 cases
+ *
+ *  -  No attempt is made to deal with larger models than tiny
+ *
+ *     small mode should work (just keep constant data in data segments)
+ *
+ *     large code/small data should be fine-ish. Really that implies 32bit
+ *     void * but for most uses you want 32bit only to be function pointers
+ *     even if its not to spec. Function entry/exit needs to allow for the
+ *     extra 2 bytes, call becomes call far, call ptr becomes a bit trickier
+ *     but not a lot. Not that ld86 can link large model yet!
+ *
+ *     large data is much harder because an address is 32bit, half of which
+ *     needs to keep getting stuck into a segment register. However we often
+ *     (usually) work with multiple pointers to the same object. Any given
+ *     object has a single segment so we will badly need optimisations to
+ *     "share" segment data and avoid lots of duplicate register uses and
+ *     mov es, foo statements.
+ *
+ *     huge model makes all pointers 32bit and all objects 32bit sized. That
+ *     probably makes the sharing es issue go away somewhat, but raises the
+ *     ugly problems of pointer normalisation (00:10 is the same as 01:00
+ *     which b*ggers up comparisons royally) and also protected mode where
+ *     your segment jump as you go over 64K boundaries is different. On the
+ *     bright side huge model performance will suck whatever the compiler
+ *     does.
+ *
+ */
+
+/* 64bit values */
+# define T64 TLONGLONG|TULONGLONG
+/* 32bit values */
+# define T32 TLONG|TULONG
+/* 16bit values */
+# define T16 TINT|TUNSIGNED
+/* 16bit values including pointers */
+# define TP16 TINT|TUNSIGNED|TPOINT
+/* 8bit values */
+# define T8  TCHAR|TUCHAR
+
+#define         SHINT  SAREG   /* short and int */
+#define         ININT  INAREG
+#define         SHCH   SBREG   /* shape for char */
+#define         INCH   INBREG
+#define         SHLL   SCREG   /* shape for long long FIXME */
+#define         INLL   INCREG
+#define         SHL    SCREG   /* shape for long*/
+#define         INL    INCREG
+#define         SHFL   SDREG   /* shape for float/double */
+#define         INFL   INDREG  /* shape for float/double */
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  T16|TPOINT,
+       SAREG,  T16|TPOINT,
+               0,      RLEFT,
+               "", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV,       INCH,
+               SHCH,                   T8,
+               SHCH,                   T8,
+               0,                      RLEFT,
+               "", },
+
+/* convert pointers to int. */
+{ SCONV,       ININT,
+               SHINT,                  TPOINT|T16,
+               SANY,                   T16,
+               0,                      RLEFT,
+               "", },
+
+/* convert (u)long to (u)long. */
+{ SCONV,       INL,
+               SHL,                    T32,
+               SHL,                    T32,
+               0,                      RLEFT,
+               "", },
+
+/* convert (u)long and (u)longlong to (u)longlong. */
+{ SCONV,       INLL,
+               SHLL,                   T64,
+               SHLL,                   T64,
+               0,                      RLEFT,
+               "", },
+
+/* convert between float/double/long double. */
+{ SCONV,       INFL,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RLEFT,
+               "ZI", },
+
+/* convert pointers to pointers. */
+{ SCONV,       ININT,
+               SHINT,                  TPOINT,
+               SANY,                   TPOINT,
+               0,                      RLEFT,
+               "", },
+
+/* char to something */
+
+/* convert char to 16bit types. */
+
+/* 8086: Only as op on AL,AX */
+{ SCONV,       ININT,
+               SBREG,                  TCHAR,
+               SAREG,                  T16,
+               NSPECIAL|NAREG|NASL,    RESC1,
+               "       cbw\n", },
+
+/* convert unsigned char to 16bit types.
+   We can do this one with any register */
+{ SCONV,       ININT,
+               SHCH|SOREG|SNAME,       TUCHAR,
+               SAREG,                  T16,
+               NSPECIAL|NAREG,         RESC1,
+               "ZT", },
+
+/* convert char to (u)long
+   8086 can only do cbw/cwd on AX and AX:DX pair */
+{ SCONV,       INL,
+               SHCH,                   TCHAR,
+               SCREG,                  T32,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "; using AL\n   cbw\n   cwd\n", },
+
+/* convert unsigned char to (u)long
+   we can do this with any register */
+{ SCONV,       INL,
+               SHCH|SOREG|SNAME,       TUCHAR,
+               SANY,                   T32,
+               NCREG|NCSL,             RESC1,
+               "ZT     xor U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+/* FIXME : need NSPECIAL to force into AL 
+       check AX:DX right way around ! */
+{ SCONV,       INFL,
+               SHCH|SOREG|SNAME,       TCHAR,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG,       RESC2,
+               "       cbw\n   cwd\n   push ax\n       push dx\n"
+               "       fildl [sp]\n    add sp, #4\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+/* FIXME : needs to use ZT to get sizes right, need a register
+   from somewhere to put 0 on the stack for the high bits */
+{ SCONV,       INFL,
+               SHCH|SOREG|SNAME,       TUCHAR,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG,       RESC2,
+               "       mov A1 AL\n     and A1, #0xff\n push A1\npush #0\n"
+               "       fildl [sp]\n    add sp,#4\n", },
+
+/* 16bit to something */
+
+/* convert 16bit to 16bit. */
+{ SCONV,       INAREG,
+               SAREG,                  T16,
+               SAREG,                  T16,
+               0,                      RLEFT,
+               "", },
+
+/* convert 16bit (in memory) to char */
+/* NOTE: uses new 'ZP' type for 'untyped right' */
+{ SCONV,       INCH,
+               SNAME|SOREG,            TP16,
+               SHCH,                   T8,
+               NBREG|NBSL,             RESC1,
+               "       mov A1,ZP AL\n", },
+
+/* convert 16bit (in reg) to char. Done as a special but basically a mov */
+{ SCONV,       INCH,
+               SAREG|SNAME|SOREG,      TP16,
+               SHCH,                   T8,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZM", },
+
+/* convert short/int to (u)long
+   This must go via AX so we can use cwd */
+{ SCONV,       INL,
+               SAREG,                  TINT,
+               SHL,                    T32,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "       mov A1, AL\n    cwd\n", },
+
+/* convert unsigned short/int to (u)long
+   Any pair will do. Note currently the compiler can't optimise
+   out the reg->reg move involved */
+{ SCONV,       INLL,
+               SAREG|SOREG|SNAME,      TUNSIGNED|TPOINT,
+               SHL,                    T32,
+               NCREG|NCSL,             RESC1,
+               "       mov A1,AL\n     xor U1,U1\n", },
+
+/* convert short/int (in memory) to float/double */
+{ SCONV,       INFL,
+               SOREG|SNAME,            TINT,
+               SDREG,                  TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,                  RESC1,
+               "       fild AL\n", },
+
+/* convert short/int (in register) to float/double */
+{ SCONV,       INFL,
+               SAREG,                  TINT,
+               SDREG,                  TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,            RESC1,
+               "       push AL\n       fild [sp]\n"
+               "       inc sp\n        inc sp\n", },
+
+/* convert unsigned short/int/ptr to double XXX - use NTEMP */
+/* FIXME: need to force this via AX so we can cwd, fix stack setup to
+   push both ax.dx*/
+{ SCONV,       INFL,
+               SAREG|SOREG|SNAME,      TUNSIGNED|TPOINT,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG|NTEMP, RESC2,
+               "       cwd\n           push ax\n"
+               "       fild [sp]\n     inc sp\n"
+               "       inc sp\n", },
+
+/* long to something */
+
+/* convert (u)long to (u)char (mem->reg) */
+{ SCONV,       INCH,
+               SOREG|SNAME,            T32,
+               SANY,                   T8,
+               NBREG|NBSL,             RESC1,
+               "       mov A1, AL\n", },
+
+/* convert (u)long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV,       INCH,
+               SHL,                    T32,
+               SANY,                   T8,
+               NBREG|NBSL|NTEMP,       RESC1,
+               "ZS", },
+
+/* convert (u)long to (u)short (mem->reg) */
+{ SCONV,       INAREG,
+               SOREG|SNAME,            T32,
+               SAREG,                  TP16,
+               NAREG|NASL,             RESC1,
+               "       mov A1,AL\n", },
+
+/* convert (u)long to 16bit (reg->reg, hopefully nothing) */
+{ SCONV,       INAREG,
+               SHL|SOREG|SNAME,        T32,
+               SAREG,                  T16,
+               NAREG|NASL|NTEMP,       RESC1,
+               "ZS", },
+
+/* FIXME: float stuff is all TODO */
+
+/* convert long long (in memory) to floating */
+{ SCONV,       INFL,
+               SOREG|SNAME,            TLONGLONG,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,                  RESC1,
+               "       fild AL\n", },
+
+/* convert long (in register) to floating */
+{ SCONV,       INFL,
+               SHL,                    TLONGLONG,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,            RESC1,
+               "       push UL\n       push AL\n"
+               "       fild [sp]\n     add sp, #8\n", },
+
+/* convert unsigned long to floating */
+{ SCONV,       INFL,
+               SCREG,                  TULONGLONG,
+               SDREG,                  TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,                  RESC1,
+               "ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV,       INCH,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHCH,                   T16|T8,
+               NBREG,                  RESC1,
+               "       sub sp,#4\n     fistpl [sp]\n   pop     A1\n    pop U1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV,       INCH,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHCH,                   T16|T8,
+               NCREG,                  RESC1,
+               "       sub sp,#4\n     fistpl (%sp)\n  pop A1\n        inc sp\n        inc sp\n", },
+#endif
+
+/* convert float/double to long XXX should use NTEMP here */
+{ SCONV,       INAREG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SAREG,  TLONG,
+               NAREG,  RESC1,
+               "       sub sp, #12\n"
+               "       fstcw sp\n"
+               "       fstcw 4[sp]\n"
+               "       mov byte ptr 1[sp], #12\n"
+               "       fldcw sp\n"
+               "       fistp 8[sp]\n"
+               "       movl A1, 8(p)\n"
+               "       fldcw 4[sp]\n"
+               "       add sp, #4\n", },
+
+/* convert float/double to unsigned long. XXX should use NTEMP here */
+{ SCONV,       INAREG,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SAREG,                  TULONG,
+               NAREG,                  RESC1,
+               "       sub sp, #16\n"
+               "       fnstcw [sp]\n"
+               "       fnstcw 4[sp]\n"
+               "       mov byte ptr 1[sp], #12\n"
+               "       fldcw [sp[\n"
+               "       fistpq 8[sp]\n"
+               "       mov word ptr 8[sp],A1\n"
+               "       mov word ptr 10[sp],U1\n"
+               "       fldcw 4[sp]\n"
+               "       add sp, #16\n", },
+
+/* convert float/double (in register) to long long */
+{ SCONV,       INLL,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHLL,                   TLONGLONG,
+               NCREG,                  RESC1,
+               "       sub sp, #16\n"
+               "       fnstcw [sp]\n"
+               "       fnstcw [sp]\n"
+               "       mov byte ptr 1[sp], #12\n"
+               "       fldcw [sp]\n"
+               "       fistpq 8[sp]\n"
+               "       movl 8[sp],A1\n"
+               "       movl 10[sp],U1\n"
+               /* need to put 12/14 somewhere FIXME */
+               "       fldcw 4[sp]\n"
+               "       add sp, #16\n", },
+
+/* convert float/double (in register) to unsigned long long */
+{ SCONV,       INLL,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHLL,                   TULONGLONG,
+               NCREG,                  RESC1,
+               "       sub sp, #16\n"
+               "       fnstcw [sp]\n"
+               "       fnstcw 4[sp]\n"
+               "       mov byte ptr 1[sp], #15\n"      /* 64-bit prec */
+               "       fldcw [sp]\n"
+               "       movl $0x5f000000, 8(%sp)\n"     /* (float)(1<<63) */
+               "       fsubs 8[sp]\n"  /* keep in range of fistpq */
+               "       fistpq 8[sp]\n"
+               "       xor byte ptr 15[sp], #0x80\n"   /* addq $1>>63 to 8(%sp) */
+               "       movl A1, 8[sp]\n"
+               "       movl U1, 10[sp]\n"
+               "       fldcw 4[sp]\n"
+               "       add sp, #16\n", },
+
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ UCALL,       FOREFF,
+               SCON,                   TANY,
+               SANY,                   TANY,
+               0,      0,
+               "       call CL\nZC", },
+
+{ CALL,                FOREFF,
+               SCON,                   TANY,
+               SANY,                   TANY,
+               0,      0,
+               "       call CL\nZC", },
+
+//{ UCALL,     FOREFF,
+//     SCON,   TANY,
+//     SAREG,  TP16,
+//             0,      0,
+//             "       call CL\nZC", },
+
+{ CALL,        INAREG,
+               SCON,                   TANY,
+               SAREG,                  TP16,
+               NAREG|NASL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INAREG,
+               SCON,                   TANY,
+               SAREG,                  TP16,
+               NAREG|NASL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,        INBREG,
+               SCON,                   TANY,
+               SBREG,                  T8,
+               NBREG,                  RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INBREG,
+               SCON,                   TANY,
+               SBREG,                  T8,
+               NBREG,                  RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,                INCREG,
+               SCON,                   TANY,
+               SCREG,                  TANY,
+               NCREG|NCSL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INCREG,
+               SCON,                   TANY,
+               SCREG,                  TANY,
+               NCREG|NCSL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,        INDREG,
+               SCON,                   TANY,
+               SDREG,                  TANY,
+               NDREG|NDSL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INDREG,
+               SCON,                   TANY,
+               SDREG,                  TANY,
+               NDREG|NDSL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,                FOREFF,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ UCALL,       FOREFF,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ CALL,                INAREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NAREG|NASL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INAREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NAREG|NASL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INBREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NBREG|NBSL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INBREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NBREG|NBSL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INCREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NCREG|NCSL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INCREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NCREG|NCSL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INDREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NDREG|NDSL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INDREG,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               NDREG|NDSL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ STCALL,      FOREFF,
+               SCON,                   TANY,
+               SANY,                   TANY,
+               NAREG|NASL,     0,
+               "       call CL\nZC", },
+
+{ STCALL,      INAREG,
+               SCON,                   TANY,
+               SANY,                   TANY,
+               NAREG|NASL,             RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ STCALL,      INAREG,
+               SNAME|SAREG,            TANY,
+               SANY,                   TANY,
+               NAREG|NASL,             RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ *
+ * 8 and 16bit we do directly, 32bit is a mix of helpers and
+ * direct operations. 64bit TODO, FPU lives in it's own little
+ * world.
+ */
+{ PLUS,                INL|FOREFF,
+               SHL,                    T32,
+               SHL|SNAME|SOREG,        T32,
+               0,                      RLEFT,
+               "       add AL,AR\n     adc UL,UR\n", },
+
+{ PLUS,                INL|FOREFF,
+               SHL|SNAME|SOREG,        T32,
+               SHL|SCON,               T32,
+               0,                      RLEFT,
+               "       add AL,AR\n     adc UL,UR\n", },
+
+/* Special treatment for long  XXX - fix commutative check */
+{ PLUS,                INL|FOREFF,
+               SHL|SNAME|SOREG,        T32,
+               SHL,                    T32,
+               0,                      RRIGHT,
+               "       add AL,AR\n     adc UL,UR\n", },
+
+{ PLUS,                INFL,
+               SHFL,                   TDOUBLE,
+               SNAME|SOREG,            TDOUBLE,
+               0,                      RLEFT,
+               "       faddl AR\n", },
+
+{ PLUS,                INFL|FOREFF,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RLEFT,
+               "       faddp\n", },
+
+{ PLUS,                INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TP16,
+               SONE,                   TANY,
+               0,                      RLEFT,
+               "       inc AL\n", },
+
+{ PLUS,                INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TP16,
+               STWO,                   TANY,
+               0,                      RLEFT,
+               "       inc AL\n        inc AL\n", },
+
+{ PLUS,                INCH|FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               SONE,                   TANY,
+               0,                      RLEFT,
+               "       inc AL\n", },
+
+{ PLUS,                INCH|FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               STWO,                   TANY,
+               0,                      RLEFT,
+               "       inc AL\n        inc AL\n", },
+
+{ PLUS,                INAREG,
+               SAREG,                  T16,
+               SAREG,                  T16,
+               NAREG|NASL|NASR,        RESC1,
+               "       lea A1, [AL+AR]\n", },
+
+{ MINUS,       INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TP16,
+               SONE,                   TANY,
+               0,                      RLEFT,
+               "       dec AL\n", },
+
+{ MINUS,       INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TP16,
+               STWO,                   TANY,
+               0,                      RLEFT,
+               "       dec AL\n        dec AL\n", },
+
+{ MINUS,       INCH|FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               SONE,                   TANY,
+               0,                      RLEFT,
+               "       dec AL\n", },
+
+{ MINUS,       INCH|FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               STWO,                   TANY,
+               0,                      RLEFT,
+               "       dec AL\n        decl AL\n", },
+
+/* address as register offset, negative */
+{ MINUS,       INLL|FOREFF,
+               SHL,                    T32,
+               SHL|SNAME|SOREG,        T32,
+               0,                      RLEFT,
+               "       sub AL,AR\n     sbb UL,UR\n", },
+
+{ MINUS,       INL|FOREFF,
+               SHL|SNAME|SOREG,        T32,
+               SHL|SCON,               T32,
+               0,                      RLEFT,
+               "       sub AL,AR\n     sbb UL,UR\n", },
+
+{ MINUS,       INFL,
+               SHFL,                   TDOUBLE,
+               SNAME|SOREG,            TDOUBLE,
+               0,                      RLEFT,
+               "       fsubl AR\n", },
+
+{ MINUS,       INFL|FOREFF,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RLEFT,
+               "       fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+/* m/r |= r */
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+               SHINT|SNAME|SOREG,      TP16,
+               SHINT,                  TP16,
+               0,                      RLEFT|RESCC,
+               "       Ow AL,AR\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+               SHINT,                  T16,
+               SHINT|SNAME|SOREG,      T16,
+               0,                      RLEFT|RESCC,
+               "       Ow AL,AR\n", },
+
+/* m/r |= r */
+{ OPSIMP,      INCH|FOREFF|FORCC,
+               SHCH,                   T8,
+               SHCH|SNAME|SOREG,       T8,
+               0,                      RLEFT|RESCC,
+               "       Ob AL,AR\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INCH|FOREFF|FORCC,
+               SHCH,                   T8,
+               SHCH|SNAME|SOREG,       T8,
+               0,                      RLEFT|RESCC,
+               "       Ob AL,AR\n", },
+
+/* m/r |= const */
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+               SHINT|SNAME|SOREG,      TP16,
+               SCON,                   TANY,
+               0,                      RLEFT|RESCC,
+               "       Ow AL,AR\n", },
+
+{ OPSIMP,      INCH|FOREFF|FORCC,
+               SHCH|SNAME|SOREG,       T8,
+               SCON,                   TANY,
+               0,                      RLEFT|RESCC,
+               "       Ob AL,AR\n", },
+
+/* r |= r/m */
+{ OPSIMP,      INL|FOREFF,
+               SHL,                    T32,
+               SHL|SNAME|SOREG,        T32,
+               0,                      RLEFT,
+               "       Ow AL,AR\n      Ow UL,UR\n", },
+
+/* m/r |= r/const */
+{ OPSIMP,      INL|FOREFF,
+               SHL|SNAME|SOREG,        T32,
+               SHL|SCON,               T32,
+               0,                      RLEFT,
+               "       Ow AL,AR\n      Ow UL,UR\n", },
+
+/* Try use-reg instructions first */
+{ PLUS,                INAREG,
+               SAREG,                  TP16,
+               SCON,                   TANY,
+               NAREG|NASL,             RESC1,
+               "       lea A1, CR[AL]\n", },
+
+{ MINUS,       INAREG,
+               SAREG,                  TP16,
+               SPCON,                  TANY,
+               NAREG|NASL,             RESC1,
+               "       lea A1, -CR[AL]\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)long left shift is emulated, longlong to do */
+
+/* For 8086 we only have shift by 1 or shift by CL
+
+   We need a way to optimise shifts by 8/16/24/32/etc
+   shifts by 8 16 24 and 32 as moves between registers for
+   the bigger types. (eg >> 16 on a long might be mov dx, ax,
+   xor ax, ax) */
+   
+{ LS,          INCREG,
+               SCREG,                  T32,
+               SHCH,                   T8,
+               0,                      RLEFT,
+               "ZO", },
+
+/* Register 8086 timing is 2 for #1 versus 8 + 4/bin for multiple
+   so a lot of shifts would in fact best be done without using the cl
+   variant, especially including the cost of a) loading cl b) probably
+   having to boot something out of cx in the first place. For memory
+   its 15+EA v 20 + EA + 4/bit, so the other way.
+   
+   8,16,24 should of course be done by loads.. FIXME 
+   
+   Also the compiler keeps generating mov dh, #8, mov cl, dh.. FIXME
+   
+   For 80186 onwards we have shl reg, immediate (other than 1), 186 shift
+   is also much faster */
+
+
+/* r/m <<= const 1*/
+{ LS,          INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      T16,
+               SONE,                   TANY,
+               0,                      RLEFT,
+               "       shl AL,#1\n", },
+
+/* r <<= const 2 */
+{ LS,          INAREG|FOREFF,
+               SAREG,                  T16,
+               STWO,                   TANY,
+               0,                      RLEFT,
+               "       shl AL,#1\n     shl AL,#1\n", },
+
+/* r/m <<= r */
+{ LS,          INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      T16,
+               SHCH,                   T8,
+               NSPECIAL,               RLEFT,
+               "       shl AL,AR\n", },
+
+{ LS,          INCH|FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               SONE,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       sal AL,#1\n", },
+
+{ LS,          INCH|FOREFF,
+               SHCH,                   T8,
+               STWO,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       sal AL,#1\n     sal AL,#1", },
+
+{ LS,          INCH|FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               SHCH,                   T8,
+               NSPECIAL,               RLEFT,
+               "       sal AL,AR\n", },
+
+/* (u)long right shift is emulated. Use a 16bit register so the push
+   comes out sanely */
+{ RS,          INCREG,
+               SCREG,                  T32,
+               SHCH,                   T8,
+               0,                      RLEFT,
+               "ZO", },
+
+{ RS,          INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TINT,
+               SHCH,                   T8,
+               NSPECIAL,               RLEFT,
+               "       sar AL,AR\n", },
+
+{ RS,          INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TINT,
+               SONE,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       sar AL,#1\n", },
+
+{ RS,          INAREG|FOREFF,
+               SAREG,                  TINT,
+               STWO,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       sar AL,#1\n     sar AL,#1", },
+
+{ RS,          INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TUNSIGNED|TPOINT,
+               SHCH,                   T8,
+               NSPECIAL,               RLEFT,
+               "       shr AL,AR\n", },
+
+{ RS,          INAREG|FOREFF,
+               SAREG|SNAME|SOREG,      TUNSIGNED,
+               SONE,                   TANY,
+               0,                      RLEFT,
+               "       shr AL,#1\n", },
+
+{ RS,          INAREG|FOREFF,
+               SAREG,                  TUNSIGNED,
+               STWO,                   TANY,
+               0,                      RLEFT,
+               "       shr AL,#1       shr AL,#1\n", },
+
+{ RS,  INCH|FOREFF,
+               SHCH|SNAME|SOREG,       TCHAR,
+               SHCH,                   T8,
+               NSPECIAL,               RLEFT,
+               "       sar AL,AR\n", },
+
+{ RS,  INCH|FOREFF,
+               SHCH|SNAME|SOREG,       TCHAR,
+               SONE,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       sar AL,#1\n", },
+
+{ RS,  INCH|FOREFF,
+               SHCH|SNAME|SOREG,       TCHAR,
+               STWO,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       sar AL,#1\n     sar AL,#1\n", },
+
+{ RS,  INCH|FOREFF,
+               SHCH|SNAME|SOREG,       TUCHAR,
+               SHCH,                   T8,
+               NSPECIAL,               RLEFT,
+               "       shr AL,AR\n", },
+
+{ RS,          INCH|FOREFF,
+               SHCH|SNAME|SOREG,       TUCHAR,
+               SONE,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       shr AL,#1\n", },
+
+{ RS,          INCH|FOREFF,
+               SHCH|SNAME|SOREG,       TUCHAR,
+               STWO,                   TANY,
+               NSPECIAL,               RLEFT,
+               "       shr AL,#1\n     shr AL,#1\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN,      FORCC|FOREFF|INL,
+               SHL,                    T32,
+               SMIXOR,                 TANY,
+               0,                      RDEST,
+               "       xor AL,AL\n     xor UL,UL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INL,
+               SHL,                    T32,
+               SMILWXOR,               TANY,
+               0,                      RDEST,
+               "       xor AL,AL\n     mov UR,UL\n", },
+
+{ ASSIGN,      FORCC|FOREFF|INL,
+               SHL,                    T32,
+               SMIHWXOR,               TANY,
+               0,                      RDEST,
+               "       mov AL,AR\n     xor UL,UL\n", },
+
+{ ASSIGN,      FOREFF|INL,
+               SHL,                    T32,
+               SCON,                   TANY,
+               0,                      RDEST,
+               "       mov AL,AR\n     mov UL,UR\n", },
+
+{ ASSIGN,      FOREFF,
+               SHL|SNAME|SOREG,        T32,
+               SCON,                   TANY,
+               0,                      0,
+               "       mov AL,AR\n     mov UL,UR\n", },
+
+{ ASSIGN,      FOREFF,
+               SAREG|SNAME|SOREG,      TP16,
+               SCON,                   TANY,
+               0,                      0,
+               "       mov AL, AR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+               SAREG,                  TP16,
+               SCON,                   TANY,
+               0,                      RDEST,
+               "       mov AL, AR\n", },
+
+{ ASSIGN,      FOREFF,
+               SHCH|SNAME|SOREG,       T8,
+               SCON,                   TANY,
+               0,      0,
+               "       mov AL, AR\n", },
+
+{ ASSIGN,      FOREFF|INCH,
+               SHCH,                   T8,
+               SCON,                   TANY,
+               0,                      RDEST,
+               "       mov AL, AR\n", },
+
+{ ASSIGN,      FOREFF|INL,
+               SNAME|SOREG,            T32,
+               SHL,                    T32,
+               0,                      RDEST,
+               "       mov AL,AR\n     mov UL,UR\n", },
+
+{ ASSIGN,      FOREFF|INL,
+               SHL,                    T32,
+               SHL,                    T32,
+               0,                      RDEST,
+               "ZH", },
+
+{ ASSIGN,      FOREFF|INAREG,
+               SAREG|SNAME|SOREG,      TP16,
+               SAREG,                  TP16,
+               0,                      RDEST,
+               "       mov AL,AR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+               SAREG,                  TP16,
+               SAREG|SNAME|SOREG,      TP16,
+               0,                      RDEST,
+               "       mov AL,AR\n", },
+
+{ ASSIGN,      FOREFF|INCH,
+               SHCH|SNAME|SOREG,       T8,
+               SHCH,                   T8|T16,
+               0,                      RDEST,
+               "       mov AL,AR\n", },
+
+{ ASSIGN,      INDREG|FOREFF,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      RDEST,
+               "", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN,      INFL,
+               SNAME|SOREG,            TLDOUBLE,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      RDEST,
+               "       fstpt AL\n      fldt AL\n", }, /* XXX */
+
+{ ASSIGN,      FOREFF,
+               SNAME|SOREG,            TLDOUBLE,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      0,
+               "       fstpt AL\n", },
+
+{ ASSIGN,      INFL,
+               SNAME|SOREG,            TDOUBLE,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      RDEST,
+               "       fstl AL\n", },
+
+{ ASSIGN,      FOREFF,
+               SNAME|SOREG,            TDOUBLE,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      0,
+               "       fstpl AL\n", },
+
+{ ASSIGN,      INFL,
+               SNAME|SOREG,            TFLOAT,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      RDEST,
+               "       fsts AL\n", },
+
+{ ASSIGN,      FOREFF,
+               SNAME|SOREG,            TFLOAT,
+               SHFL,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,                      0,
+               "       fstps AL\n", },
+/* end very important order */
+
+{ ASSIGN,      INFL|FOREFF,
+               SHFL,                   TLDOUBLE,
+               SHFL|SOREG|SNAME,       TLDOUBLE,
+               0,                      RDEST,
+               "       fldt AR\n", },
+
+{ ASSIGN,      INFL|FOREFF,
+               SHFL,                   TDOUBLE,
+               SHFL|SOREG|SNAME,       TDOUBLE,
+               0,                      RDEST,
+               "       fldl AR\n", },
+
+{ ASSIGN,      INFL|FOREFF,
+               SHFL,                   TFLOAT,
+               SHFL|SOREG|SNAME,       TFLOAT,
+               0,                      RDEST,
+               "       flds AR\n", },
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG,       INAREG|FOREFF,
+               SOREG|SNAME|SAREG,      TPTRTO|TSTRUCT,
+               SFUNCALL,               TPTRTO|TSTRUCT,
+               0,                      RRIGHT,
+               "", },
+#endif
+
+{ STASG,       INAREG|FOREFF,
+               SOREG|SNAME,            TANY,
+               SAREG,                  TPTRTO|TANY,
+               NSPECIAL|NAREG,         RDEST,
+               "F      mov A1,si\nZQF  mov si,A1\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* long div is emulated */
+{ DIV, INCREG,
+               SCREG|SNAME|SOREG|SCON, T32,
+               SCREG|SNAME|SOREG|SCON, T32,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+/* REVIEW We can only do (i)divb ax/byte  and (i)divw (dx:ax)/word
+   and the results are always in ah/al (remainer/mod)
+   or dx:ax (dx = remainer, ax = mod)
+   
+   Power of two needs to be done by shifts. For other cases of constants
+   we need to implement two things
+   1. Spotting add sequences for constants with few 1 bits on one side
+   2. Spotting cases we can compute the magic constant to multiply with for
+      the same result */
+   
+   
+{ DIV, INAREG,
+               SAREG,                  TUNSIGNED|TPOINT,
+               SAREG|SNAME|SOREG,      TUNSIGNED|TPOINT,
+               NSPECIAL,               RDEST,
+               "       xor dx,dx\n     divw AR\n", },
+
+{ DIV, INCH,
+               SHCH,                   TUCHAR,
+               SHCH|SNAME|SOREG,       TUCHAR,
+               NSPECIAL,               RDEST,
+               "       xor ah,ah\n     divb AR\n", },
+
+{ DIV, INFL,
+               SHFL,                   TDOUBLE,
+               SNAME|SOREG,            TDOUBLE,
+               0,                      RLEFT,
+               "       fdivl AR\n", },
+
+{ DIV, INFL,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RLEFT,
+               "       fdivZAp\n", },
+
+/* (u)long mod is emulated */
+{ MOD,         INCREG,
+               SCREG|SNAME|SOREG|SCON, T32,
+               SCREG|SNAME|SOREG|SCON, T32,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ MOD,         INAREG,
+               SAREG,                  TP16,
+               SAREG|SNAME|SOREG,      TP16,
+               NAREG|NSPECIAL,         RESC1,
+               "       xor dx,dx\n     divw AR\n", },
+
+{ MOD, INCH,
+               SHCH,                   TUCHAR,
+               SHCH|SNAME|SOREG,       TUCHAR,
+               NBREG|NSPECIAL,         RESC1,
+               "       xor ah,ah\n     divb AR\n", },
+
+/* (u)long mul is emulated */
+/* On 8086 we can only do multiplies of al * value into ax (for 8bit)
+   or ax * value into dx:ax for 16bit 
+   
+   80186 allows us to do a signed multiply of a register with a constant
+   into a second register
+   
+   Same about shifts, and add optimisations applies here too */
+   
+/* 32bit mul is emulated (for now) */
+{ MUL,         INCREG,
+               SCREG|SNAME|SOREG|SCON,         T32,
+               SCREG|SNAME|SOREG|SCON,         T32,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+/* FIMXE: need special rules */
+{ MUL, INAREG,
+               SAREG,                  T16|TPOINT,
+               SAREG|SNAME|SOREG,      T16|TPOINT,
+               NSPECIAL,               RDEST,
+               "       mul AR\n", },
+
+{ MUL, INCH,
+               SHCH,                   T8,
+               SHCH|SNAME|SOREG,       T8,
+               NSPECIAL,               RDEST,
+               "       mulb AR\n", },
+
+{ MUL, INFL,
+               SHFL,                   TDOUBLE,
+               SNAME|SOREG,            TDOUBLE,
+               0,                      RLEFT,
+               "       fmull AR\n", },
+
+{ MUL, INFL,
+               SHFL    ,               TLDOUBLE|TDOUBLE|TFLOAT,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RLEFT,
+               "       fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,        INLL,
+               SANY,                   TANY,
+               SOREG,                  T32,
+               NCREG,                  RESC1,
+               "       mov UL,U1\n     mov AL,A1\n", },
+
+{ UMUL,        INAREG,
+               SANY,                   TP16,
+               SOREG,                  TP16,
+               NAREG|NASL,             RESC1,
+               "       mov AL,A1\n", },
+
+{ UMUL,        INCH,
+               SANY,                   TANY,
+               SOREG,                  T8,
+               NBREG|NBSL,             RESC1,
+               "       mov AL,A1\n", },
+
+{ UMUL,        INAREG,
+               SANY,                   TANY,
+               SOREG,                  T16,
+               NAREG|NASL,             RESC1,
+               "       mov AL,A1\n", },
+
+{ UMUL,        INFL,
+               SANY,                   TANY,
+               SOREG,                  TLDOUBLE,
+               NDREG|NDSL,             RESC1,
+               "       fldt AL\n", },
+
+{ UMUL,        INFL,
+               SANY,                   TANY,
+               SOREG,                  TDOUBLE,
+               NDREG|NDSL,             RESC1,
+               "       fldl AL\n", },
+
+{ UMUL,        INFL,
+               SANY,                   TANY,
+               SOREG,                  TFLOAT,
+               NDREG|NDSL,             RESC1,
+               "       flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG,       FORCC,
+               SHL|SOREG|SNAME,        T32,
+               SHL,                    T32,
+               0,      0,
+               "ZD", },
+
+{ OPLOG,       FORCC,
+               SAREG|SOREG|SNAME,      TP16,
+               SCON|SAREG,             TP16,
+               0,                      RESCC,
+               "       cmp AL,AR\n", },
+
+
+{ OPLOG,       FORCC,
+               SCON|SAREG,             TP16,
+               SAREG|SOREG|SNAME,      TP16,
+               0,                      RESCC,
+               "       cmp AL,AR\n", },
+
+{ OPLOG,       FORCC,
+               SBREG|SOREG|SNAME,      T8,
+               SCON|SBREG,             TANY,
+               0,                      RESCC,
+               "       cmpb AL,AR\n", },
+
+{ OPLOG,       FORCC,
+               SCON|SBREG,             T8,
+               SBREG|SOREG|SNAME,      TANY,
+               0,                      RESCC,
+               "       cmpb AL,AR\n", },
+
+{ OPLOG,       FORCC,
+               SDREG,                  TLDOUBLE|TDOUBLE|TFLOAT,
+               SDREG,                  TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RNOP,
+               "ZG", },
+
+{ OPLOG,       FORCC,
+               SANY,                   TANY,
+               SANY,                   TANY,
+               REWRITE,        0,
+               "diediedie!", },
+
+/* AND/OR/ER/NOT */
+
+/* FIXME: pcc generates nonsense ands, but they should be fixed somewhere
+   if possible. In particular it will do the classic 32bit and with a 16bit
+   0xFFFF by generating and ax,#ffff and bx,#0
+       eg compiling
+               sum1 = (sum1 & 0xFFFF) + (sum1 >> 16);
+       writes a pile of crap code.
+*/
+       
+       
+{ AND, INCREG|FOREFF,
+               SCREG,                  T32,
+               SCREG|SOREG|SNAME,      T32,
+               0,                      RLEFT,
+               "       and AR,AL\n     and UR,UL\n", },
+
+{ AND, INAREG|FOREFF,
+               SAREG,                  T16,
+               SAREG|SOREG|SNAME,      T16,
+               0,                      RLEFT,
+               "       and AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+               SAREG|SOREG|SNAME,      T16,
+               SCON|SAREG,             T16,
+               0,                      RLEFT,
+               "       and AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+               SBREG|SOREG|SNAME,      T8,
+               SCON|SBREG,             T8,
+               0,                      RLEFT,
+               "       and AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+               SBREG,                  T8,
+               SBREG|SOREG|SNAME,      T8,
+               0,                      RLEFT,
+               "       and AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+               SCON,                   TANY,
+               SANY,                   TANY,
+               0,                      RNOP,
+               "       jmp LL\n", },
+
+#if defined(GCC_COMPAT) || defined(LANG_F77)
+{ GOTO,        FOREFF,
+               SAREG,                  TANY,
+               SANY,                   TANY,
+               0,                      RNOP,
+               "       jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,     FORCC|INL,
+               SCREG,                  T32,
+               SMIXOR,                 TANY,
+               NCREG,                  RESC1,
+               "       xor U1,U1\n     xor A1,A1\n", },
+
+{ OPLTYPE,     FORCC|INL,
+               SCREG,                  T32,
+               SMILWXOR,               TANY,
+               NCREG,                  RESC1,
+               "       mov U1,UL\n     xor A1,A1\n", },
+
+{ OPLTYPE,     FORCC|INL,
+               SCREG,                  T32,
+               SMIHWXOR,               TANY,
+               NCREG,                  RESC1,
+               "       xor U1,U1\n     mov A1,AL\n", },
+
+{ OPLTYPE,     INL,
+               SANY,                   TANY,
+               SCREG,                  T32,
+               NCREG,                  RESC1,
+               "ZK", },
+
+{ OPLTYPE,     INL,
+               SANY,                   TANY,
+               SCON|SOREG|SNAME,       T32,
+               NCREG,                  RESC1,
+               "       mov U1,UL\n     mov A1,AL\n", },
+
+{ OPLTYPE,     FORCC|INAREG,
+               SAREG,                  TP16,
+               SMIXOR,                 TANY,
+               NAREG|NASL,             RESC1,
+               "       xor A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+               SANY,                   TANY,
+               SAREG|SCON|SOREG|SNAME, TP16,
+               NAREG|NASL,             RESC1,
+               "       mov A1,AL\n", },
+
+{ OPLTYPE,     INBREG,
+               SANY,                   TANY,
+               SBREG|SOREG|SNAME|SCON, T8,
+               NBREG,                  RESC1,
+               "       mov A1,AL\n", },
+
+{ OPLTYPE,     FORCC|INAREG,
+               SAREG,                  T16,
+               SMIXOR,                 TANY,
+               NAREG,                  RESC1,
+               "       xor A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+               SANY,                   TANY,
+               SAREG|SOREG|SNAME|SCON, T16,
+               NAREG,                  RESC1,
+               "       mov A1,AL\n", },
+
+{ OPLTYPE,     INDREG,
+               SANY,                   TLDOUBLE,
+               SOREG|SNAME,            TLDOUBLE,
+               NDREG,                  RESC1,
+               "       fldt AL\n", },
+
+{ OPLTYPE,     INDREG,
+               SANY,                   TDOUBLE,
+               SOREG|SNAME,            TDOUBLE,
+               NDREG,                  RESC1,
+               "       fldl AL\n", },
+
+{ OPLTYPE,     INDREG,
+               SANY,                   TFLOAT,
+               SOREG|SNAME,            TFLOAT,
+               NDREG,                  RESC1,
+               "       flds AL\n", },
+
+/* Only used in ?: constructs. The stack already contains correct value */
+{ OPLTYPE,     INDREG,
+               SANY,                   TFLOAT|TDOUBLE|TLDOUBLE,
+               SDREG,                  TFLOAT|TDOUBLE|TLDOUBLE,
+               NDREG,                  RESC1,
+               "", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      INCREG|FOREFF,
+               SCREG,                  T32,
+               SCREG,                  T32,
+               0,                      RLEFT,
+               "       neg AL\n        adc UL,#0\n     neg UL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+               SAREG,                  TP16,
+               SAREG,                  TP16,
+               0,                      RLEFT,
+               "       neg AL\n", },
+
+{ UMINUS,      INBREG|FOREFF,
+               SBREG,                  T8,
+               SBREG,                  T8,
+               0,                      RLEFT,
+               "       neg AL\n", },
+
+{ UMINUS,      INFL|FOREFF,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,                      RLEFT,
+               "       fchs\n", },
+
+{ COMPL,       INCREG,
+               SCREG,                  T32,
+               SANY,                   TANY,
+               0,                      RLEFT,
+               "       not AL\n        not UL\n", },
+
+{ COMPL,       INAREG,
+               SAREG,                  T16,
+               SANY,                   TANY,
+               0,                      RLEFT,
+               "       not AL\n", },
+
+{ COMPL,       INBREG,
+               SBREG,                  T8,
+               SANY,                   TANY,
+               0,                      RLEFT,
+               "       not AL\n", },
+
+/*
+ * Arguments to functions.
+ *
+ * char has already been promoted to integer types
+ */
+/* Push immediate not 8086... Loading a register and pushing costs us
+   4 + 11 clocks, loading memory would cost us 16 + EA */
+{ FUNARG,      FOREFF,
+               /*SCON|*/SCREG|SNAME|SOREG,     T32,
+               SANY,                   T32,
+               0,                      RNULL,
+               "       push UL\n       push AL\n", },
+
+{ FUNARG,      FOREFF,
+               /*SCON|*/SAREG|SNAME|SOREG,     T16|TPOINT,
+               SANY,                   TP16,
+               0,                      RNULL,
+               "       push AL\n", },
+
+/* FIXME: FPU needs reworking into 4 regs or a memcpy */
+{ FUNARG,      FOREFF,
+               SNAME|SOREG,            TDOUBLE,
+               SANY,                   TDOUBLE,
+               0,                      0,
+               "       pushl UL\n      pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+               SDREG,                  TDOUBLE,
+               SANY,                   TDOUBLE,
+               0,                      0,
+               "       sub sp,#8\n     fstpl [sp]\n", },
+
+{ FUNARG,      FOREFF,
+               SNAME|SOREG,            TFLOAT,
+               SANY,                   TFLOAT,
+               0,      0,
+               "       push UL\n       push AL\n", },
+
+{ FUNARG,      FOREFF,
+               SDREG,                  TFLOAT,
+               SANY,                   TFLOAT,
+               0,                      0,
+               "       sub sp,#4\n     fstps [sp]\n", },
+
+{ FUNARG,      FOREFF,
+               SDREG,                  TLDOUBLE,
+               SANY,                   TLDOUBLE,
+               0,                      0,
+               "       sub sp,#12\n    fstpt [sp]\n", },
+
+{ STARG,       FOREFF,
+               SAREG,                  TPTRTO|TSTRUCT,
+               SANY,                   TSTRUCT,
+               NSPECIAL,               0,
+               "ZF", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/m16c/TODO b/lang/pcc/pcc/arch/m16c/TODO
new file mode 100644 (file)
index 0000000..5ef0ba4
--- /dev/null
@@ -0,0 +1 @@
+* Mul/Div does not work.
\ No newline at end of file
diff --git a/lang/pcc/pcc/arch/m16c/code.c b/lang/pcc/pcc/arch/m16c/code.c
new file mode 100644 (file)
index 0000000..cbad1ed
--- /dev/null
@@ -0,0 +1,333 @@
+/*     $Id: code.c,v 1.25 2014/05/29 19:20:02 plunky Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ */
+void
+defalign(int n)
+{
+#if 0
+       char *s;
+
+       n /= SZCHAR;
+       if (lastloc == PROG || n == 1)
+               return;
+       s = (isinlining ? permalloc(40) : tmpalloc(40));
+       sprintf(s, "\t.align %d\n", n);
+       send_passt(IP_ASM, s);
+#endif
+}
+
+/*
+ * define the current location as the name p->soname
+ */
+void
+defnam(struct symtab *p)
+{
+       char *c = p->soname;
+
+       if (p->sclass == EXTDEF)
+               printf("        PUBLIC %s\n", c);
+       printf("%s:\n", c);
+}
+
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       NODE *p, *q;
+       int sz;
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+       /* address of return struct is in eax */
+       /* create a call to memcpy() */
+       /* will get the result in eax */
+       p = block(REG, NIL, NIL, CHAR+PTR, 0, 0);
+       p->n_rval = R0;
+       q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0);
+       q->n_rval = FB;
+       q->n_lval = 8; /* return buffer offset */
+       p = block(CM, q, p, INT, 0, 0);
+       sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+       p = block(CM, p, bcon(sz), INT, 0, 0);
+       p->n_right->n_name = "";
+       p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0);
+       p->n_left->n_name = "memcpy";
+       send_passt(IP_NODE, p);
+}
+
+/*
+ * helper for bfcode() to put register arguments on stack.
+ */
+static void
+argmove(struct symtab *s, int regno)
+{
+       NODE *p, *r;
+
+       s->sclass = AUTO;
+       s->soffset = NOOFFSET;
+       oalloc(s, &autooff);
+       p = nametree(s);
+       r = bcon(0);
+       r->n_op = REG;
+       r->n_rval = regno;
+       r->n_type = p->n_type;
+       r->n_sue = p->n_sue;
+       r->n_df = p->n_df;
+       ecode(buildtree(ASSIGN, p, r));
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ * On m16k, space is allocated on stack for register arguments,
+ * arguments are moved to the stack and symtab is updated accordingly.
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+       struct symtab *s;
+       int i, r0l, r0h, a0, r2, sz, hasch, stk;
+       int argoff = ARGINIT;
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               /* Function returns struct, adjust arg offset */
+               for (i = 0; i < n; i++)
+                       a[i]->soffset += SZPOINT(INT);
+       }
+       /* first check if there are 1-byte parameters */
+       for (hasch = i = 0; i < n && i < 6; i++)
+               if (DEUNSIGN(a[i]->stype) == CHAR)
+                       hasch = 1;
+
+       stk = r0l = r0h = a0 = r2 = 0;
+       for (i = 0; i < n; i++) {
+               s = a[i];
+               sz = tsize(s->stype, s->sdf, s->ssue);
+               if (ISPTR(s->stype) && ISFTN(DECREF(s->stype)))
+                       sz = SZLONG; /* function pointers are always 32 */
+               if (stk == 0)
+                   switch (sz) {
+               case SZCHAR:
+                       if (r0l) {
+                               if (r0h)
+                                       break;
+                               argmove(s, 1);
+                               r0h = 1;
+                       } else {
+                               argmove(s, 0);
+                               r0l = 1;
+                       }
+                       continue;
+
+               case SZINT:
+                       if (s->stype > BTMASK) {
+                               /* is a pointer */
+                               if (a0) {
+                                       if (r0l || hasch) {
+                                               if (r2)
+                                                       break;
+                                               argmove(s, R2);
+                                               r2 = 1;
+                                       } else {
+                                               argmove(s, R0);
+                                               r0l = r0h = 1;
+                                       }
+                               } else {
+                                       argmove(s, A0);
+                                       a0 = 1;
+                               }
+                       } else if (r0l || hasch) {
+                               if (r2) {
+                                       if (a0)
+                                               break;
+                                       argmove(s, A0);
+                                       a0 = 1;
+                               } else {
+                                       argmove(s, R2);
+                                       r2 = 1;
+                               }
+                       } else {
+                               argmove(s, R0);
+                               r0l = r0h = 1;
+                       }
+                       continue;
+               case SZLONG:
+                       if (r0l||r0h||r2)
+                               break;
+                       argmove(s, R0);
+                       r0l = r0h = r2 = 1;
+                       continue;
+
+               default:
+                       break;
+               }
+               stk = 1;
+               s->soffset = argoff;
+               argoff += sz;
+       }
+}
+
+/*
+ * Add a symbol to an internal list printed out at the end.
+ */
+void addsym(struct symtab *);
+static struct symlst {
+       struct symlst *next;
+       struct symtab *sp;
+} *sympole;
+
+void
+addsym(struct symtab *q)
+{
+       struct symlst *w = sympole;
+
+       if (q == NULL)
+               return;
+
+       while (w) {
+               if (q == w->sp)
+                       return; /* exists */
+               w = w->next;
+       }
+       w = permalloc(sizeof(struct symlst));
+       w->sp = q;
+       w->next = sympole;
+       sympole = w;
+}
+
+struct caps {
+       char *cap, *stat;
+} caps[] = {
+       { "__64bit_doubles", "Disabled" },
+       { "__calling_convention", "Normal" },
+       { "__constant_data", "near" },
+       { "__data_alignment", "2" },
+       { "__data_model", "near" },
+       { "__processor", "M16C" },
+       { "__rt_version", "1" },
+       { "__variable_data", "near" },
+       { NULL, NULL },
+};
+
+/*
+ * Called before parsing begins.
+ */
+void
+bjobcode(void)
+{
+       struct caps *c;
+
+       printf("        NAME gurka.c\n"); /* Don't have the name */
+       for (c = caps; c->cap; c++)
+               printf("        RTMODEL \"%s\", \"%s\"\n", c->cap, c->stat);
+       //printf("      RSEG CODE:CODE:REORDER:NOROOT(0)\n");
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+       struct symlst *w = sympole;
+
+       for (w = sympole; w; w = w->next) {
+               if (w->sp->sclass != EXTERN)
+                       continue;
+               printf("        EXTERN %s\n", w->sp->soname);
+       }
+       
+       printf("        END\n");
+}
+
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+       static  int     lastoctal = 0;
+
+       /* put byte i+1 in a string */
+
+       if (t < 0) {
+               if (i != 0)
+                       puts("\"");
+       } else {
+               if (i == 0)
+                       printf("\t.ascii \"");
+               if (t == '\\' || t == '"') {
+                       lastoctal = 0;
+                       putchar('\\');
+                       putchar(t);
+               } else if (t < 040 || t >= 0177) {
+                       lastoctal++;
+                       printf("\\%o",t);
+               } else if (lastoctal && '0' <= t && t <= '9') {
+                       lastoctal = 0;
+                       printf("\"\n\t.ascii \"%c", t);
+               } else {        
+                       lastoctal = 0;
+                       putchar(t);
+               }
+       }
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       return p;
+}
diff --git a/lang/pcc/pcc/arch/m16c/local.c b/lang/pcc/pcc/arch/m16c/local.c
new file mode 100644 (file)
index 0000000..259427b
--- /dev/null
@@ -0,0 +1,454 @@
+/*     $Id: local.c,v 1.22 2015/08/18 10:15:08 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*     this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(NODE *p)
+{
+       /* this is called to do local transformations on
+          an expression tree preparitory to its being
+          written out in intermediate code.
+       */
+
+       /* the major essential job is rewriting the
+          automatic variables and arguments in terms of
+          REG and OREG nodes */
+       /* conversion ops which are not necessary are also clobbered here */
+       /* in addition, any special features (such as rewriting
+          exclusive or) are easily handled here as well */
+
+       struct symtab *q;
+       NODE *l, *r;
+       int o;
+       TWORD ml;
+
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case STATIC:
+                       if (q->slevel == 0)
+                               break;
+                       p->n_lval = 0;
+                       p->n_sp = q;
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+                       }
+               break;
+
+       case PCONV:
+               ml = p->n_left->n_type;
+               l = p->n_left;
+               if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON)
+                       break;
+               l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_sue = p->n_sue;
+               nfree(p);
+               p = l;
+               break;
+
+       case SCONV:
+               l = p->n_left;
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) {
+                       nfree(p);
+                       return l;
+               }
+               if (l->n_op == ICON) {
+                       CONSZ val = l->n_lval;
+                       switch (p->n_type) {
+                       case CHAR:
+                               l->n_lval = (char)val;
+                               break;
+                       case UCHAR:
+                               l->n_lval = val & 0377;
+                               break;
+                       case SHORT:
+                       case INT:
+                               l->n_lval = (short)val;
+                               break;
+                       case USHORT:
+                       case UNSIGNED:
+                               l->n_lval = val & 0177777;
+                               break;
+                       case ULONG:
+                       case ULONGLONG:
+                               l->n_lval = val & 0xffffffff;
+                               break;
+                       case LONG:
+                       case LONGLONG:
+                               l->n_lval = (int)val;
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", p->n_type);
+                       }
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       return l;
+               }
+               break;
+               
+
+       }
+
+       return(p);
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == INT || t == UNSIGNED || t == CHAR || t == UCHAR ||
+               ISPTR(t))
+               return(1);
+       return 0; /* XXX - fix reg assignment in pftn.c */
+}
+
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       if ((off % SZINT) == 0)
+               p =  buildtree(MUL, p, bcon(off/SZINT));
+       else if ((off % SZSHORT) == 0) {
+               p = buildtree(MUL, p, bcon(off/SZSHORT));
+               p = buildtree(PLUS, p, bcon(1));
+               p = buildtree(RS, p, bcon(1));
+       } else if ((off % SZCHAR) == 0) {
+               p = buildtree(MUL, p, bcon(off/SZCHAR));
+               p = buildtree(PLUS, p, bcon(3));
+               p = buildtree(RS, p, bcon(2));
+       } else
+               cerror("roundsp");
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+       /* add the size to sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+int
+ninval(NODE *p)
+{
+       struct symtab *q;
+       TWORD t;
+
+       p = p->n_left;
+       t = p->n_type;
+       if (t > BTMASK)
+               t = p->n_type = INT; /* pointer */
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+               inval(p->n_lval & 0xffffffff);
+               inval(p->n_lval >> 32);
+               break;
+       case LONG:
+       case ULONG:
+       case INT:
+       case UNSIGNED:
+               printf("\t.long 0x%x", (int)p->n_lval);
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)) {
+                               printf("+" LABFMT, q->soffset);
+                       } else
+                               printf("+%s", exname(q->soname));
+               }
+               printf("\n");
+               break;
+       default:
+               fwalk(p, eprint, 0);
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+       if (p == NULL)
+               return "";
+       return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case SHORT:
+               MODTYPE(type,INT);
+               break;
+
+       case USHORT:
+               MODTYPE(type,UNSIGNED);
+               break;
+
+       case LONGLONG:
+               MODTYPE(type,LONG);
+               break;
+
+       case ULONGLONG:
+               MODTYPE(type,ULONG);
+               break;
+
+       case LDOUBLE:
+               MODTYPE(type,DOUBLE);
+               break;
+       }
+       return (type);
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the storage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+       return(EXTERN);
+}
+
+/*
+ * Extern variable not necessary common.
+ */
+void
+extdec(struct symtab *q)
+{
+       extern void addsym(struct symtab *);
+       addsym(q);
+}
+
+/*
+ * Call to a function
+ */
+void
+calldec(NODE *p, NODE *r)
+{
+       struct symtab *q = p->n_sp;
+       extern void addsym(struct symtab *);
+       addsym(q);
+}
+
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+       int off;
+       char *c = q->soname;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+
+       printf("        PUBLIC %s\n", c);
+       /* XXX - NOROOT??? */
+       printf("        RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n");
+       printf("%s:\n", c);
+       printf("        DS8 %d\n", off);
+       printf("        REQUIRE __data16_zero\n");
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       if (q->slevel == 0)
+               printf("        .lcomm %s,0%o\n", exname(q->soname), off);
+       else
+               printf("        .lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+void
+setloc1(int locc)
+{
+       if (locc == lastloc)
+               return;
+       lastloc = locc;
+}
+
+/*
+ * special handling before tree is written out.
+ */
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+       union dimfun *df;
+       union arglist *al;
+       NODE *q;
+       int i;
+
+       switch (p->n_op) {
+       case MOD:
+       case DIV:
+               if (p->n_type == LONG || p->n_type == ULONG) {
+                       /* Swap arguments for hardops() later */
+                       q = p->n_left;
+                       p->n_left = p->n_right;
+                       p->n_right = q;
+               }
+               break;
+
+       case CALL:
+       case STCALL:
+               /*
+                * inform pass2 about varargs.
+                * store first variadic argument number in n_stalign
+                * in the CM node.
+                */
+               if (p->n_right->n_op != CM)
+                       break; /* nothing to care about */
+               df = p->n_left->n_df;
+               if (df && (al = df->dfun)) {
+                       for (i = 0; i < 6; i++, al++) {
+                               if (al->type == TELLIPSIS || al->type == TNULL)
+                                       break;
+                       }
+                       p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0;
+               } else
+                       p->n_right->n_stalign = 0;
+               break;
+
+       case FCON:
+               /* Write float constants to memory */
+               sp = tmpalloc(sizeof(struct symtab));
+               sp->sclass = STATIC;
+               sp->ssue = 0;
+               sp->slevel = 1; /* fake numeric label */
+               sp->soffset = getlab();
+               sp->sflags = 0;
+               sp->stype = p->n_type;
+               sp->squal = (CON >> TSHIFT);
+
+               defloc(sp);
+               ninval(0, sp->ssue->suesize, p);
+
+               p->n_op = NAME;
+               p->n_lval = 0;
+               p->n_sp = sp;
+               break;
+       }
+
+}
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char **ary)
+{
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/m16c/local2.c b/lang/pcc/pcc/arch/m16c/local2.c
new file mode 100644 (file)
index 0000000..f3f63d8
--- /dev/null
@@ -0,0 +1,664 @@
+/*     $Id: local2.c,v 1.43 2015/01/04 19:17:23 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+
+static int ftlab1, ftlab2;
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static TWORD ftype;
+static int addto;
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+    ftype = ipp->ipp_type;
+
+#if 0
+    if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR)
+       comperr("fix prologue register savings", ipp->ipp_regs);
+#endif
+    
+    printf("   RSEG CODE:CODE:REORDER:NOROOT(0)\n");
+    if (ipp->ipp_vis)  
+       printf("        PUBLIC %s\n", ipp->ipp_name);
+    printf("%s:\n", ipp->ipp_name);
+    
+#if 0  
+    if (xsaveip) {
+       /* Optimizer running, save space on stack */
+       addto = (p2maxautooff - AUTOINIT)/SZCHAR;
+       printf("        enter #%d\n", addto);
+    } else {
+#endif
+
+       /* non-optimized code, jump to epilogue for code generation */
+       ftlab1 = getlab2();
+       ftlab2 = getlab2();
+       printf("        jmp.w " LABFMT "\n", ftlab1);
+       deflab(ftlab2);
+}
+
+/*
+ * End of block.
+ */
+void
+eoftn(struct interpass_prolog *ipp)
+{
+#if 0
+       if (ipp->ipp_regs != MINRVAR)
+               comperr("fix eoftn register savings %x", ipp->ipp_regs);
+#endif
+
+       //      if (xsaveip == 0)
+       addto = (p2maxautooff - AUTOINIT)/SZCHAR;
+
+       /* return from function code */
+       //deflab(ipp->ipp_ip.ip_lbl);   //XXX - is this necessary?
+       
+       /* If retval is a pointer and not a function pointer, put in A0 */
+       if (ISPTR(DECREF(ipp->ipp_type)) &&
+           !ISFTN(DECREF(DECREF(ipp->ipp_type))))
+           printf("    mov.w r0,a0\n");
+       
+       /* struct return needs special treatment */
+       if (ftype == STRTY || ftype == UNIONTY) {
+               comperr("fix struct return in eoftn");
+       } else
+               printf("        exitd\n");
+
+       /* Prolog code */
+       //      if (xsaveip == 0) {
+               deflab(ftlab1);
+               printf("        enter #%d\n", addto);
+               printf("        jmp.w " LABFMT "\n", ftlab2);
+               //}
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s.%c", str, f);
+}
+
+char *
+rnames[] = {  /* keyed to register number tokens */
+    "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l",
+    "r1h", "r1l",
+};
+
+/*
+ * Return the size (in bytes) of some types.
+ */
+int
+tlen(p) NODE *p;
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case INT:
+               case UNSIGNED:
+               case FLOAT:
+                       return 2;
+
+               case DOUBLE:
+               case LONG:
+               case ULONG:
+                       return 4;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int o = p->n_op;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       if (o >= ULE)
+               o -= (ULE-LE);
+       switch (o) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       expand(p, 0, "  cmp.w UR,UL\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+       expand(p, 0, "  cmp.w AR,AL\n");
+       cbgen(p->n_op, e);
+       deflab(s);
+}
+
+
+void
+zzzcode(NODE *p, int c)
+{
+       NODE *l;
+
+       switch (c) {
+       case 'A': /* print negative shift constant */
+               p = getlr(p, 'R');
+               if (p->n_op != ICON)
+                       comperr("ZA bad use");
+               p->n_lval = -p->n_lval;
+               adrput(stdout, p);
+               p->n_lval = -p->n_lval;
+               break;
+
+       case 'B':
+               if (p->n_rval)
+                       printf("        add.b #%d,%s\n",
+                           p->n_rval, rnames[STKREG]);
+               break;
+
+       case 'C': /* Print label address */
+               p = p->n_left;
+               if (p->n_lval)
+                       printf(LABFMT, (int)p->n_lval);
+               else
+                       printf("%s", p->n_name);
+               break;
+
+       case 'D': /* copy function pointers */
+               l = p->n_left;
+               printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n",
+                   p->n_right->n_name, rnames[l->n_rval+1],
+                   p->n_right->n_name, rnames[l->n_rval]);
+               break;
+
+       case 'E': /* double-reg printout */
+               /* XXX - always r0r2 here */
+               printf("%s%s", rnames[R0], rnames[R2]);
+               break;
+
+       case 'F': /* long comparisions */
+               twollcomp(p);
+               break;
+
+       case 'G':
+               printf("R0R2");
+               break;
+
+       case 'H': /* push 32-bit address (for functions) */
+               printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n",
+                   p->n_left->n_name, p->n_left->n_name);
+               break;
+
+       case 'I': /* push 32-bit address (for functions) */
+               l = p->n_left;
+               printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n",
+                   (int)l->n_lval, rnames[l->n_rval],
+                   (int)l->n_lval+2, rnames[l->n_rval]);
+               break;
+
+       default:
+               comperr("bad zzzcode %c", c);
+       }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, SOREG) == SRDIR))
+               return(1);
+       return(0);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       return 0;
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o == OREG || o == REG || o == NAME)
+               return SRDIR; /* Direct match */
+       if (o == UMUL && shumul(p->n_left, SOREG))
+               return SROREG; /* Convert into oreg */
+       return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = p->n_lval;
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+%d", val);
+               } else
+                       fprintf(fp, "%d", val);
+               return;
+
+       default:
+               comperr("illegal conput");
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZINT;
+       switch (p->n_op) {
+       case REG:
+               printf("%s", rnames[p->n_rval + 1]);
+               break;
+
+       case NAME:
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+       case ICON:
+               printf("#" CONFMT, p->n_lval >> 16);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       /* output an address, with offsets, from p */
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0')
+                       fputs(p->n_name, io);
+               if (p->n_lval != 0)
+                       fprintf(io, "+" CONFMT, p->n_lval);
+               return;
+
+       case OREG:
+               if (p->n_lval)
+                       fprintf(io, "%d", (int)p->n_lval);
+               fprintf(io, "[%s]", rnames[p->n_rval]);
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               fputc('#', io);
+               conput(io, p);
+               return;
+
+       case REG:
+           /*if (DEUNSIGN(p->n_type) == CHAR) {
+                       fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1',
+                           (p->n_rval & 1) ? 'H' : 'L');
+                           } else*/
+           fprintf(io, "%s", rnames[p->n_rval]);
+           return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+static char *
+ccbranches[] = {
+       "jeq",          /* jumpe */
+       "jne",          /* jumpn */
+       "jle",          /* jumple */
+       "jlt",          /* jumpl */
+       "jge",          /* jumpge */
+       "jgt",          /* jumpg */
+       "jleu",         /* jumple (jlequ) */
+       "jltu",         /* jumpl (jlssu) */
+       "jgeu",         /* jumpge (jgequ) */
+       "jgtu",         /* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("        %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+#if 0
+void
+mygenregs(NODE *p)
+{
+
+       if (p->n_op == MINUS && p->n_type == DOUBLE &&
+           (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) {
+               p->n_su |= DORIGHT;
+       }
+       /* Must walk down correct node first for logops to work */
+       if (p->n_op != CBRANCH)
+               return;
+       p = p->n_left;
+       if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG))
+               return;
+       p->n_su &= ~DORIGHT;
+
+}
+#endif
+
+struct hardops hardops[] = {
+       { PLUS, FLOAT, "?F_ADD_L04" },
+       { MUL, LONG, "?L_MUL_L03" },
+       { MUL, ULONG, "?L_MUL_L03" },
+       { DIV, LONG, "?SL_DIV_L03" },
+       { DIV, ULONG, "?UL_DIV_L03" },
+       { MOD, LONG, "?SL_MOD_L03" },
+       { MOD, ULONG, "?UL_MOD_L03" },
+       { RS, LONGLONG, "__ashrdi3" },
+       { RS, ULONGLONG, "__lshrdi3" },
+       { LS, LONGLONG, "__ashldi3" },
+       { LS, ULONGLONG, "__ashldi3" },
+       { 0 },
+};
+
+int
+special(NODE *p, int shape)
+{
+       switch (shape) {
+       case SFTN:
+               if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) {
+                       if (p->n_op == NAME || p->n_op == OREG)
+                               return SRDIR;
+                       else
+                               return SRREG;
+               }
+               break;
+       }
+       return SRNOPE;
+}
+
+void    
+myreader(NODE *p)
+{
+       NODE *q, *r, *s, *right;
+
+       if (optype(p->n_op) == LTYPE)
+               return;
+       if (optype(p->n_op) != UTYPE)
+               myreader(p->n_right);
+       myreader(p->n_left);
+
+       switch (p->n_op) {
+       case PLUS:
+       case MINUS:
+               if (p->n_type != LONG && p->n_type != ULONG)
+                       break;
+               if (p->n_right->n_op == NAME || p->n_right->n_op == OREG)
+                       break;
+               /* Must convert right into OREG */
+               right = p->n_right;
+               q = mklnode(OREG, (freetemp(szty(right->n_type))),
+                   FPREG, right->n_type);
+               s = mkbinode(ASSIGN, q, right, right->n_type);
+               r = talloc(); 
+               *r = *q;
+               p->n_right = r;
+               pass2_compile(ipnode(s));
+               break;
+       }
+}
+
+
+void
+rmove(int s, int d, TWORD t)
+{
+       switch (t) {
+       case CHAR:
+       case UCHAR:
+           printf("    mov.b %s,%s\n", rnames[s], rnames[d]);
+           break;
+       default:
+           printf("    mov.w %s,%s\n", rnames[s], rnames[d]);
+       }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num;
+
+       switch (c) {
+       case CLASSA:
+               num = r[CLASSA];
+               num += r[CLASSC];
+               return num < 4;
+       case CLASSB:
+               num = r[CLASSB];
+               return num < 2;
+       case CLASSC:
+               num = 2*r[CLASSA];
+               num += r[CLASSC];
+               return num < 4;
+       }
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == CHAR || t == UCHAR)
+               return CLASSC;
+       
+       if(ISPTR(t))
+               return CLASSB;
+       
+       return CLASSA;
+}
+
+static int sizen;
+
+/* XXX: Fix this. */
+static int
+argsiz(NODE *p)
+{
+        TWORD t = p->n_type;
+
+        if (t < LONGLONG || t > MAXTYPES)
+                return 4;
+        if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+                return 8;
+        if (t == LDOUBLE)
+                return 12;
+        if (t == STRTY)
+                return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+        comperr("argsiz");
+        return 0;
+}
+
+/*
+ * Calculate argument sizes.
+ * XXX: Fix this.
+ */
+void
+lastcall(NODE *p)
+{
+        sizen = 0;
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+                sizen += argsiz(p->n_right);
+        sizen += argsiz(p);
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/m16c/macdefs.h b/lang/pcc/pcc/arch/m16c/macdefs.h
new file mode 100644 (file)
index 0000000..5c095af
--- /dev/null
@@ -0,0 +1,195 @@
+/*     $Id: macdefs.h,v 1.27 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+#define makecc(val,i)   lastcon = (lastcon<<8)|((val<<8)>>8);
+
+#define ARGINIT                40      /* # bits above fp where arguments start */
+#define AUTOINIT       0       /* # bits below fp where automatics start */
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise 
+ * treat it as an integer.
+ */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZINT          16
+#define SZFLOAT         16
+#define SZDOUBLE        16
+#define SZLDOUBLE       16
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG      32
+/* pointers are of different sizes on m16c */
+#define SZPOINT(t)     (ISFTN(DECREF(t)) ? 32 : 16)
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALINT          16
+#define ALFLOAT                16
+#define ALDOUBLE       16
+#define ALLDOUBLE      16
+#define ALLONG         16
+#define ALLONGLONG     16
+#define ALSHORT                16
+#define ALPOINT                16
+#define ALSTRUCT       16
+#define ALSTACK                16
+
+/*
+ * Min/max values.
+ */
+#define MIN_CHAR       -128
+#define MAX_CHAR       127
+#define MAX_UCHAR      255
+#define MIN_SHORT      -32768
+#define MAX_SHORT      32767
+#define MAX_USHORT     65535
+#define MIN_INT                -32768
+#define MAX_INT                32767
+#define MAX_UNSIGNED   65535
+#define MIN_LONG       -2147483648
+#define MAX_LONG       2147483647
+#define MAX_ULONG      4294967295UL
+#define MIN_LONGLONG   -2147483648
+#define MAX_LONGLONG   2147483647
+#define MAX_ULONGLONG  4294967295UL
+
+/* Default char is unsigned */
+#undef CHAR_UNSIGNED
+
+/*
+ * Use large-enough types.
+ */
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#define LABFMT "L%d"           /* format for printing labels */
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_LE
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     1
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)  gencall(a,b)
+
+#define szty(t) (((t) == LONG || (t) == ULONG || \
+       (ISPTR(t) && ISFTN(DECREF(t)))) ? 2 : 1)
+
+/*
+ * m16c register classes:
+ * A - 16-bit data registers R0-R3
+ * B - 16-bit address registers A0-A1
+ * C - 8-bit data registers R0H, R0L, R1H, R1L
+ */
+
+#define R0     0
+#define R2     1
+#define R1     2
+#define R3     3
+
+#define A0     4
+#define A1     5
+#define FB     6
+#define SP     7
+
+#define R0H     8
+#define R0L     9
+#define R1H     10
+#define R1L     11
+
+#define NUMCLASS 4      /* Number of register classes */
+
+#define RETREG(x)      (x == CHAR || x == UCHAR ? R0L : R0)
+
+#define FPREG  FB      /* frame pointer */
+#define STKREG SP      /* stack pointer */
+
+#if 0
+#define REGSZ  8       /* Number of registers */
+#define MINRVAR R1     /* first register variable */
+#define MAXRVAR R2     /* last register variable */
+#endif
+
+#define MAXREGS 12 /* 12 registers */
+
+#define RSTATUS \
+       SAREG|TEMPREG, SAREG|PERMREG, SAREG|TEMPREG, SAREG|PERMREG, \
+       SBREG|TEMPREG, SBREG|PERMREG, 0, 0, SCREG, SCREG, SCREG, SCREG,
+
+#define ROVERLAP \
+       {R0H, R0L, -1},\
+       {-1},\
+       {R1H, R1L, -1},\
+       {-1},\
+\
+       {-1},\
+       {-1},\
+\
+       {-1},\
+       {-1},\
+\
+       {R0, -1},\
+       {R0, -1},\
+       {R1, -1},\
+       {R1, -1},
+
+#define PCLASS(p) (p->n_type <= UCHAR ? SCREG : ISPTR(p->n_type) ? SBREG:SAREG)
+           
+int COLORMAP(int c, int *r);
+#define        GCLASS(x) (x < 4 ? CLASSA : x < 6 ? CLASSB : x < 12 ? CLASSC : CLASSD)
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define        ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 6)      /* A1 */
+#define ENCRA2(x)      ((x) << 12)     /* A2 */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+
+#define        MYADDEDGE(x, t)
+
+#ifndef NEW_READER
+//#define TAILCALL
+#endif
+#define        SFTN    (SPECIAL|6)
diff --git a/lang/pcc/pcc/arch/m16c/order.c b/lang/pcc/pcc/arch/m16c/order.c
new file mode 100644 (file)
index 0000000..1aaf0fe
--- /dev/null
@@ -0,0 +1,621 @@
+/*     $Id: order.c,v 1.22 2014/06/01 11:35:02 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <strings.h>
+
+int canaddr(NODE *);
+
+/*
+ * should the assignment op p be stored,
+ * given that it lies as the right operand of o
+ * (or the left, if o==UNARY MUL)
+ */
+/*
+void
+stoasg(NODE *p, int o)
+{
+       if (x2debug)
+               printf("stoasg(%p, %o)\n", p, o);
+}
+*/
+/* should we delay the INCR or DECR operation p */
+int
+deltest(NODE *p)
+{
+       return 0;
+}
+
+/*
+ * Check if p can be autoincremented.
+ * XXX - nothing can be autoincremented for now.
+ */
+int
+autoincr(NODE *p)
+{
+       return 0;
+}
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+int
+offstar(NODE *p, int shape)
+{
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( p->n_right->n_op == ICON ){
+                       geninsn(p->n_left, INBREG);
+                       p->n_su = -1;
+                       return 1;
+               }
+       }
+       geninsn(p, INBREG);
+       return 0;
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+//     NODE *l = p->n_left;
+
+#ifdef PCC_DEBUG
+       if (x2debug) {
+               printf("shumul(%p)\n", p);
+               fwalk(p, e2print, 0);
+       }
+#endif
+       /* XXX - fix */
+
+       /* Can only generate OREG of BREGs (or FB) */
+       if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB))
+               return SROREG;
+#if 0
+       if ((p->n_op == PLUS || p->n_op == MINUS) &&
+           (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) &&
+           p->n_right->n_op == ICON)
+               return SOREG;
+       return 0;
+#else
+       return SROREG;
+#endif
+}
+
+/*
+ * Rewrite increment/decrement operation.
+ */
+int
+setincr(NODE *p)
+{
+       if (x2debug)
+               printf("setincr(%p)\n", p);
+
+       return(0);
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+#if 0
+/*
+ * register allocation for instructions with special preferences.
+ */
+regcode
+regalloc(NODE *p, struct optab *q, int wantreg)
+{
+       regcode regc;
+
+       if (q->op == DIV || q->op == MOD) {
+               /*
+                * 16-bit div.
+                */
+               if (regblk[R0] & 1 || regblk[R2] & 1)
+                       comperr("regalloc: needed regs inuse, node %p", p);
+               if (p->n_su & DORIGHT) {
+                       regc = alloregs(p->n_right, A0);
+                       if (REGNUM(regc) != A0) {
+                               p->n_right = movenode(p->n_right, A0);
+                               if ((p->n_su & RMASK) == ROREG) {
+                                       p->n_su &= ~RMASK;
+                                       p->n_su |= RREG;
+                                       p->n_right->n_su &= ~LMASK;
+                                       p->n_right->n_su |= LOREG;
+                               }
+                               freeregs(regc);
+                               regblk[A0] |= 1;
+                       }
+               }
+               regc = alloregs(p->n_left, R0);
+               if (REGNUM(regc) != R0) {
+                       p->n_left = movenode(p->n_left, R0);
+                       freeregs(regc);
+                       regblk[R0] |= 1;
+               }
+               if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) {
+                       regc = alloregs(p->n_right, A0);
+                       if (REGNUM(regc) != A0) {
+                               p->n_right = movenode(p->n_right, A0);
+                               if ((p->n_su & RMASK) == ROREG) {
+                                       p->n_su &= ~RMASK;
+                                       p->n_su |= RREG;
+                                       p->n_right->n_su &= ~LMASK;
+                                       p->n_right->n_su |= LOREG;
+                               }
+                       }
+               }
+               regblk[A0] &= ~1;
+               regblk[R0] &= ~1;
+               regblk[R2] &= ~1;
+               if (q->op == DIV) {
+                       MKREGC(regc, R0, 1);
+                       regblk[R0] |= 1;
+               } else {
+                       MKREGC(regc, R2, 1);
+                       regblk[R2] |= 1;
+               }
+       } else
+               comperr("regalloc");
+       p->n_rall = REGNUM(regc);
+       return regc;
+}
+#endif
+
+/*
+ * Special handling of some instruction register allocation.
+ * - left is the register that left node wants.
+ * - right is the register that right node wants.
+ * - res is in which register the result will end up.
+ * - mask is registers that will be clobbered.
+ *
+ *  XXX - Fix this function
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+    switch (q->op) {
+
+    case DIV:
+    case MOD:
+       if(q->ltype & (TINT|TSHORT)){
+           static struct rspecial s[] = {
+               { NRES, R0 }, { NRES, R2}, { 0 } };
+           return s;
+       }
+       /*
+       else if(q->ltype & TCHAR) {
+           static struct rspecial s[] = {
+               { NRES, R0L }, { NRES, R0H}, { 0 } };
+           return s;
+           }*/
+       break;
+
+    case MUL:
+       /*
+       if(q->ltype & (TINT|TSHORT)){
+           static struct rspecial s[] = {
+               { NRES, R0 }, { NRES, R2}, { 0 } };
+           return s;
+           }*/
+       comperr("multiplication not implemented");
+       break;
+       
+    default:
+       break;
+    }
+    comperr("nspecial entry %d", q - table);
+    return 0; /* XXX gcc */
+}
+
+
+/*
+ * Splitup a function call and give away its arguments first.
+ * Calling convention used ("normal" in IAR syntax) is:
+ * - 1-byte parameters in R0L if possible, otherwise in R0H.
+ * - 2-byte pointers in A0.
+ * - 2-byte non-pointers in R0 if no byte-size arguments are found in
+ *   in the first 6 bytes of parameters, otherwise R2 or at last A0.
+ * - 4-byte parameters in R2R0.
+ */
+void
+gencall(NODE *p, NODE *prev)
+{
+       NODE *n = 0; /* XXX gcc */
+       static int storearg(NODE *);
+       int o = p->n_op;
+       int ty = optype(o);
+
+       if (ty == LTYPE)
+               return;
+
+       switch (o) {
+       case CALL:
+               /* swap arguments on some hardop-converted insns */
+               /* Normal call, just push args and be done with it */
+               p->n_op = UCALL;
+//printf("call\n");
+               /* Check if left can be evaluated directly */
+               if (p->n_left->n_op == UMUL) {
+                       TWORD t = p->n_left->n_type;
+                       int k = (freetemp(szty(t)));
+                       NODE *n = mklnode(OREG, k, FB, t);
+                       NODE *q = tcopy(n);
+                       pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t)));
+                       p->n_left = q;
+               }
+               gencall(p->n_left, p);
+               p->n_rval = storearg(p->n_right);
+//printf("end call\n");
+               break;
+
+       case UFORTCALL:
+       case FORTCALL:
+               comperr("FORTCALL");
+
+       case USTCALL:
+       case STCALL:
+               /*
+                * Structure return.  Look at the node above
+                * to decide about buffer address:
+                * - FUNARG, allocate space on stack, don't remove.
+                * - nothing, allocate space on stack and remove.
+                * - STASG, get the address of the left side as arg.
+                * - FORCE, this ends up in a return, get supplied addr.
+                * (this is not pretty, but what to do?)
+                */
+               if (prev == NULL || prev->n_op == FUNARG) {
+                       /* Create nodes to generate stack space */
+                       n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
+                           mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
+                           mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
+//printf("stsize %d\n", p->n_stsize);
+                       pass2_compile(ipnode(n));
+               } else if (prev->n_op == STASG) {
+                       n = prev->n_left;
+                       if (n->n_op == UMUL)
+                               n = nfree(n);
+                       else if (n->n_op == NAME) {
+                               n->n_op = ICON; /* Constant reference */
+                               n->n_type = INCREF(n->n_type);
+                       } else
+                               comperr("gencall stasg");
+               } else if (prev->n_op == FORCE) {
+                       ; /* do nothing here */
+               } else {
+                       comperr("gencall bad op %d", prev->n_op);
+               }
+
+               /* Deal with standard arguments */
+               gencall(p->n_left, p);
+               if (o == STCALL) {
+                       p->n_op = USTCALL;
+                       p->n_rval = storearg(p->n_right);
+               } else
+                       p->n_rval = 0;
+               /* push return struct address */
+               if (prev == NULL || prev->n_op == FUNARG) {
+                       n = mklnode(REG, 0, STKREG, INT);
+                       if (p->n_rval)
+                               n = mkbinode(PLUS, n,
+                                   mklnode(ICON, p->n_rval, 0, INT), INT);
+                       pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+                       if (prev == NULL)
+                               p->n_rval += p->n_stsize/4;
+               } else if (prev->n_op == FORCE) {
+                       /* return value for this function */
+                       n = mklnode(OREG, 8, FPREG, INT);
+                       pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+                       p->n_rval++;
+               } else {
+                       pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+                       n = p;
+                       *prev = *p;
+                       nfree(n);
+               }
+//printf("end stcall\n");
+               break;
+
+       default:
+               if (ty != UTYPE)
+                       gencall(p->n_right, p);
+               gencall(p->n_left, p);
+               break;
+       }
+}
+
+/*
+ * Create separate node trees for function arguments.
+ * This is partly ticky, the strange calling convention 
+ * may cause a bunch of code reorganization here.
+ */
+static int
+storearg(NODE *p)
+{
+       NODE *n, *q, **narry;
+       int nch, k, i, nn, rary[4];
+       int r0l, r0h, r2, a0, stk, sz;
+       TWORD t;
+       int maxrargs = 0;
+
+       if (p->n_op == CM)
+               maxrargs = p->n_stalign;
+
+       /* count the arguments */
+       for (i = 1, q = p; q->n_op == CM; q = q->n_left)
+               i++;
+       nn = i;
+
+       /* allocate array to store arguments */
+       narry = tmpalloc(sizeof(NODE *)*nn);
+
+       /* enter nodes into array */
+       for (q = p; q->n_op == CM; q = q->n_left)
+               narry[--i] = q->n_right;
+       narry[--i] = q;
+
+       /* free CM nodes */
+       for (q = p; q->n_op == CM; ) {
+               n = q->n_left;
+               nfree(q);
+               q = n;
+       }
+
+       /* count char args */
+       r0l = r0h = r2 = a0 = 0;
+       for (sz = nch = i = 0; i < nn && i < 6; i++) {
+               TWORD t = narry[i]->n_type;
+               if (sz >= 6)
+                       break;
+               if (t == CHAR || t == UCHAR) {
+                       nch++;
+                       sz++;
+               } else if ((t >= SHORT && t <= UNSIGNED) ||
+                   t > BTMASK || t == FLOAT) {
+                       sz += 2;
+               } else /* long, double */
+                       sz += 4;
+                       
+       }
+
+       /*
+        * Now the tricky part. The parameters that should be on stack
+        * must be found and pushed first, then the register parameters.
+        * For the latter, be sure that evaluating them do not use any
+        * registers where argument values already are inserted.
+        * XXX - function pointers?
+        * XXX foo(long a, char b) ???
+        */
+       for (stk = 0; stk < 4; stk++) {
+               TWORD t;
+
+               if (stk == nn)
+                       break;
+               t = narry[stk]->n_type;
+               if (ISFTN(DECREF(t)))
+                       t = LONG;
+               switch (t) {
+               case CHAR: case UCHAR:
+                       if (r0l) {
+                               if (r0h)
+                                       break;
+                               rary[stk] = R2; /* char talk for 'R0H' */
+                               r0h = 1;
+                       } else {
+                               rary[stk] = R0;
+                               r0l = 1;
+                       }
+                       continue;
+
+               case INT: case UNSIGNED:
+                       if (r0l || nch) {
+                               if (r2) {
+                                       if (a0)
+                                               break;
+                                       rary[stk] = A0;
+                                       a0 = 1;
+                               } else {
+                                       rary[stk] = R2;
+                                       r2 = 1;
+                               }
+                       } else {
+                               rary[stk] = R0;
+                               r0l = r0h = 1;
+                       }
+                       continue;
+
+               case LONG: case ULONG:
+                       if (r0l || r2)
+                               break;
+                       rary[stk] = R0;
+                       r0l = r0h = r2 = 1;
+                       continue;
+
+               default:
+                       if (ISPTR(narry[stk]->n_type) &&
+                           !ISFTN(DECREF(narry[stk]->n_type))) {
+                               if (a0) {
+                                       if (r0l || nch) {
+                                               if (r2)
+                                                       break;
+                                               rary[stk] = R2;
+                                               r2 = 1;
+                                       } else {
+                                               rary[stk] = R0;
+                                               r0l = r0h = 1;
+                                       }
+                               } else {
+                                       rary[stk] = A0;
+                                       a0 = 1;
+                               }
+                               continue;
+                       }
+                       break;
+               }
+               break;
+       }
+
+       /*
+        * The arguments that must be on stack are stk->nn args.
+        * Argument 0->stk-1 should be put in the rary[] register.
+        */
+       for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */
+               NODE nod;
+               pass2_compile(ipnode(mkunode(FUNARG,
+                   narry[i], 0, narry[i]->n_type)));
+               nod.n_type = narry[i]->n_type;
+               sz += tlen(&nod);
+       }
+       /* if param cannot be addressed directly, evaluate and put on stack */
+       for (i = 0; i < stk; i++) {
+
+               if (canaddr(narry[i]))
+                       continue;
+               t = narry[i]->n_type;
+               k = (freetemp(szty(t)));
+               n = mklnode(OREG, k, FB, t);
+               q = tcopy(n);
+               pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t)));
+               narry[i] = q;
+       }
+       /* move args to registers */
+       for (i = 0; i < stk; i++) {
+               t = narry[i]->n_type;
+               pass2_compile(ipnode(mkbinode(ASSIGN, 
+                   mklnode(REG, 0, rary[i], t), narry[i], t)));
+       }
+       return sz;
+}
+
+/*
+ * Tell if a register can hold a specific datatype.
+ */
+#if 0
+int
+mayuse(int reg, TWORD type)
+{
+       return 1;  /* Everything is OK */
+}
+#endif
+
+#ifdef TAILCALL
+void
+mktailopt(struct interpass *ip1, struct interpass *ip2)
+{
+       extern int earlylab;
+       extern char *cftname;
+       char *fn;
+       NODE *p;
+
+       p = ip1->ip_node->n_left->n_left;
+       if (p->n_op == ICON) {
+               fn = p->n_name;
+               /* calling ourselves */
+               p = ip1->ip_node->n_left;
+               if (p->n_op == CALL) {
+                       if (storearg(p->n_right))
+                               comperr("too many args: fix mktailopt");
+                       p->n_op = UCALL;
+               }
+               tfree(ip1->ip_node);
+               p = ip2->ip_node->n_left;
+               if (strcmp(fn, cftname)) {
+                       /* Not us, must generate fake prologue */
+                       ip1->type = IP_ASM;
+                       ip1->ip_asm = "\tmov.w FB,SP\n\tpop.w FB\n";
+                       pass2_compile(ip1);
+                       p->n_lval = p->n_rval = 0;
+                       p->n_name = fn;
+               } else
+                       p->n_lval = earlylab;
+       } else {
+               pass2_compile(ip1);
+       }
+       pass2_compile(ip2);
+}
+#endif
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[1] = { -1 }; /* Terminate with -1 */
+
+       return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/m16c/table.c b/lang/pcc/pcc/arch/m16c/table.c
new file mode 100644 (file)
index 0000000..e8f186e
--- /dev/null
@@ -0,0 +1,589 @@
+/*     $Id: table.c,v 1.35 2011/06/05 08:54:42 plunky Exp $    */
+
+#include "pass2.h"
+
+# define ANYSIGNED TINT|TLONG|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TL TLONG|TULONG
+# define TWORD TUNSIGNED|TINT
+# define TCH TCHAR|TUCHAR
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* (signed) char -> int/pointer */
+{ SCONV,       INAREG,
+       SCREG,          TCHAR,
+       SANY,           TINT|TPOINT,
+               NAREG,  RESC1,
+               "       mov.b AL, A1\n\texts.b A1\n", },
+
+/* (unsigned) char -> int/pointer */
+{ SCONV,       INAREG,
+       SCREG,          TUCHAR,
+       SANY,           TINT|TPOINT,
+               NAREG,  RESC1,
+               "       mov.b AL, A1\n", },
+    
+/* unsigned char -> long */
+{ SCONV,       INAREG,
+       SCREG,          TUCHAR,
+       SANY,           TL,
+               NAREG|NASL,     RESC1,
+               "       mov.b AL, A1\n  mov.w #0,U1\n", },
+
+/* int or pointer -> (unsigned) long */
+{ SCONV,       INAREG,
+       SAREG|SNAME,    TWORD|TPOINT,
+       SANY,                   TL,
+               NAREG|NASL,     RESC1,
+               "       mov.w AL,A1\n   mov.w #0,U1\n", },
+
+/* char -> (signed) long */
+{ SCONV,       INAREG,
+       SAREG|SNAME,    TCHAR,
+       SANY,                   TLONG,
+               NAREG|NASL,     RESC1,
+               "       exts.b AL\n     exts.w AL\n", },
+
+/* long -> ulong */
+{ SCONV,       INAREG,
+       SAREG,          TL,
+       SANY,                   TL,
+               0,      RLEFT,
+       "", },
+
+/* long -> int or pointer */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SNAME,      TL,
+       SANY,                   TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       mov.w AL,A1\n", },
+
+/* int -> char */
+{ SCONV,       INCREG,
+       SAREG,          TWORD,
+       SANY,           TCH,
+               NCREG,  RESC1,
+               "       mov.b AL, A1\n", },
+
+/* int -> long */
+{ SCONV,       INAREG,
+       SAREG,          TWORD,
+       SANY,           TLONG,
+               NAREG|NASL,     RESC1,
+               "       exts.w AL", },
+
+/* long -> char */
+{ SCONV,       INAREG,
+       SAREG,          TL,
+       SANY,           TCH,
+               NAREG|NASL,     RESC1,
+               "", },
+
+{ SCONV,       INAREG,
+       SAREG,          TPOINT,
+       SANY,           TWORD,
+               0,      RLEFT,
+               "", },
+
+{ PLUS,        INAREG|FOREFF,
+       SAREG,  TL,
+       SCON|SNAME|SOREG,       TL,
+               0,      RLEFT,
+               "       add.w AR,AL\n   adc.w UR,UL\n", },
+
+{ MINUS,       INAREG|FOREFF,
+       SAREG,  TL,
+       SCON|SNAME|SOREG,       TL,
+               0,      RLEFT,
+               "       sub.w AR,AL\n   sbb.w UR,UL\n", },
+
+{ AND,         INAREG|FOREFF,
+       SAREG,                  TL,
+       SAREG|SNAME|SOREG,      TL,
+               0,      RLEFT,
+               "       and.w AR,AL\n   and.w UR,UL\n", },
+
+{ ER,          INAREG|FOREFF,
+       SAREG,                  TL,
+       SAREG|SNAME|SOREG,      TL,
+               0,      RLEFT,
+               "       xor.w AR,AL\n   xor.w UR,UL\n", },
+
+{ OR,          INAREG|FOREFF,
+       SAREG,                  TL,
+       SAREG|SNAME|SOREG,      TL,
+               0,      RLEFT,
+               "       xor.w AR,AL\n   xor.w UR,UL\n", },
+
+{ COMPL,       INAREG|FOREFF,
+       SAREG,                  TL,
+       SAREG|SNAME|SOREG,      TL,
+               0,      RLEFT,
+               "       not.w AR,AL\n   not.w UR,UL\n", },
+       
+{ OPSIMP,      INAREG|FOREFF,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+               0,      RLEFT,
+               "       Ow AR,AL\n", },
+
+/* XXX - Is this rule really correct? Having a SAREG shape seems kind of
+   strange. Doesn't work. Gives a areg as A1. */
+#if 0  
+{ OPSIMP,      INBREG,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SBREG|SNAME|SOREG|SCON,   TWORD|TPOINT,
+               NBREG,  RESC1,
+               "       ++Ow AR,A1\n", },
+#endif
+       
+{ OPSIMP,      INBREG,
+       SBREG,                  TWORD|TPOINT,
+       SAREG|SBREG|SNAME|SOREG|SCON,   TWORD|TPOINT,
+               0,      RLEFT,
+               "       Ow AR,AL\n", },
+       
+{ OPSIMP,      INCREG|FOREFF,
+       SCREG,                  TCH,
+       SCREG|SNAME|SOREG|SCON, TCH,
+               0,      RLEFT,
+               "       Ob AR,AL\n", },
+       
+/* XXX - Do these work? check nspecial in order.c */
+/* signed integer division */
+{ DIV,         INAREG,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TWORD,
+         /*2*NAREG|NASL|*/NSPECIAL,            RLEFT,
+               "       div.w AR\n      mov.w r0,AL\n", },
+      //               "       xor.w r2\n      div.w AR\n", },
+
+
+/* signed integer/char division - separate entry for FOREFF */
+{ DIV,         FOREFF,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TWORD,
+               0,              0,
+               "", },
+
+#if 0
+/* signed char division */
+{ DIV,         INCREG,
+       SCREG,                  TCHAR,
+       SCREG|SNAME|SOREG,      TCH,
+               2*NCREG|NCSL|NSPECIAL,          RLEFT,
+               "       div.b AR\n\tmov.b r0l,AL\n", },
+      //               "       xor.w r2\n      div.w AR\n", },
+#endif
+       
+/* signed integer modulus, equal to above */
+{ MOD,         INAREG,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TWORD,
+         /*2*NAREG|NASL|*/NSPECIAL,            RLEFT,
+               "       div.w AR\n\tmov r2,AL\n", },
+
+/* signed integer modulus - separate entry for FOREFF */
+{ MOD,         FOREFF,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TWORD,
+               0,              0,
+               "", },
+
+/* signed integer multiplication */
+{ MUL,         INAREG,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TWORD,
+               2*NAREG|NASL|NSPECIAL,          RESC1,
+               "       mul.w AL,AR\n", },
+
+{ MUL,         FOREFF,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TWORD,
+               0,      0,
+               "", },
+
+#if 0
+{ LS,          INAREG,
+       SAREG,  TWORD,
+       SCON,           TANY,
+               0,      RLEFT,
+               "       shl.w AR,AL\n", },
+#endif
+
+{ LS,          INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "       push.b r1h\n"
+               "       mov.b AR,r1h\n"
+               "       shl.w r1h,AL\n"
+               "       pop.b r1h\n", },
+
+{ LS,          INAREG,
+       SAREG,  TL,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "       push.b r1h\n"
+               "       mov.b AR,r1h\n"
+               "       shl.l r1h,ZG\n"
+               "       pop.b r1h\n", },
+
+{ RS,          INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "       push.b r1h\n"
+               "       mov.b AR,r1h\n"
+               "       neg.b r1h\n"
+               "       shl.w r1h,AL\n"
+               "       pop.b r1h\n", },
+
+{ RS,          INAREG,
+       SAREG,  TL,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "       push.b r1h\n"
+               "       mov.b AR,r1h\n"
+               "       neg.b r1h\n"
+               "       shl.l r1h,ZG\n"
+               "       pop.b r1h\n", },
+
+#if 0
+{ RS,          INAREG,
+       SAREG,  TUNSIGNED,
+       SCON,           TANY,
+               0,      RLEFT,
+               "       shl ZA,AL\n", },
+
+{ RS,          INAREG,
+       SAREG,  TINT,
+       SCON,           TANY,
+               0,      RLEFT,
+               "       sha ZA,AL\n", },
+#endif
+
+{ OPLOG,       FORCC,
+       SAREG|SBREG|SOREG|SNAME,        TL,
+       SAREG|SBREG|SOREG|SNAME,        TL,
+               0,      0,
+               "ZF", },
+
+{ OPLOG,       FORCC,
+       SBREG|SOREG,    TWORD|TPOINT,
+       SCON,                   TWORD|TPOINT,
+               0,      RESCC,
+               "       cmp.w AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SBREG|SOREG|SNAME,        TWORD|TPOINT,
+       SAREG|SBREG|SOREG|SNAME,        TWORD|TPOINT,
+               0,      RESCC,
+               "       cmp.w AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SCREG|SOREG|SNAME,      TCH,
+       SCREG|SOREG|SNAME,      TCH,
+               0,      RESCC,
+               "       cmp.b AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SCREG|SOREG|SNAME,      TCH,
+       SCREG|SOREG|SNAME,      TCH,
+               0,      RESCC,
+               "       cmp.b AR,AL\n", },
+
+{ GOTO,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp.w ZC\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON|SNAME|SOREG|SAREG, TL|TFTN,
+               NAREG,  RESC1,
+               "       mov.w AR,A1\n   mov.w UR,U1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON|SNAME|SOREG|SAREG|SBREG,   TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       mov.w AR,A1\n", },      
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SBREG|SCON|SNAME|SOREG|SAREG,   TWORD|TPOINT,
+               NBREG,  RESC1,
+               "       mov.w AR,A1\n", },      
+    /*
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SCON|SNAME|SOREG,       TCH,
+               NAREG,  RESC1,
+               "       mov.b AR, A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,                   TANY,
+       SCON|SNAME|SOREG,       TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "       mov.b AR,A1\n", },
+    */
+    
+{ OPLTYPE,     INCREG,
+       SANY,                   TANY,
+       SCON|SNAME|SOREG,       TCHAR|TUCHAR,
+               NCREG,  RESC1,
+               "       mov.b AR,A1\n", },
+    
+{ COMPL,       INAREG,
+       SAREG,  TWORD,
+       SANY,           TANY,
+               0,      RLEFT,
+               "       not.w AL\n", },
+
+{ COMPL,       INCREG,
+       SCREG,  TCH,
+       SANY,           TANY,
+               0,      RLEFT,
+               "       not.b AL\n", },
+       
+/* Push function address */
+{ FUNARG,      FOREFF,
+       SCON,   TFTN,
+       SANY,   TANY,
+               0,      RNULL,
+               "ZH", },
+
+{ FUNARG,      FOREFF,
+       SOREG,  TFTN,
+       SANY,   TANY,
+               0,      RNULL,
+               "ZI", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SAREG,    TL|TFTN,
+       SANY,   TANY,
+               0,      RNULL,
+               "       push.w UL\n     push.w AL\n", },
+
+{ FUNARG,      FOREFF,
+       SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+       SANY,                   TANY,
+               0,      RNULL,
+               "       push.w AL\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SANY,                           TANY,
+               0,      RNULL,
+               "       push.b AL\n", },
+
+/* Match function pointers first */
+#if 0
+{ ASSIGN,      FOREFF,
+       SFTN,   TWORD|TPOINT,
+       SFTN,   TWORD|TPOINT,
+               NAREG,  0,
+               "ZD", },
+#endif
+
+{ ASSIGN,      INAREG,
+       SAREG,  TFTN,
+       SCON,   TFTN,
+               0,      RLEFT,
+               "ZD", },
+    
+{ ASSIGN,      INBREG,
+       SBREG,  TFTN,
+       SCON,   TFTN,
+               0,      RLEFT,
+               "ZD", },
+
+{ ASSIGN,      INAREG,
+       SAREG,  TFTN,
+       SBREG|SAREG|SOREG|SNAME,        TFTN,
+               0,      RLEFT,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+
+{ ASSIGN,      INBREG,
+       SBREG,  TFTN,
+       SBREG|SAREG|SOREG|SNAME,        TFTN,
+               0,      RLEFT,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+    
+{ ASSIGN,      INAREG,
+       SBREG|SAREG|SOREG|SNAME,        TFTN,
+       SAREG,  TFTN,
+               0,      RRIGHT,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+
+{ ASSIGN,      INBREG,
+       SBREG|SAREG|SOREG|SNAME,        TFTN,
+       SBREG,  TFTN,
+               0,      RRIGHT,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+
+/* a reg -> a reg */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "       mov.w AR,AL\n", },
+
+{ ASSIGN,      INAREG,
+       SBREG|SAREG|SOREG|SNAME,        TL,
+       SAREG,  TL,
+               0,      RRIGHT,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+
+{ ASSIGN,      INBREG,
+       SBREG|SAREG|SOREG|SNAME,        TL,
+       SBREG,  TL,
+               0,      RRIGHT,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+    
+{ ASSIGN,      FOREFF,
+       SBREG|SAREG|SOREG|SNAME,        TL,
+       SCON|SBREG|SAREG|SOREG|SNAME,   TL,
+               0,      0,
+               "       mov.w AR,AL\n   mov.w UR,UL\n", },
+
+{ ASSIGN,      INAREG|FOREFF,
+       SAREG,  TWORD|TPOINT,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       mov.w AR,AL\n", },
+
+{ ASSIGN,      INBREG|FOREFF,
+       SBREG,  TWORD|TPOINT,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       mov.w AR,AL\n", },
+    
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TWORD|TPOINT,
+       SCON,           TANY,
+               0,      0,
+               "       mov.w AR,AL\n", },
+
+/* char, oreg/name -> c reg */
+{ ASSIGN,      FOREFF|INCREG,
+       SCREG,  TCHAR|TUCHAR,
+       SOREG|SNAME|SCON,       TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       mov.b AR,AL\n", },
+
+/* int, oreg/name -> a reg */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SOREG|SNAME,    TWORD|TPOINT,
+               0,      RLEFT,
+               "       mov.w AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,  TWORD|TPOINT,
+       SOREG|SNAME,    TWORD|TPOINT,
+               0,      RLEFT,
+               "       mov.w AR,AL\n", },
+    
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RRIGHT,
+               "       mov.w AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG|SNAME,    TWORD|TPOINT,
+       SBREG,  TWORD|TPOINT,
+               0,      RRIGHT,
+               "       mov.w AR,AL\n", },
+    
+{ ASSIGN,      FOREFF|INCREG,
+       SOREG|SNAME,    TCHAR|TUCHAR,
+       SCREG,  TCHAR|TUCHAR,
+               0,      RRIGHT,
+               "       mov.b AR,AL\n", },
+
+{ ASSIGN,       FOREFF|INCREG,
+        SCREG,    TCHAR|TUCHAR,
+        SCREG,  TCHAR|TUCHAR,
+                0,      RRIGHT,
+                "      mov.b AR,AL\n", },
+
+{ ASSIGN,       FOREFF|INBREG,
+        SBREG,    TWORD|TPOINT,
+        SBREG,  TWORD|TPOINT,
+                0,      RRIGHT,
+                "      mov.w AR,AL\n", },
+       
+{ UMUL,        INAREG,
+       SBREG,  TPOINT|TWORD,
+       SANY,   TFTN,
+               NAREG,  RESC1,
+               "       mov.w [AL],A1\n mov.w 2[AL],U1\n", },
+
+{ UMUL,        INAREG,
+       SBREG,  TPOINT|TWORD,
+       SANY,   TPOINT|TWORD,
+               NAREG,  RESC1,
+               "       mov.w [AL],A1\n", },
+
+{ UMUL,        INBREG,
+       SBREG,  TPOINT|TWORD,
+       SANY,   TPOINT|TWORD,
+               NBREG|NBSL,     RESC1,
+               "       mov.w [AL],A1\n", },
+
+{ UMUL,                INAREG,
+       SBREG,  TCHAR|TUCHAR|TPTRTO,
+       SANY,   TCHAR|TUCHAR,
+               NAREG,  RESC1,
+               "       mov.b [AL], A1\n", },
+    
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       jsr.w CL\nZB", },
+    
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG,  RESC1,
+               "       jsr.w CL\nZB", },
+
+{ UCALL,        INAREG,
+       SNAME|SOREG,    TANY,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       jsri.a AL\nZB", },
+
+{ UCALL,        FOREFF,
+       SNAME|SOREG,    TANY,
+       SANY,           TANY,
+               0,     0,  
+               "       jsri.a AL\nZB", },
+    
+{ UCALL,        INAREG,
+       SBREG,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       jsri.a [AL]\nZB", },
+
+{ UCALL,        FOREFF,
+       SBREG,   TANY,
+       SANY,   TANY,
+               0,     0,
+               "       jsri.a [AL]\nZB", },
+
+    
+{ FREE, FREE,  FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
+
diff --git a/lang/pcc/pcc/arch/m68k/code.c b/lang/pcc/pcc/arch/m68k/code.c
new file mode 100644 (file)
index 0000000..bb1f8f1
--- /dev/null
@@ -0,0 +1,296 @@
+/*     $Id: code.c,v 1.8 2016/01/30 17:26:19 ragge Exp $       */
+/*
+ * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+#ifdef LANG_CXX
+#define p1listf listf
+#define p1tfree tfree
+#else
+#define NODE P1ND
+#define talloc p1alloc
+#define tfree p1tfree
+#endif
+
+extern int gotnr;
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+       case UDATA: break;
+       case PICLDATA:
+       case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
+       case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
+       case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       name = getexname(sp);
+       if (sp->sclass == EXTDEF) {
+               printf("\t.globl %s\n", name);
+               if (ISFTN(sp->stype)) {
+                       printf("\t.type %s,@function\n", name);
+               } else {
+                       printf("\t.type %s,@object\n", name);
+                       printf("\t.size %s,%d\n", name,
+                           (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
+               }
+       }
+       if (sp->slevel == 0)
+               printf("%s:\n", name);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ * The return value is in (or pointed to by) RETREG.
+ */
+int sttemp;
+
+void
+efcode(void)
+{
+       NODE *p, *q;
+
+       gotnr = 0;
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+       /* use stasg to get call to memcpy() */
+       p = buildtree(UMUL, tempnode(sttemp, INCREF(STRTY),
+           cftnsp->sdf, cftnsp->sap), NIL);
+       q = block(REG, 0, 0, INCREF(STRTY), cftnsp->sdf, cftnsp->sap);
+       regno(q) = A0;
+       q = buildtree(UMUL, q, NIL);
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **s, int cnt)
+{
+       struct symtab *sp2;
+       NODE *n, *p;
+       int i;
+
+       if (kflag) { /* PIC code */
+               /* Generate extended assembler for PIC prolog */
+               p = tempnode(0, CHAR|PTR, 0, 0);
+               gotnr = regno(p);
+               p = block(XARG, p, NIL, INT, 0, 0);
+               p->n_name = "=r";
+               p = block(XASM, p, bcon(0), INT, 0, 0);
+
+               p->n_name = "lea (%%pc,_GLOBAL_OFFSET_TABLE_@GOTPC),%0\n";
+               p->n_right->n_type = STRTY;
+               ecomp(p);
+       }
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               n = tempnode(0, INCREF(CHAR), 0, 0);
+               p = block(REG, 0, 0, INCREF(CHAR), 0, 0);
+               regno(p) = A0;
+               sttemp = regno(n);
+               ecomp(buildtree(ASSIGN, n, p));
+       }
+
+       if (xtemps == 0)
+               return;
+
+        /* put arguments in temporaries */
+        for (i = 0; i < cnt; i++) {
+                if (s[i]->stype == STRTY || s[i]->stype == UNIONTY ||
+                    cisreg(s[i]->stype) == 0)
+                        continue;
+                if (cqual(s[i]->stype, s[i]->squal) & VOL)
+                        continue;
+                sp2 = s[i];
+                n = tempnode(0, s[i]->stype, s[i]->sdf, s[i]->sap);
+                n = buildtree(ASSIGN, n, nametree(sp2));
+                s[i]->soffset = regno(n->n_left);
+                s[i]->sflags |= STNODE;
+                ecomp(n);
+        }
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+       if (flag)
+               return;
+
+       printf("\t.ident \"PCC: %s\"\n", VERSSTR);
+}
+
+void
+bjobcode(void)
+{
+       /* Set correct names for our types */
+       astypnames[SHORT] = astypnames[USHORT] = "\t.word";
+       astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
+ */
+NODE *
+funcode(NODE *p)
+{
+       NODE *r, *l;
+
+       /* Fix function call arguments. On m68k, just add funarg */
+       for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+               if (r->n_right->n_op != STARG) {
+                       r->n_right = intprom(r->n_right);
+                       r->n_right = block(FUNARG, r->n_right, NIL,
+                           r->n_right->n_type, r->n_right->n_df,
+                           r->n_right->n_ap);
+               }
+       }
+       if (r->n_op != STARG) {
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_left = intprom(r->n_left);
+               r->n_type = r->n_left->n_type;
+       }
+       return p;
+
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+/*
+ * Return return as given by a.
+ */
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+cerror((char *)__func__);
+       nframes = glval(a);
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+
+       f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
+       f = buildtree(UMUL, f, NIL);
+
+       return f;
+}
+
+/*
+ * Return frame as given by a.
+ */
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+cerror((char *)__func__);
+       nframes = glval(a);
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--)
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+
+       return f;
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+
+cerror((char *)__func__);
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = FPREG;
+       return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0);
+}
diff --git a/lang/pcc/pcc/arch/m68k/local.c b/lang/pcc/pcc/arch/m68k/local.c
new file mode 100644 (file)
index 0000000..8a93c58
--- /dev/null
@@ -0,0 +1,562 @@
+/*     $Id: local.c,v 1.16 2016/01/30 17:26:19 ragge Exp $     */
+/*
+ * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#undef NIL
+#define NIL NULL
+
+#ifdef LANG_CXX
+#define P1ND NODE
+#define p1nfree nfree
+#define p1fwalk fwalk
+#define p1tcopy tcopy
+#define p1alloc talloc
+#else
+#define        NODE P1ND
+#define        nfree p1nfree
+#define        fwalk p1fwalk
+#endif
+
+
+/*     this file contains code which is dependent on the target machine */
+
+int gotnr;
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+       struct symtab *sp = permalloc(sizeof(struct symtab));
+       size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+       
+       sp->sname = permalloc(len);
+       strlcpy(sp->sname, p, len);
+       strlcat(sp->sname, s, len);
+       strlcat(sp->sname, s2, len);
+       sp->sap = attr_new(ATTR_SONAME, 1);
+       sp->sap->sarg(0) = sp->sname;
+       sp->sclass = EXTERN;
+       sp->sflags = sp->slevel = 0;
+       sp->stype = 0xdeadbeef;
+       return sp;
+}
+
+/*
+ * Create a reference for an extern variable.
+ */
+static NODE *
+picext(NODE *p)
+{
+       NODE *q, *r;
+       struct symtab *sp;
+       char *name;
+
+       q = tempnode(gotnr, PTR|VOID, 0, 0);
+       name = getexname(p->n_sp);
+
+#ifdef notdef
+       struct attr *ga;
+       if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) &&
+           strcmp(ga->sarg(0), "hidden") == 0) {
+               /* For hidden vars use GOTOFF */
+               sp = picsymtab("", name, "@GOTOFF");
+               r = xbcon(0, sp, INT);
+               q = buildtree(PLUS, q, r);
+               q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+               q->n_sp = p->n_sp; /* for init */
+               nfree(p);
+               return q;
+       }
+#endif
+
+       sp = picsymtab("", name, "@GOT");
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, PTR|VOID, 0, 0);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       nfree(p);
+       return q;
+}
+
+static char *
+getsoname(struct symtab *sp)
+{
+       struct attr *ap;
+       return (ap = attr_find(sp->sap, ATTR_SONAME)) ?
+           ap->sarg(0) : sp->sname;
+       
+}
+
+
+static NODE *
+picstatic(NODE *p)
+{
+       NODE *q, *r;
+       struct symtab *sp;
+
+       q = tempnode(gotnr, PTR|VOID, 0, 0);
+       if (p->n_sp->slevel > 0) {
+               char buf[32];
+               if ((p->n_sp->sflags & SMASK) == SSTRING)
+                       p->n_sp->sflags |= SASG;
+               snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
+               sp = picsymtab("", buf, "@GOT");
+       } else {
+               sp = picsymtab("", getsoname(p->n_sp), "@GOT");
+       }
+       
+       sp->sclass = STATIC;
+       sp->stype = p->n_sp->stype;
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, PTR|VOID, 0, 0);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       nfree(p);
+       return q;
+}
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+       register struct symtab *q;
+       register NODE *r, *l;
+       register int o;
+       TWORD t;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       slval(r, 0);
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       slval(p, 0);
+                       p->n_rval = q->soffset;
+                       break;
+
+               case USTATIC:
+               case STATIC:
+                       if (kflag == 0)
+                               break;
+                       if (blevel > 0 && !statinit)
+                               p = picstatic(p);
+                       break;
+
+               case EXTERN:
+               case EXTDEF:
+                       if (kflag == 0)
+                               break;
+                       if (blevel > 0 && !statinit)
+                               p = picext(p);
+                       break;
+               }
+               break;
+
+       case ADDROF:
+               if (kflag == 0 || blevel == 0 || statinit)
+                       break;
+               /* char arrays may end up here */
+               l = p->n_left;
+               if (l->n_op != NAME ||
+                   (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
+                       break;
+               l = p;
+               p = picstatic(p->n_left);
+               nfree(l);
+               if (p->n_op != UMUL)
+                       cerror("ADDROF error");
+               l = p;
+               p = p->n_left;
+               nfree(l);
+               break;
+
+       case STASG: /* convert struct assignment to call memcpy */
+               l = p->n_left;
+               if (l->n_op == NAME && ISFTN(l->n_sp->stype))
+                       break; /* struct return, do nothing */
+               /* first construct arg list */
+               p->n_left = buildtree(ADDROF, p->n_left, 0);
+               r = bcon(tsize(STRTY, p->n_df, p->n_ap)/SZCHAR);
+               p->n_left = buildtree(CM, p->n_left, p->n_right);
+               p->n_right = r;
+               p->n_op = CM;
+               p->n_type = INT;
+
+               r = block(NAME, NIL, NIL, INT, 0, 0);
+               r->n_sp = lookup(addname("memcpy"), SNORMAL);
+               if (r->n_sp->sclass == SNULL) {
+                       r->n_sp->sclass = EXTERN;
+                       r->n_sp->stype = INCREF(VOID+PTR)+(FTN-PTR);
+               }
+               r->n_type = r->n_sp->stype;
+               p = buildtree(CALL, r, p);
+               break;
+
+       case SCONV:
+               l = p->n_left;
+               if (l->n_op == ICON && ISPTR(l->n_type)) {
+                       /* Do immediate cast here */
+                       /* Should be common code */
+                       q = l->n_sp;
+                       l->n_sp = NULL;
+                       l->n_type = UNSIGNED;
+                       if (concast(l, p->n_type) == 0)
+                               cerror("clocal");
+                       p = nfree(p);
+                       p->n_sp = q;
+               }
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               t = p->n_type;
+               if (ISITY(t))
+                       t = t - (FIMAG-FLOAT);
+               p->n_left->n_rval = RETREG(t);
+               break;
+       }
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+#define IALLOC(sz)     (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+       NODE *l;
+
+       if (cdope(p->n_op) & CALLFLG) {
+               if (p->n_left->n_op == ADDROF &&
+                   p->n_left->n_left->n_op == NAME) {
+                       p->n_left = nfree(p->n_left);
+                       l = p->n_left;
+                       l->n_op = ICON;
+                       if (l->n_sp->sclass != STATIC &&
+                           l->n_sp->sclass != USTATIC)
+                               l->n_sp =
+                                   picsymtab(l->n_sp->sname, "@PLTPC", "");
+               }
+       }
+
+       if (p->n_op != FCON)
+               return;
+
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+       sp->sname = NULL;
+
+       locctr(DATA, sp);
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       slval(p, 0);
+       p->n_sp = sp;
+
+}
+
+/*
+ * Convert ADDROF NAME to ICON?
+ */
+int
+andable(NODE *p)
+{
+#ifdef notdef
+       /* shared libraries cannot have direct referenced static syms */
+       if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC)
+               return 1;
+#endif
+       return 1;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       return 1;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR));
+       p = buildtree(PLUS, p, bcon(30));
+       p = buildtree(AND, p, xbcon(-16, NULL, UNSIGNED));
+       p = cast(p, UNSIGNED, 0);
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, UNSIGNED+PTR, 0, 0);
+       slval(sp, 0);
+       sp->n_rval = STKREG;
+       p = (buildtree(MINUSEQ, sp, p));
+       ecomp(p);
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+UNSIGNED, t->n_df, t->n_ap);
+       slval(sp, 0);
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       p = (buildtree(ASSIGN, t, sp)); /* Emit! */
+       ecomp(p);
+
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+
+       switch (p->n_type) {
+       case LDOUBLE:
+               u.i[2] = 0;
+               u.l = (long double)((union flt *)p->n_dcon)->fp;
+#if defined(HOST_LITTLE_ENDIAN)
+               /* XXX probably broken on most hosts */
+               printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
+#else
+               printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+#endif
+               break;
+       case DOUBLE:
+               u.d = (double)((union flt *)p->n_dcon)->fp;
+#if defined(HOST_LITTLE_ENDIAN)
+               printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
+               printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+#endif
+               break;
+       case FLOAT:
+               u.f = (float)((union flt *)p->n_dcon)->fp;
+               printf("\t.long\t0x%x\n", u.i[0]);
+               break;
+
+       case LONGLONG:
+       case ULONGLONG:
+               printf("\t.long\t0x%x\n", (int)(off >> 32) & 0xffffffff);
+               printf("\t.long\t0x%x\n", (int)(off) & 0xffffffff);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+       return (p == NULL ? "" : p);
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+
+       }
+       return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off, al;
+       char *name;
+
+       name = getexname(sp);
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+       al = talign(sp->stype, sp->sap)/SZCHAR;
+
+       if (sp->sclass == STATIC) {
+               if (sp->slevel == 0) {
+                       printf("\t.local %s\n", name);
+               } else
+                       printf("\t.local " LABFMT "\n", sp->soffset);
+       }
+       if (sp->slevel == 0) {
+               printf("\t.comm %s,0%o,%d\n", name, off, al);
+       } else
+               printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+}
+
+char *nextsect;
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+       struct attr *ga;
+
+#ifdef HAVE_WEAKREF
+       /* not many as'es have this directive */
+       if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
+               char *wr = ga->sarg(0);
+               char *sn = getsoname(sp);
+               if (wr == NULL) {
+                       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) {
+                               wr = ga->sarg(0);
+                       }
+               }
+               if (wr == NULL)
+                       printf("\t.weak %s\n", sn);
+               else
+                       printf("\t.weakref %s,%s\n", sn, wr);
+       } else
+              if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
+               char *an = ga->sarg(0);
+               char *sn = getsoname(sp);
+               char *v;
+
+               v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
+               printf("\t.%s %s\n", v, sn);
+               printf("\t.set %s,%s\n", sn, an);
+       }
+       if (alias != NULL && (sp->sclass != PARAM)) {
+               char *name = getexname(sp);
+               printf("\t.globl %s\n", name);
+               printf("%s = ", name);
+               printf("%s\n", exname(alias));
+               alias = NULL;
+       }
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+               NODE *p = p1alloc();
+
+               p->n_op = NAME;
+               p->n_sp =
+                 (struct symtab *)(constructor ? "constructor" : "destructor");
+               sp->sap = attr_add(sp->sap, gcc_attr_parse(p));
+               constructor = destructor = 0;
+       }
+#endif
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/m68k/local2.c b/lang/pcc/pcc/arch/m68k/local2.c
new file mode 100644 (file)
index 0000000..813b3f2
--- /dev/null
@@ -0,0 +1,815 @@
+/*     $Id: local2.c,v 1.17 2016/01/30 17:26:19 ragge Exp $    */
+/*
+ * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+static int stkpos;
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static int regm, regf, fpsub, nfp;
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int i;
+
+       /*
+        * Subtract both space for automatics and permanent regs.
+        * XXX - no struct return yet.
+        */
+
+       fpsub = p2maxautooff;
+       if (fpsub >= AUTOINIT/SZCHAR)
+               fpsub -= AUTOINIT/SZCHAR;
+       regm = regf = nfp = 0;
+       for (i = 0; i < MAXREGS; i++)
+               if (TESTBIT(ipp->ipp_regs, i)) {
+                       if (i <= A7) {
+                               regm |= (1 << i);
+                               fpsub += 4;
+                       } else if (i >= FP0) {
+                               regf |= (1 << (i - FP0));
+                               fpsub += 12;
+                               nfp += 12;
+                       } else
+                               comperr("bad reg range");
+               }
+       printf("        link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub);
+       if (regm)
+               printf("        movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp);
+       if (regf)
+               printf("        fmovem #%d,%d(%%fp)\n", regf, -fpsub);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       if (regm)
+               printf("        movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm);
+       if (regf)
+               printf("        fmovem %d(%%fp),#%d\n", -fpsub, regf);
+       printf("        unlk %%fp\n     rts\n");
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "eor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s", str);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+                       return(SZINT/SZCHAR);
+
+               case LONG:
+               case ULONG:
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       comperr("fldexpand");
+       return 0;
+}
+
+static void
+starg(NODE *p)
+{
+       int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       int subsz = (sz + 3) & ~3;
+       int fr, tr, cr;
+
+       fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */
+       cr = regno(getlr(p, '1')); /* count reg (number of words) */
+       tr = regno(getlr(p, '2')); /* to reg (stack) */
+
+       /* Sub from stack and put in toreg */
+       printf("        sub.l #%d,%%sp\n", subsz);
+       printf("        move.l %%sp,%s\n", rnames[tr]);
+
+       /* Gen an even copy start */
+       if (sz & 1)
+               expand(p, INBREG, "     move.b (AL)+,(A2)+\n");
+       if (sz & 2)
+               expand(p, INBREG, "     move.w (AL)+,(A2)+\n");
+       sz -= (sz & 3);
+       
+       /* if more than 4 words, use loop, otherwise output instructions */
+       if (sz > 16) {
+               printf("        move.l #%d,%s\n", (sz/4)-1, rnames[cr]);
+               expand(p, INBREG, "1:   move.l (AL)+,(A2)+\n");
+               expand(p, INBREG, "     dbra A1,1b\n");
+       } else {
+               if (sz > 12)
+                       expand(p, INBREG, "     move.l (AL)+,(A2)+\n"), sz -= 4;
+               if (sz > 8)
+                       expand(p, INBREG, "     move.l (AL)+,(A2)+\n"), sz -= 4;
+               if (sz > 4)
+                       expand(p, INBREG, "     move.l (AL)+,(A2)+\n"), sz -= 4;
+               if (sz == 4)
+                       expand(p, INBREG, "     move.l (AL)+,(A2)+\n");
+       }
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       TWORD t = p->n_type;
+       char *s;
+
+       switch (c) {
+       case 'L':
+               t = p->n_left->n_type;
+               /* FALLTHROUGH */
+       case 'A':
+               s = (t == CHAR || t == UCHAR ? "b" :
+                   t == SHORT || t == USHORT ? "w" : 
+                   t == FLOAT ? "s" :
+                   t == DOUBLE ? "d" :
+                   t == LDOUBLE ? "x" : "l");
+               printf("%s", s);
+               break;
+
+       case 'B':
+               if (p->n_qual)
+                       printf("        add.l #%d,%%sp\n", (int)p->n_qual);
+               break;
+
+       case 'C': /* jsr or bsr.l XXX - type of CPU? */
+               printf("%s", kflag ? "bsr.l" : "jsr");
+               break;
+
+       case 'F': /* Emit float branches */
+               switch (p->n_op) {
+               case GT: s = "fjnle"; break;
+               case GE: s = "fjnlt"; break;
+               case LE: s = "fjngt"; break;
+               case LT: s = "fjnge"; break;
+               case NE: s = "fjne"; break;
+               case EQ: s = "fjeq"; break;
+               default: comperr("ZF"); s = 0;
+               }
+               printf("%s " LABFMT "\n", s, p->n_label);
+               break;
+
+       case 'P':
+               printf("        lea -%d(%%fp),%%a0\n", stkpos);
+               break;
+
+       case 'Q': /* struct assign */
+               printf("        move.l %d,-(%%sp)\n", 
+                   attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
+               expand(p, INAREG, "     move.l AR,-(%sp)\n");
+               expand(p, INAREG, "     move.l AL,-(%sp)\n");
+               printf("        jsr memcpy\n");
+               printf("        add.l #12,%%sp\n");
+               break;
+
+       case 'S': /* struct arg */
+               starg(p);
+               break;
+
+       case '2':
+               if (regno(getlr(p, '2')) != regno(getlr(p, 'L')))
+                       expand(p, INAREG, "     fmove.x AL,A2\n");
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+#if 0
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return(0);
+}
+#endif
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       comperr("flshape");
+       return(0);
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("#" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       long val = getlval(p);
+
+       if (p->n_type <= UCHAR)
+               val &= 255;
+       else if (p->n_type <= USHORT)
+               val &= 65535;
+
+       switch (p->n_op) {
+       case ICON:
+               fprintf(fp, "%ld", val);
+               if (p->n_name[0])
+                       printf("+%s", p->n_name);
+               break;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+       switch (p->n_op) {
+       case REG:
+               printf("%%%s", &rnames[p->n_rval][2]);
+               break;
+       case NAME:
+       case OREG:
+               setlval(p, getlval(p) + 4);
+               adrput(stdout, p);
+               setlval(p, getlval(p) - 4);
+               break;
+
+       case ICON:
+               printf("#%d", (int)getlval(p));
+               break;
+
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       int r;
+
+       /* output an address, with offsets, from p */
+       switch (p->n_op) {
+       case NAME:
+               if (getlval(p))
+                       fprintf(io, CONFMT "%s", getlval(p),
+                           *p->n_name ? "+" : "");
+               if (p->n_name[0])
+                       printf("%s", p->n_name);
+               else
+                       comperr("adrput");
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               
+               if (getlval(p))
+                       fprintf(io, CONFMT "%s", getlval(p),
+                           *p->n_name ? "+" : "");
+               if (p->n_name[0])
+                       printf("%s", p->n_name);
+               if (R2TEST(r)) {
+                       int r1 = R2UPK1(r);
+                       int r2 = R2UPK2(r);
+                       int sh = R2UPK3(r);
+
+                       fprintf(io, "(%s,%s,%d)", 
+                           r1 == MAXREGS ? "" : rnames[r1],
+                           r2 == MAXREGS ? "" : rnames[r2], sh);
+               } else
+                       fprintf(io, "(%s)", rnames[p->n_rval]);
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
+                       fprintf(io, "#" CONFMT, getlval(p) >> 32);
+               } else {
+                       fputc('#', io);
+                       conput(io, p);
+               }
+               return;
+
+       case REG:
+               if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) &&
+                       /* XXX allocated reg may get wrong type here */
+                   (p->n_rval > A7 && p->n_rval < FP0)) {
+                       fprintf(io, "%%%c%c", rnames[p->n_rval][0],
+                           rnames[p->n_rval][1]);
+               } else
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+static char *
+ccbranches[] = {
+       "jeq",          /* jumpe */
+       "jne",          /* jumpn */
+       "jle",          /* jumple */
+       "jlt",          /* jumpl */
+       "jge",          /* jumpge */
+       "jgt",          /* jumpg */
+       "jls",          /* jumple (jlequ) */
+       "jcs",          /* jumpl (jlssu) */
+       "jcc",          /* jumpge (jgequ) */
+       "jhi",          /* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("        %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static void
+mkcall(NODE *p, char *name)
+{
+       p->n_op = CALL;
+       p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
+       p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
+       p->n_left->n_name = name;
+}
+
+static void
+mkcall2(NODE *p, char *name)
+{
+       p->n_op = CALL;
+       p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type);
+       p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
+       p->n_right = mkbinode(CM, p->n_left, p->n_right, INT);
+       p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
+       p->n_left->n_name = name;
+}
+
+
+static void
+fixcalls(NODE *p, void *arg)
+{
+       struct attr *ap;
+       TWORD lt;
+
+       switch (p->n_op) {
+       case STCALL:
+       case USTCALL:
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               if (ap->iarg(0)+p2autooff > stkpos)
+                       stkpos = ap->iarg(0)+p2autooff;
+               break;
+
+       case DIV:
+               if (p->n_type == LONGLONG)
+                       mkcall2(p, "__divdi3");
+               else if (p->n_type == ULONGLONG)
+                       mkcall2(p, "__udivdi3");
+               break;
+
+       case MOD:
+               if (p->n_type == LONGLONG)
+                       mkcall2(p, "__moddi3");
+               else if (p->n_type == ULONGLONG)
+                       mkcall2(p, "__umoddi3");
+               break;
+
+       case MUL:
+               if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
+                       mkcall2(p, "__muldi3");
+               break;
+
+       case LS:
+               if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
+                       mkcall2(p, "__ashldi3");
+               break;
+
+       case RS:
+               if (p->n_type == LONGLONG)
+                       mkcall2(p, "__ashrdi3");
+               else if (p->n_type == ULONGLONG)
+                       mkcall2(p, "__lshrdi3");
+               break;
+
+       case SCONV:
+               lt = p->n_left->n_type;
+               switch (p->n_type) {
+               case LONGLONG:
+                       if (lt == FLOAT)
+                               mkcall(p, "__fixsfdi");
+                       else if (lt == DOUBLE)
+                               mkcall(p, "__fixdfdi");
+                       else if (lt == LDOUBLE)
+                               mkcall(p, "__fixxfdi");
+                       break;
+               case ULONGLONG:
+                       if (lt == FLOAT)
+                               mkcall(p, "__fixunssfdi");
+                       else if (lt == DOUBLE)
+                               mkcall(p, "__fixunsdfdi");
+                       else if (lt == LDOUBLE)
+                               mkcall(p, "__fixunsxfdi");
+                       break;
+               case FLOAT:
+                       if (lt == LONGLONG)
+                               mkcall(p, "__floatdisf");
+                       else if (lt == ULONGLONG)
+                               mkcall(p, "__floatundisf");
+                       break;
+               case DOUBLE:
+                       if (lt == LONGLONG)
+                               mkcall(p, "__floatdidf");
+                       else if (lt == ULONGLONG)
+                               mkcall(p, "__floatundidf");
+                       break;
+               case LDOUBLE:
+                       if (lt == LONGLONG)
+                               mkcall(p, "__floatdixf");
+                       else if (lt == ULONGLONG)
+                               mkcall(p, "__floatundixf");
+                       break;
+               }
+               break;
+#if 0
+       case XASM:
+               p->n_name = adjustname(p->n_name);
+               break;
+#endif
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       stkpos = p2autooff;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, fixcalls, 0);
+       }
+       if (stkpos > p2autooff)
+               p2autooff = stkpos;
+       if (stkpos > p2maxautooff)
+               p2maxautooff = stkpos;
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+
+       if (s >= D0D1 && s <= D6D7) {
+               printf("        move.l %s,%s\n",
+                   rnames[s-D0D1], rnames[d-D0D1]);
+               printf("        move.l %s,%s\n",
+                   rnames[s+1-D0D1], rnames[d+1-D0D1]);
+       } else if (t >= FLOAT && t <= TDOUBLE)
+               printf("        fmove.x %s,%s\n", rnames[s], rnames[d]);
+       else
+               printf("        move.l %s,%s\n", rnames[s], rnames[d]);
+}
+
+/*
+ * For class cc, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int cc, int *r)
+{
+       int a,c;
+
+       a = r[CLASSA];
+       c = r[CLASSC];
+
+       switch (cc) {
+       case CLASSA:
+               if (c * 2 + a < 8)
+                       return 1;
+               break;
+       case CLASSB:
+               return r[CLASSB] < 6;
+       case CLASSC:
+               if (c > 2)
+                       return 0;
+               if (c == 2 && a > 0)
+                       return 0;
+               if (c == 1 && a > 1)
+                       return 0;
+               if (c == 0 && a > 3)
+                       return 0;
+               return 1;
+       }
+       return 0;
+}
+
+char *rnames[] = {
+       "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+       "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
+       "d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7",
+       "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", 
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t > BTMASK)
+               return CLASSB;
+       if (t == LONGLONG || t == ULONGLONG)
+               return CLASSC;
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return CLASSD;
+       return CLASSA;
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (t < LONGLONG || t == FLOAT || t > BTMASK)
+               return 4;
+       if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+               return 8;
+       if (t == LDOUBLE)
+               return 12;
+       if (t == STRTY || t == UNIONTY)
+               return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3;
+       comperr("argsiz");
+       return 0;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               size += argsiz(p->n_right);
+       size += argsiz(p);
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       int cw = xasmcode(p->n_name);
+       int ww;
+       char *w;
+
+       ww = XASMVAL(cw);
+again: switch (ww) {
+       case 'd': /* Just convert to reg */
+       case 'a':
+               p->n_name = tmpstrdup(p->n_name);
+               w = strchr(p->n_name, XASMVAL(cw));
+               *w = 'r'; /* now reg */
+               break;
+       case 'o': /* offsetable reg */
+               if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG ||
+                   p->n_left->n_op == NAME) {
+                       return 1;
+               }
+               if (ww == XASMVAL(cw))
+                       ww = XASMVAL1(cw);
+               else
+                       ww = XASMVAL2(cw);
+               goto again;
+       }
+       return 0;
+}
+
+/*
+ * Handle special characters following % in gcc extended assembler.
+ */
+int
+targarg(char *w, void *arg)
+{
+       switch (w[1]) {
+       case '.': /* Remove dot if not needed */
+               printf(".");
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/m68k/macdefs.h b/lang/pcc/pcc/arch/m68k/macdefs.h
new file mode 100644 (file)
index 0000000..d1f7ac6
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2011 Janne Johansson <jj@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = i ? (val<<8)|lastcon : val
+
+#define ARGINIT                64      /* # bits above fp where arguments start */
+#define AUTOINIT       0       /* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         8
+#define SZSHORT                16
+#define SZINT          32
+#define SZLONG         32
+#define SZPOINT(t)     32
+#define SZLONGLONG     64
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      128
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         8
+#define ALSHORT                16
+#define ALINT          32
+#define ALLONG         32
+#define ALPOINT                32
+#define ALLONGLONG     64
+#define ALFLOAT                32
+#define ALDOUBLE       64
+#define ALLDOUBLE      32      /* ???? */
+/* #undef ALSTRUCT     m68k struct alignment is member defined */
+#define ALSTACK                32
+#define ALMAX          64 
+
+/*
+ * Min/max values.
+ */
+#define MIN_CHAR       -128
+#define MAX_CHAR       127
+#define MAX_UCHAR      255
+#define MIN_SHORT      -32768
+#define MAX_SHORT      32767
+#define MAX_USHORT     65535
+#define MIN_INT                (-0x7fffffff-1)
+#define MAX_INT                0x7fffffff
+#define MAX_UNSIGNED   0xffffffffU
+#define MIN_LONG       MIN_INT
+#define MAX_LONG       MAX_INT
+#define MAX_ULONG      MAX_UNSIGNED
+#define MIN_LONGLONG   0x8000000000000000LL
+#define MAX_LONGLONG   0x7fffffffffffffffLL
+#define MAX_ULONGLONG  0xffffffffffffffffULL
+
+/* Default char is signed */
+#undef CHAR_UNSIGNED
+#define BOOL_TYPE      UCHAR   /* what used to store _Bool */
+
+/*
+ * Use large-enough types.
+ */
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#define LABFMT ".L%d"          /* format for printing labels */
+#define STABLBL ".LL%d"                /* format for stab (debugging) labels */
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG         (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG         FSZLONG
+#define AUTOREG EBP
+#define ARGREG EBP
+#define ARGOFFSET 8
+#endif
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_BE /* big-endian */
+
+#undef FINDMOPS /* XXX FIXME */
+
+#define CC_DIV_0       /* division by zero is safe in the compiler */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)  gencall(a,b)
+
+/* How many integer registers are needed? (used for stack allocation) */
+#define szty(t) ((t) == LDOUBLE ? 3 : \
+       (t) == DOUBLE || DEUNSIGN(t) == LONGLONG ? 2 : 1)
+
+/*
+ * All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ *
+ * The classes used on m68k are:
+ *     A - 32-bit data registers
+ *     B - 32-bit address registers
+ *     C - 64-bit combined registers
+ *     D - 80-bit floating point registers
+ */
+#define D0     0
+#define D1     1
+#define D2     2
+#define D3     3
+#define D4     4
+#define D5     5
+#define D6     6
+#define D7     7
+
+/* no support yet for using A registers for data calculations */
+#define A0     8
+#define A1     9
+#define A2     10
+#define A3     11
+#define A4     12
+#define A5     13
+#define A6     14 /* frame pointer?  Isnt it A4 on amigaos.. */
+#define A7     15  /* Stack pointer */
+
+#define D0D1   16
+#define D1D2   17
+#define D2D3   18
+#define D3D4   19
+#define D4D5   20
+#define D5D6   21
+#define D6D7   22
+
+#define        FP0     23
+#define        FP1     24
+#define        FP2     25
+#define        FP3     26
+#define        FP4     27
+#define        FP5     28
+#define        FP6     29
+#define        FP7     30
+
+#define MAXREGS 31     /* 31 registers */
+
+#define RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG, \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|PERMREG, SBREG|PERMREG, \
+       SBREG|PERMREG, SBREG|PERMREG, 0, 0, /* fp and sp are ignored here */ \
+       SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+       SDREG|TEMPREG, SDREG|TEMPREG, SDREG|PERMREG, SDREG|PERMREG, \
+       SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG,
+
+
+/* no overlapping registers at all */
+#define ROVERLAP \
+       /* 8 data registers */   \
+       { D0D1, -1},\
+       { D1D2, D0D1, -1},\
+       { D2D3, D1D2,-1},\
+       { D3D4, D2D3,-1},\
+       { D4D5, D3D4,-1},\
+       { D5D6, D4D5,-1},\
+       { D6D7, D5D6,-1},\
+       { D6D7, -1},\
+       /* 8 adress registers */  \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { D0, D1, D1D2, -1},    \
+       { D1, D2, D0D1, D2D3, -1},      \
+       { D2, D3, D1D2, D3D4, -1},      \
+       { D3, D4, D2D3, D4D5, -1},      \
+       { D4, D5, D3D4, D5D6, -1},      \
+       { D5, D6, D4D5, D6D7, -1},      \
+       { D6, D7, D5D6, -1},  \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1}, \
+       { -1},
+
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (p->n_type == FLOAT || p->n_type == DOUBLE || \
+       p->n_type == LDOUBLE ? SDREG : p->n_type == LONGLONG || \
+       p->n_type == ULONGLONG ? SCREG : p->n_type > BTMASK ? SBREG : SAREG)
+
+#define NUMCLASS       4       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 23 ? CLASSC : CLASSD)
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)       (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 12)     /* A1 */
+#define ENCRA2(x)      ((x) << 18)     /* A2 */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+
+#define RETREG(x)      ((x) == FLOAT || (x) == DOUBLE || (x) == LDOUBLE ? FP0 : \
+       (x) == LONGLONG || (x) == ULONGLONG ? D0D1 : (x) > BTMASK ? A0 : D0)
+
+#define FPREG  A6      /* frame pointer */
+#define STKREG A7      /* stack pointer */
+
+#define HAVE_WEAKREF
+#define TARGET_FLT_EVAL_METHOD 2       /* all as long double */
+
+/*
+ * Extended assembler macros.
+ */
+int targarg(char *w, void *arg);
+#define XASM_TARGARG(w, ary) (w[1] == 'b' ? w++, 0 : targarg(w, ary))
+
diff --git a/lang/pcc/pcc/arch/m68k/order.c b/lang/pcc/pcc/arch/m68k/order.c
new file mode 100644 (file)
index 0000000..92722ae
--- /dev/null
@@ -0,0 +1,180 @@
+/*     $Id: order.c,v 1.5 2016/01/30 17:26:19 ragge Exp $      */
+/*
+ * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       if (off > MAX_SHORT || off < MIN_SHORT)
+               return 1; /* max signed 16-bit offset */
+       return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ * Especially on m68k we must be careful about class changes;
+ * Pointers can only have a scalar added to it if PLUS, but when
+ * MINUS may be either only pointers or left pointer and right scalar.
+ *
+ * So far we only handle the trivial OREGs here.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *q;
+
+       if (x2debug) {
+               printf("offstar(%p)\n", p);
+               fwalk(p, e2print, 0);
+       }
+
+       if (isreg(p))
+               return; /* Matched (%a0) */
+
+       q = p->n_right;
+       if ((p->n_op == PLUS || p->n_op == MINUS) && q->n_op == ICON &&
+           notoff(0, 0, getlval(q), 0) == 0 && !isreg(p->n_left)) {
+               (void)geninsn(p->n_left, INBREG);
+               return;
+       }
+       (void)geninsn(p, INBREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ * For simple OREGs conversion should already be done.
+ */
+void
+myormake(NODE *q)
+{
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on x86 */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case STASG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, D0 }, { NEVER, D1 },
+                               { NEVER, A0 }, { NEVER, A1 },
+                               /* { NRES, A0 }, */ { 0 } };
+                       return s;
+               }
+       }
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0;
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[] = { A0, -1 };
+
+       if (p->n_op == STCALL)
+               return r; /* only if struct return */
+       return &r[1];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/m68k/table.c b/lang/pcc/pcc/arch/m68k/table.c
new file mode 100644 (file)
index 0000000..860be6e
--- /dev/null
@@ -0,0 +1,1007 @@
+/*     $Id: table.c,v 1.13 2015/10/27 14:48:50 ragge Exp $     */
+/*
+ * Copyright (c) 2014 Anders Magnusson (ragge@ludd.ltu.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#define TLL    TLONGLONG|TULONGLONG
+#define TAREG  TINT|TSHORT|TCHAR|TUNSIGNED|TUSHORT|TUCHAR
+#define SABREG SAREG|SBREG
+#define TFP    TFLOAT|TDOUBLE|TLDOUBLE
+
+# define ANYSIGNED TINT|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED
+# define TSWORD TINT
+# define TWORD TUWORD|TSWORD
+#define TANYINT TLL|ANYFIXED
+#define         SHINT  SAREG   /* Any integer */
+#define         ININT  INAREG
+#define         SHFL   SCREG   /* shape for long double */
+#define         INFL   INCREG  /* shape for long double */
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* begin with all these casts */
+
+/* pointer to pointer (same reg class) */
+{ PCONV,       INBREG,
+       SBREG,          TPOINT,
+       SBREG,          TANY,
+               0,      RLEFT,
+               "", },
+
+/* (u)int -> pointer */
+{ PCONV,       INBREG,
+       SAREG,          TWORD,
+       SBREG,          TANY,
+               NBREG,  RESC1,
+               "       move.l AL,A1\n", },
+
+/* pointer to int/unsigned */
+{ SCONV,       INAREG,
+       SBREG,          TPOINT,
+       SAREG,          TWORD,
+               NAREG,  RESC1,
+               "       move.l AL,A1\n", },
+
+/* (u)char -> (u)char */
+{ SCONV,       INAREG,
+       SAREG,          TCHAR|TUCHAR,
+       SAREG,          TCHAR|TUCHAR,
+               0,      RLEFT,
+               "", },
+
+/* char -> short/ushort */
+{ SCONV,       INAREG|INBREG,
+       SABREG,         TCHAR,
+       SABREG,         TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       ext.w AL\n", },
+
+/* uchar -> short/ushort */
+{ SCONV,       INAREG|INBREG,
+       SABREG,         TUCHAR,
+       SABREG,         TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       and.l #255,AL\n", },
+
+/* char -> (u)int */
+{ SCONV,       INAREG,
+       SAREG,          TCHAR,
+       SAREG,          TINT|TUNSIGNED,
+               0,      RLEFT,
+               "       extb.l AL\n", },
+
+/* uchar -> (u)int */
+{ SCONV,       INAREG,
+       SAREG,          TUCHAR,
+       SAREG,          TINT|TUNSIGNED,
+               0,      RLEFT,
+               "       and.l #255,AL\n", },
+
+/* char -> (u)longlong */
+{ SCONV,       INCREG,
+       SAREG|SNAME|SOREG,      TCHAR,
+       SCREG,                  TLL,
+               NCREG,  RESC1,
+               "       move.b AL,U1\n  extb.l U1\n"
+               "       smi A1\n        extb.l A1\n", },
+
+/* uchar -> (u)longlong */
+{ SCONV,       INCREG,
+       SAREG|SNAME|SOREG,      TUCHAR,
+       SCREG,                  TLL,
+               NCREG,  RESC1,
+               "       move.b AL,U1\n  and.l #255,U1\n clr.l A1\n", },
+
+/* char -> float/(l)double */
+{ SCONV,       INDREG,
+       SAREG,          TCHAR,
+       SDREG,          TFP,
+               NDREG,  RESC1,
+               "       fmove.ZL AL,A1\n", },
+
+/* (u)char -> float/(l)double */
+{ SCONV,       INDREG,
+       SAREG,          TUCHAR,
+       SDREG,          TFP,
+               NAREG|NDREG,    RESC2,
+               "       clr.l A1\n      move.b AL,A1\n  fmove.w A1,A2\n", },
+
+/* (u)short -> (u)char */
+{ SCONV,       INAREG,
+       SAREG,          TSHORT|TUSHORT,
+       SAREG,          TCHAR|TUCHAR,
+               0,      RLEFT,
+               "", },
+
+/* (u)short -> (u)short */
+{ SCONV,       INAREG,
+       SAREG,          TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RLEFT,
+               "", },
+
+/* short -> (u)int */
+{ SCONV,       INAREG|INBREG,
+       SABREG,         TSHORT,
+       SABREG,         TINT|TUNSIGNED,
+               0,      RLEFT,
+               "       ext.l AL\n", },
+
+/* ushort -> (u)int */
+{ SCONV,       INAREG|INBREG,
+       SABREG,         TUSHORT,
+       SABREG,         TINT|TUNSIGNED,
+               0,      RLEFT,
+               "       and.l #65535,AL\n", },
+
+/* short -> (u)longlong */
+{ SCONV,       INCREG,
+       SAREG,          TSHORT,
+       SCREG,          TLL,
+               NCREG,  RESC1,
+               "       move AL,U1\n    ext.l U1\n"
+               "       smi A1\n        extb.l A1\n", },
+
+/* ushort -> (u)longlong */
+{ SCONV,       INCREG,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SCREG,                  TLL,
+               NCREG,  RESC1,
+               "       move.l AL,U1\n  and.l #65535,U1\n       clr.l A1\n", },
+
+/* short -> float/(l)double */
+{ SCONV,       INDREG,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SDREG,                  TFP,
+               NDREG|NDSL,     RESC1,
+               "       fmove.w AL,A1\n", },
+
+/* ushort -> float/(l)double */
+{ SCONV,       INDREG,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SAREG|SDREG,            TFP,
+               NAREG|NDREG|NDSL,       RESC2,
+               "       move.w AL,A1\n  and.l #65535,A1\n"
+               "       fmove.l A1,A2\n", },
+
+/* (u)int -> (u)char */
+{ SCONV,       INAREG,
+       SAREG,          TWORD,
+       SAREG,          TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       and.l #255,AL\n", },
+
+/* (u)int -> (u)short */
+{ SCONV,       INAREG,
+       SAREG,          TWORD,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       and.l #65535,AL\n", },
+
+/* (u)int -> (u)int  - nothing */
+{ SCONV,       INAREG,
+       SAREG,          TWORD,
+       SAREG,          TWORD,
+               0,      RLEFT,
+               "", },
+
+/* int -> (u)longlong */
+{ SCONV,       INCREG,
+       SAREG|SOREG|SNAME,      TINT,
+       SCREG,                  TLL,
+               NCREG,  RESC1,
+               "       move.l AL,U1\n  smi A1\n        extb.l A1\n", },
+
+/* (u)int -> (u)longlong */
+{ SCONV,       INCREG,
+       SAREG|SOREG|SNAME,      TUNSIGNED,
+       SCREG,                  TLL,
+               NCREG,  RESC1,
+               "       move.l AL,U1\n  clr.l A1\n", },
+
+/* int -> float/(l)double */
+{ SCONV,       INDREG,
+       SAREG|SNAME|SOREG,      TINT,
+       SDREG,                  TFP,
+               NDREG|NDSL,     RESC1,
+               "       fmove.l AL,A1\n", },
+
+/* uint -> double */
+{ SCONV,       INDREG,
+       SAREG,          TUNSIGNED,
+       SDREG,          TFLOAT|TDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "       fmove.l AL,A1\n"
+               "       tst.l AL\n"
+               "       jge 1f\n"
+               "       fadd.d #0x41f0000000000000,A1\n"
+               "1:\n", },
+
+/* (u)longlong -> (u)char/(u)short/(u)int */
+{ SCONV,       INAREG,
+       SCREG|SOREG|SNAME,      TLL,
+       SAREG,                  TAREG,
+               NAREG,  RESC1,
+               "       movl UL,A1\n", },
+
+/* (u)longlong to (u)longlong */
+{ SCONV,       INCREG,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RLEFT,
+               "", },
+
+/* float/(l)double -> int/short/char (in reg) */
+{ SCONV,       INAREG,
+       SDREG,  TFP,
+       SAREG,  TINT|TSHORT|TCHAR,
+               NAREG,  RESC1,
+               "       fmove.ZA AL,A1\n", },
+
+/* float -> unsigned */
+{ SCONV,       INAREG,
+       SDREG,  TFLOAT,
+       SAREG,  TUNSIGNED,
+               NAREG|NDREG|NDSL,       RESC1,
+               "Z2     fcmp.s #0x4f000000,A2\n"
+               "       fjge 2f\n"
+               "       fintrz.x A2,A2\n"
+               "       fmove.l A2,A1\n"
+               "       jra 3f\n"
+               "2:     fsub.s #0x4f000000,A2\n"
+               "       fintrz.x A2,A2\n"
+               "       fmove.l A2,A1\n"
+               "       add.l #-2147483648,A1\n3:\n", },
+
+/* float -> (l)double */
+{ SCONV,       INDREG,
+       SDREG,  TFLOAT,
+       SDREG,  TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               "", }, /* in fp regs -> do nothing */
+
+/* double -> ldouble */
+{ SCONV,       INDREG,
+       SDREG,  TDOUBLE,
+       SDREG,  TLDOUBLE,
+               0,      RLEFT,
+               "", }, /* in fp regs -> do nothing */
+
+/* double -> uchar */
+{ SCONV,       INAREG,
+       SDREG,  TDOUBLE,
+       SAREG,  TUCHAR,
+               NAREG|NDREG|NDSL,       RESC1,
+               "       fintrz.x AL,A2\n        fmove.w A2,A1\n", },
+
+/* double -> ushort */
+{ SCONV,       INAREG,
+       SDREG,  TDOUBLE,
+       SAREG,  TUSHORT,
+               NAREG|NDREG|NDSL,       RESC1,
+               "       fintrz.x AL,A2\n        fmove.l A2,A1\n", },
+
+/* double -> unsigned */
+{ SCONV,       INAREG,
+       SDREG,  TDOUBLE,
+       SAREG,  TUNSIGNED,
+               NAREG|NDREG|NDSL,       RESC1,
+               "Z2     fcmp.d #0x41e0000000000000,A2\n"
+               "       fjge 2f\n"
+               "       fintrz.x A2,A2\n"
+               "       fmove.l A2,A1\n"
+               "       jra 3f\n"
+               "2:     fsub.d #0x41e0000000000000,A2\n"
+               "       fintrz.x A2,A2\n"
+               "       fmove.l A2,A1\n"
+               "       add.l #-2147483648,A1\n3:\n", },
+
+/* (l)double -> float */
+{ SCONV,       INDREG,
+       SDREG,  TDOUBLE|TLDOUBLE,
+       SDREG,  TFLOAT,
+               NAREG,  RLEFT,
+               "       fmove.s AL,A1\n fmove.s A1,AL\n", },
+
+/* ldouble -> double */
+{ SCONV,       INDREG,
+       SDREG,  TLDOUBLE,
+       SDREG,  TDOUBLE,
+               NTEMP*2,        RLEFT,
+               "       fmove.d AL,A1\n fmove.d A1,AL\n", },
+
+/* assignment */
+{ ASSIGN,      FOREFF,
+       SCREG|SNAME|SOREG,      TLL,
+       SCREG|SNAME|SOREG,      TLL,
+               0,      0,
+               "       move.l AR,AL\n"
+               "       move.l UR,UL\n", },
+
+{ ASSIGN,      INCREG,
+       SCREG|SNAME|SOREG,      TLL,
+       SCREG,                  TLL,
+               0,      RDEST,
+               "       move.l AR,AL\n"
+               "       move.l UR,UL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TAREG,
+       SAREG|SNAME|SOREG,      TAREG,
+               0,      0,
+               "       move.ZA AR,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SBREG|SNAME|SOREG,      TPOINT,
+       SBREG|SNAME|SOREG,      TPOINT,
+               0,      0,
+               "       move.l AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TAREG,
+       SAREG,                  TAREG,
+               0,      RDEST,
+               "       move.ZA AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG|SNAME|SOREG,      TPOINT,
+       SBREG,                  TPOINT,
+               0,      RDEST,
+               "       move.l AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INDREG,
+       SNAME|SOREG,    TFP,
+       SDREG,          TFP,
+               0,      RDEST,
+               "       fmove.ZA AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INDREG,
+       SDREG,          TFP,
+       SNAME|SOREG,    TFP,
+               0,      RDEST,
+               "       fmove.ZA AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INDREG,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               0,      RDEST,
+               "       fmove.x AR,AL\n", },
+
+/* structure stuff */
+{ STASG,       INBREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SBREG,          TPTRTO|TANY,
+               NSPECIAL,       RDEST,
+               "ZQ", },
+/* 
+ * Simple ops (add, sub, and, or, xor)
+ */
+/* Address registers may be added to (or subtracted from) */
+{ PLUS, FOREFF,
+       SBREG|SNAME|SOREG|SCON,         TWORD|TPOINT,
+       SAREG,                          TWORD,
+               0,      0,
+               "       add.l AR,AL\n", },
+
+{ PLUS, FOREFF|INBREG,
+       SBREG,                  TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD,
+               0,      RLEFT|RESCC,
+               "       add.l AR,AL\n", },
+
+{ PLUS, FOREFF|INDREG,
+       SDREG,          TFP,
+       SNAME|SOREG|SCON, TFP,
+               0,      RLEFT|RESCC,
+               "       fadd.ZA AR,AL\n", },
+
+{ PLUS, FOREFF|INDREG,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               0,      RLEFT|RESCC,
+               "       fadd.x AR,AL\n", },
+
+{ PLUS, FOREFF|INCREG|RESCC,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RLEFT|RESCC,
+               "       add.l UR,UL\n   addx.l AR,AL\n", },
+
+{ MINUS, FOREFF,
+       SBREG|SNAME|SOREG|SCON,         TWORD|TPOINT,
+       SBREG,                          TWORD,
+               0,      0,
+               "       sub.l AR,AL\n", },
+
+{ MINUS, INAREG,
+       SBREG,          TPOINT,
+       SBREG,          TPOINT,
+               NAREG,  RESC1,
+               "       move.l AL,A1\n  sub.l AR,A1\n", },
+
+{ MINUS, FOREFF|INBREG,
+       SBREG,                          TWORD|TPOINT,
+       SABREG|SNAME|SOREG|SCON,        TWORD,
+               0,      RLEFT|RESCC,
+               "       sub.l AR,AL\n", },
+
+{ MINUS, FOREFF|INDREG,
+       SDREG,                  TFP,
+       SNAME|SOREG|SCON, TFP,
+               0,      RLEFT|RESCC,
+               "       fsub.ZA AR,AL\n", },
+
+{ MINUS, FOREFF|INDREG,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               0,      RLEFT|RESCC,
+               "       fsub.x AR,AL\n", },
+
+{ MINUS, FOREFF|INCREG|RESCC,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RLEFT|RESCC,
+               "       sub.l UR,UL\n   subx.l AR,AL\n", },
+
+/* two pointers give a scalar */
+{ MINUS,       INAREG|FORCC,
+       SBREG|SNAME|SOREG|SCON, TPOINT,
+       SBREG|SNAME|SOREG|SCON, TPOINT,
+               NAREG,  RESC1|RESCC,
+               "       move.l AL,A1\n  sub.l AR,A1\n", },
+
+/* Hack to allow for opsimp later down */
+/* Fortunately xor is not that common */
+{ ER,  FOREFF|INAREG,
+       SAREG,                          TAREG,
+       SNAME|SOREG|SCON,               TAREG,
+               NAREG,  RLEFT|RESCC,
+               "       move.ZA AR,A1\n eor.ZA A1,AL\n", },
+
+{ ER,  FOREFF|INCREG|FORCC,
+       SCREG|SNAME|SOREG|SCON,         TLL,
+       SCREG,                          TLL,
+               0,      RLEFT|RESCC,
+               "       eor.l AR,AL\n   eor.l UR,UL\n", },
+
+{ AND, FOREFF|INCREG|FORCC,
+       SCREG,                          TLL,
+       SCREG|SNAME|SOREG|SCON,         TLL,
+               0,      RLEFT|RESCC,
+               "       and.l AR,AL\n   and.l UR,UL\n", },
+
+{ OR,  FOREFF|INCREG|FORCC,
+       SCREG,                          TLL,
+       SCREG|SNAME|SOREG|SCON,         TLL,
+               0,      RLEFT|RESCC,
+               "       or.l AR,AL\n    or.l UR,UL\n", },
+
+{ OPSIMP,      FOREFF|INAREG,
+       SAREG,                          TAREG,
+       SAREG|SNAME|SOREG|SCON,         TAREG,
+               0,      RLEFT|RESCC,
+               "       Oz.ZA AR,AL\n", },
+
+{ OPSIMP,      FOREFF,
+       SAREG|SNAME|SOREG,      TAREG,
+       SAREG,                  TAREG,
+               0,      RLEFT|RESCC,
+               "       Oz.ZA AR,AL\n", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      FOREFF|INCREG|FORCC,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RLEFT|RESCC,
+               "       neg.l UL\n      negx.l AL\n", },
+
+{ UMINUS,      FOREFF|INAREG|FORCC,
+       SAREG,  TAREG,
+       SAREG,  TAREG,
+               0,      RLEFT|RESCC,
+               "       neg.ZA AL\n", },
+
+{ UMINUS,      INDREG|FORCC,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               NDREG,  RESC1|RESCC,
+               "       fmovecr #0xf,A1\n       fsub.x AL,A1\n", },
+
+{ UMINUS,      INDREG|FORCC,
+       SNAME|SOREG,    TFP,
+       SDREG,          TFP,
+               NDREG,  RESC1|RESCC,
+               "       fmovecr #0xf,A1\n       fsub.ZA AL,A1\n", },
+
+{ COMPL,       FOREFF|INAREG|FORCC,
+       SAREG,  TAREG,
+       SAREG,  TAREG,
+               0,      RLEFT|RESCC,
+               "       not.ZA AL\n", },
+
+{ COMPL,       FOREFF|INCREG,
+       SCREG,  TLL,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       not.l AL\n      not.l UL\n", },
+
+/*
+ * Shift operators.
+ */
+{ LS,  INAREG|FOREFF,
+       SAREG,  TAREG,
+       SAREG,  TAREG,
+               0,      RLEFT,
+               "       lsl.ZA AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG,  TUNSIGNED|TUSHORT|TUCHAR,
+       SAREG,  TAREG,
+               0,      RLEFT,
+               "       lsr.ZA AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG,  TINT|TSHORT|TCHAR,
+       SAREG,  TAREG,
+               0,      RLEFT,
+               "       asr.ZA AR,AL\n", },
+
+/*
+ * Leaf movements
+ */
+{ OPLTYPE,     INCREG,
+       SANY,                   TANY,
+       SCREG|SCON|SOREG|SNAME, TLL,
+               NCREG|NCSL,     RESC1,
+               "       move.l AL,A1\n  move.l UL,U1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TAREG,
+               NAREG|NASL,     RESC1,
+               "       move.ZA AL,A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SBREG|SCON|SOREG|SNAME, TPOINT,
+               NBREG|NBSL,     RESC1,
+               "       move.l AL,A1\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TANY,
+       SNAME|SOREG,    TFP,
+               NDREG|NDSL,     RESC1,
+               "       fmove.ZA AL,A1\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,   TANY,
+       SDREG,  TFP,
+               NDREG|NDSL,     RESC1,
+               "       fmove.x AL,A1\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL, INCREG,
+       SANY,   TPOINT,
+       SOREG,  TLL,
+               NCREG,  RESC1,
+               "       move.l AL,A1\n  move.l UL,U1\n", },
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "       move.l AL,A1\n", },
+
+{ UMUL, INBREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NBREG|NBSL,     RESC1,
+               "       move.l AL,A1\n", },
+
+{ UMUL, INDREG,
+       SANY,   TPOINT|TFP,
+       SOREG,  TFP,
+               NDREG|NDSL,     RESC1,
+               "       fmove.ZA AL,A1\n", },
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       move.w AL,A1\n", },
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       move.b AL,A1\n", },
+
+
+/*
+ * DIV/MOD/MUL 
+ */
+{ DIV, INAREG,
+       SAREG|SNAME|SOREG,      TINT,
+       SAREG,                  TINT,
+               0,      RLEFT,
+               "       divs.l AR,AL\n", },
+
+{ DIV, INAREG,
+       SAREG|SNAME|SOREG,      TUNSIGNED,
+       SAREG,                  TUNSIGNED,
+               0,      RLEFT,
+               "       divu.l AR,AL\n", },
+
+{ DIV, INDREG,
+       SDREG,          TDOUBLE|TLDOUBLE,
+       SNAME|SOREG,    TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               "       fdiv.ZA AR,AL\n", },
+
+{ DIV, INDREG,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               0,      RLEFT,
+               "       fdiv.x AR,AL\n", },
+
+{ DIV, INDREG,
+       SDREG,          TFLOAT,
+       SNAME|SOREG,    TFLOAT,
+               0,      RLEFT,
+               "       fsgldiv.ZA AR,AL\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TINT,
+       SAREG|SNAME|SOREG,      TINT,
+               NAREG*2,        RESC1,
+               "mov.l AL,A2\n  divsl.l AR,A1:A2\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TUNSIGNED,
+       SAREG|SNAME|SOREG,      TUNSIGNED,
+               NAREG*2,        RESC1,
+               "mov.l AL,A2\n  divul.l AR,A1:A2\n", },
+
+{ MUL, INAREG,
+       SAREG|SNAME|SOREG,      TWORD,
+       SAREG,                  TWORD,
+               0,      RLEFT,
+               "       muls.l AR,AL\n", },
+
+{ MUL, INDREG,
+       SDREG,          TDOUBLE|TLDOUBLE,
+       SNAME|SOREG,    TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               "       fmul.ZA AR,AL\n", },
+
+{ MUL, INDREG,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               0,      RLEFT,
+               "       fmul.x AR,AL\n", },
+
+{ MUL, INDREG,
+       SDREG,          TFLOAT,
+       SNAME|SOREG,    TFLOAT,
+               0,      RLEFT,
+               "       fsglmul.s AR,AL\n", },
+
+/*
+ * Function call nodes.
+ * Too many of them.
+ */
+/* FOREFF both direct and indirect */
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       ZC CL\n", },
+
+{ CALL,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       ZC CL\nZB", },
+
+{ UCALL,       FOREFF,
+       SBREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       jsr (AL)\n", },
+
+{ CALL,                FOREFF,
+       SBREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       jsr (AL)\nZB", },
+
+/* small scalar both direct and indirect */
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SAREG,  TAREG,
+               NAREG|NASL,     RESC1,
+               "       ZC CL\n", },
+
+{ CALL,                INAREG,
+       SCON,   TANY,
+       SAREG,  TAREG,
+               NAREG|NASL,     RESC1,
+               "       ZC CL\nZB", },
+
+{ UCALL,       INAREG,
+       SBREG,  TANY,
+       SAREG,  TAREG,
+               NAREG|NASL,     RESC1,
+               "       jsr (AL)\n", },
+
+{ CALL,                INAREG,
+       SBREG,  TANY,
+       SAREG,  TAREG,
+               NAREG|NASL,     RESC1,
+               "       jsr (AL)\nZB", },
+
+/* long long both direct and indirect */
+{ UCALL,       INCREG,
+       SCON,   TANY,
+       SCREG,  TLL,
+               NCREG|NCSL,     RESC1,
+               "       ZC CL\n", },
+
+{ CALL,                INCREG,
+       SCON,   TANY,
+       SCREG,  TLL,
+               NCREG|NCSL,     RESC1,
+               "       ZC CL\nZB", },
+
+{ UCALL,       INCREG,
+       SBREG,  TANY,
+       SCREG,  TLL,
+               NCREG|NCSL,     RESC1,
+               "       jsr (AL)\n", },
+
+{ CALL,                INCREG,
+       SBREG,  TANY,
+       SCREG,  TLL,
+               NCREG|NCSL,     RESC1,
+               "       jsr (AL)\nZB", },
+
+/* floats both direct and indirect */
+{ UCALL,       INDREG,
+       SCON,   TANY,
+       SDREG,  TFP,
+               NDREG|NDSL,     RESC1,
+               "       ZC CL\n", },
+
+{ CALL,                INDREG,
+       SCON,   TANY,
+       SDREG,  TFP,
+               NDREG|NDSL,     RESC1,
+               "       ZC CL\nZB", },
+
+{ UCALL,       INDREG,
+       SBREG,  TANY,
+       SDREG,  TFP,
+               NDREG|NDSL,     RESC1,
+               "       jsr (AL)\n", },
+
+{ CALL,                INDREG,
+       SBREG,  TANY,
+       SDREG,  TFP,
+               NDREG|NDSL,     RESC1,
+               "       jsr (AL)\nZB", },
+
+/* pointers both direct and indirect */
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "       ZC CL\n", },
+
+{ CALL,                INBREG,
+       SCON,   TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "       ZC CL\nZB", },
+
+{ UCALL,       INBREG,
+       SBREG,  TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "       jsr (AL)\n", },
+
+{ CALL,                INBREG,
+       SBREG,  TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "       jsr (AL)\nZB", },
+
+
+/* struct return both direct and indirect */
+{ USTCALL,     INBREG|FOREFF,
+       SCON,   TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "ZP     ZC CL\n", },
+
+{ STCALL,      INBREG|FOREFF,
+       SCON,   TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "ZP     ZC CL\nZB", },
+
+{ USTCALL,     INBREG|FOREFF,
+       SBREG,  TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "ZP     jsr (AL)\n", },
+
+{ STCALL,              INBREG|FOREFF,
+       SBREG,  TANY,
+       SBREG,  TWORD|TPOINT,
+               NBREG|NBSL,     RESC1,
+               "ZP     jsr (AL)\nZB", },
+
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,      FOREFF,
+       SAREG|SOREG|SNAME|SCON, TINT|TUNSIGNED,
+       SANY,                   TANY,
+               0,      RNULL,
+               "       move.l AL,-(%sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SCREG|SOREG|SNAME|SCON, TLL,
+       SANY,                   TANY,
+               0,      RNULL,
+               "       move.l UL,-(%sp)\n      move.l AL,-(%sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SCON,   TPOINT,
+       SANY,   TANY,
+               0,      RNULL,
+               "       pea CL\n", },
+
+{ FUNARG,      FOREFF,
+       SCON|SABREG|SNAME,      TWORD|TPOINT,
+       SANY,                   TWORD|TPOINT,
+               0,      RNULL,
+               "       move.l AL,-(%sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SOREG,  TWORD|TPOINT,
+       SANY,   TWORD|TPOINT,
+               0,      RNULL,
+               "       move.l AL,-(%sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TFP,
+       SANY,   TFP,
+               0,      RNULL,
+               "       fmove.ZA AL,-(%sp)\n", },
+
+{ STARG,       FOREFF,
+       SBREG,  TPTRTO|TSTRUCT,
+       SANY,   TSTRUCT,
+               NAREG|NBREG,    RNULL,
+               "ZS", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+#if 0
+{ OPLOG,       FORCC,
+       SHLL|SOREG|SNAME,       TLL,
+       SHLL,                   TLL,
+               0,      0,
+               "ZD", },
+#endif
+
+{ OPLOG,       INCREG|FORCC,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RESCC|RLEFT, /* trash left nodes */
+               "       sub.l UR,UL\n   subx.l AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG,                  TWORD,
+       SCON|SAREG|SOREG|SNAME, TWORD,
+               0,      RESCC,
+               "       cmp.l AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SBREG,                  TPOINT,
+       SCON|SBREG|SOREG|SNAME, TPOINT,
+               0,      RESCC,
+               "       cmp.l AR,AL\n", },
+
+/* jumps below emitted in zzzcode */
+{ OPLOG,       FORCC,
+       SDREG,                  TFP,
+       SCON|SOREG|SNAME,       TFP,
+               0,      0,
+               "       fcmp.ZL AR,AL\n ZF", },
+
+{ OPLOG,       FORCC,
+       SDREG,  TFP,
+       SDREG,  TFP,
+               0,      0,
+               "       fcmp.x AR,AL\n  ZF", },
+
+
+/*
+ * Jumps.
+ */
+{ GOTO,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp LL\n", },
+
+#if defined(GCC_COMPAT) || defined(LANG_F77)
+{ GOTO,                FOREFF,
+       SBREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp (AL)\n", },
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE, FREE,  FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/mips/TODO b/lang/pcc/pcc/arch/mips/TODO
new file mode 100644 (file)
index 0000000..07072de
--- /dev/null
@@ -0,0 +1,2 @@
+* Fix floating-point arguments in registers
+* Fix structure arguments in registers
diff --git a/lang/pcc/pcc/arch/mips/code.c b/lang/pcc/pcc/arch/mips/code.c
new file mode 100644 (file)
index 0000000..c77aecc
--- /dev/null
@@ -0,0 +1,738 @@
+/*     $Id: code.c,v 1.27 2016/01/06 16:11:24 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include <assert.h>
+#include "pass1.h"
+
+#ifndef LANG_CXX
+#undef NIL
+#define NIL NULL
+#define NODE P1ND
+#define nfree p1nfree
+#define ccopy p1tcopy
+#define tfree p1tfree
+#endif
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+       case UDATA: break;
+       case PICLDATA:
+       case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
+       case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
+       case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *n;
+
+       if (ISFTN(sp->stype))
+               return; /* XXX until fixed */
+
+       n = getexname(sp);
+
+       if (sp->sclass == EXTDEF)
+               printf("        .globl %s\n", n);
+       if (sp->slevel == 0) {
+#ifdef USE_GAS
+               printf("\t.type %s,@%s\n", n,
+                   ISFTN(sp->stype) ? "function" : "object");
+               if (!ISFTN(sp->stype))
+                       printf("\t.size %s," CONFMT "\n", n,
+                           tsize(sp->stype, sp->sdf, sp->sap));
+#endif
+               printf("%s:\n", n);
+       } else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+
+/*
+ * cause the alignment to become a multiple of n
+ */
+void
+defalign(int n)
+{
+       n = ispow2(n / SZCHAR);
+       if (n == -1)
+               cerror("defalign: n != 2^i");
+       printf("\t.p2align %d\n", n);
+}
+
+static int rvnr;
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       NODE *p, *q;
+       int tempnr;
+       int ty;
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+
+       ty = cftnsp->stype - FTN;
+
+       q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+       q->n_rval = V0;
+       p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
+       tempnr = regno(p);
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+
+       q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
+       q = buildtree(UMUL, q, NIL);
+
+       p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+       p = buildtree(UMUL, p, NIL);
+
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+
+       q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+       p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+       p->n_rval = V0;
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers */
+static void
+putintemp(struct symtab *sym)
+{
+       NODE *p;
+       p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+       p = buildtree(ASSIGN, p, nametree(sym));
+       sym->soffset = regno(p->n_left);
+       sym->sflags |= STNODE;
+       ecomp(p);
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retptr(void)
+{
+       NODE *p, *q;
+
+       p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
+       rvnr = regno(p);
+       q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       q->n_rval = A0;
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *regp)
+{
+       int reg = *regp;
+       NODE *p, *q;
+       int navail;
+       int sz;
+       int off;
+       int num;
+       int i;
+
+       navail = nargregs - (reg - A0);
+       sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
+       off = ARGINIT/SZINT + (reg - A0);
+       num = sz > navail ? navail : sz;
+       for (i = 0; i < num; i++) {
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               q->n_rval = reg++;
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               p->n_rval = FP;
+               p = block(PLUS, p, bcon(4*off++), INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+
+       *regp = reg;
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *regp, int dotemps)
+{
+       int reg = *regp;
+       NODE *p, *q;
+       int navail;
+
+       /* alignment */
+       ++reg;
+       reg &= ~1;
+
+       navail = nargregs - (reg - A0);
+
+       if (navail < 2) {
+               /* would have appeared half in registers/half
+                * on the stack, but alignment ensures it
+                * appears on the stack */
+               if (dotemps)
+                       putintemp(sym);
+               *regp = reg;
+               return;
+       }
+
+       q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+       q->n_rval = A0A1 + (reg - A0);
+       if (dotemps) {
+               p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               sym->soffset = regno(p);
+               sym->sflags |= STNODE;
+       } else {
+               p = nametree(sym);
+       }
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+       *regp = reg + 2;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *regp, int dotemps)
+{
+       NODE *p, *q;
+
+       q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+       q->n_rval = (*regp)++;
+       if (dotemps) {
+               p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               sym->soffset = regno(p);
+               sym->sflags |= STNODE;
+       } else {
+               p = nametree(sym);
+       }
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+/*
+ * XXX This is a hack.  We cannot have (l)doubles in more than one
+ * register class.  So we bounce them in and out of temps to
+ * move them in and out of the right registers.
+ */
+static void
+param_double(struct symtab *sym, int *regp, int dotemps)
+{
+       int reg = *regp;
+       NODE *p, *q, *t;
+       int navail;
+       int tmpnr;
+
+       /* alignment */
+       ++reg;
+       reg &= ~1;
+
+       navail = nargregs - (reg - A0);
+
+       if (navail < 2) {
+               /* would have appeared half in registers/half
+                * on the stack, but alignment ensures it
+                * appears on the stack */
+               if (dotemps)
+                       putintemp(sym);
+               *regp = reg;
+               return;
+       }
+
+       t = tempnode(0, LONGLONG, 0, 0);
+       tmpnr = regno(t);
+       q = block(REG, NIL, NIL, LONGLONG, 0, 0);
+       q->n_rval = A0A1 + (reg - A0);
+       p = buildtree(ASSIGN, t, q);
+       ecomp(p);
+
+       if (dotemps) {
+               sym->soffset = tmpnr;
+               sym->sflags |= STNODE;
+       } else {
+               q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
+               p = nametree(sym);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+       *regp = reg + 2;
+}
+
+/*
+ * XXX This is a hack.  We cannot have floats in more than one
+ * register class.  So we bounce them in and out of temps to
+ * move them in and out of the right registers.
+ */
+static void
+param_float(struct symtab *sym, int *regp, int dotemps)
+{
+       NODE *p, *q, *t;
+       int tmpnr;
+
+       t = tempnode(0, INT, 0, 0);
+       tmpnr = regno(t);
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       q->n_rval = (*regp)++;
+       p = buildtree(ASSIGN, t, q);
+       ecomp(p);
+
+       if (dotemps) {
+               sym->soffset = tmpnr;
+               sym->sflags |= STNODE;
+       } else {
+               q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
+               p = nametree(sym);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       union arglist *usym;
+       int lastreg = A0 + nargregs - 1;
+       int saveallargs = 0;
+       int i, reg;
+
+       /*
+        * Detect if this function has ellipses and save all
+        * argument register onto stack.
+        */
+       usym = cftnsp->sdf->dfun;
+       while (usym && usym->type != TNULL) {
+               if (usym->type == TELLIPSIS) {
+                       saveallargs = 1;
+                       break;
+               }
+               ++usym;
+       }
+
+       reg = A0;
+
+       /* assign hidden return structure to temporary */
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               param_retptr();
+               ++reg;
+       }
+
+        /* recalculate the arg offset and create TEMP moves */
+        for (i = 0; i < cnt; i++) {
+
+               if ((reg > lastreg) && !xtemps)
+                       break;
+               else if (reg > lastreg) 
+                       putintemp(sp[i]);
+               else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
+                       param_struct(sp[i], &reg);
+               else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
+                       param_64bit(sp[i], &reg, xtemps && !saveallargs);
+               else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
+                       param_double(sp[i], &reg, xtemps && !saveallargs);
+               else if (sp[i]->stype == FLOAT)
+                       param_float(sp[i], &reg, xtemps && !saveallargs);
+               else
+                       param_32bit(sp[i], &reg, xtemps && !saveallargs);
+       }
+
+       /* if saveallargs, save the rest of the args onto the stack */
+       if (!saveallargs)
+               return;
+       while (reg <= lastreg) {
+               NODE *p, *q;
+               int off = ARGINIT/SZINT + (reg - A0);
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               q->n_rval = reg++;
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               p->n_rval = FP;
+               p = block(PLUS, p, bcon(4*off), INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+}
+
+void
+bjobcode(void)
+{
+       printf("\t.section .mdebug.abi32\n");
+       printf("\t.previous\n");
+
+       /* only if -fpic or -fPIC */
+       if (kflag > 0)
+               printf("\t.abicalls\n");
+}
+
+#ifdef notdef
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+       static int lastoctal = 0;
+
+       /* put byte i+1 in a string */
+
+       if (t < 0) {
+               if (i != 0)
+                       puts("\\000\"");
+       } else {
+               if (i == 0)
+                       printf("\t.ascii \"");
+               if (t == 0)
+                       return;
+               else if (t == '\\' || t == '"') {
+                       lastoctal = 0;
+                       putchar('\\');
+                       putchar(t);
+               } else if (t == 011) {
+                       printf("\\t");
+               } else if (t == 012) {
+                       printf("\\n");
+               } else if (t < 040 || t >= 0177) {
+                       lastoctal++;
+                       printf("\\%o",t);
+               } else if (lastoctal && '0' <= t && t <= '9') {
+                       lastoctal = 0;
+                       printf("\"\n\t.ascii \"%c", t);
+               } else {        
+                       lastoctal = 0;
+                       putchar(t);
+               }
+       }
+}
+#endif
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, NODE *parent, int *regp)
+{
+       int reg = *regp;
+       NODE *l, *q, *t, *r;
+       int tmpnr;
+       int navail;
+       int off;
+       int num;
+        int sz;
+       int ty;
+       int i;
+
+       navail = nargregs - (reg - A0);
+       sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
+       num = sz > navail ? navail : sz;
+
+       l = p->n_left;
+       nfree(p);
+       ty = l->n_type;
+       t = tempnode(0, l->n_type, l->n_df, l->n_ap);
+       tmpnr = regno(t);
+       l = buildtree(ASSIGN, t, l);
+
+       if (p != parent) {
+               q = parent->n_left;
+       } else
+               q = NULL;
+
+       /* copy structure into registers */
+       for (i = 0; i < num; i++) {
+               t = tempnode(tmpnr, ty, 0, 0);
+               t = block(SCONV, t, NIL, PTR+INT, 0, 0);
+               t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
+               t = buildtree(UMUL, t, NIL);
+
+               r = block(REG, NIL, NIL, INT, 0, 0);
+               r->n_rval = reg++;
+
+                       r = buildtree(ASSIGN, r, t);
+               if (q == NULL)
+                       q = r;
+               else 
+                       q = block(CM, q, r, INT, 0, 0);
+       }
+       off = ARGINIT/SZINT + nargregs;
+       for (i = num; i < sz; i++) {
+               t = tempnode(tmpnr, ty, 0, 0);
+               t = block(SCONV, t, NIL, PTR+INT, 0, 0);
+               t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
+               t = buildtree(UMUL, t, NIL);
+
+               r = block(REG, NIL, NIL, INT, 0, 0);
+               r->n_rval = FP;
+               r = block(PLUS, r, bcon(4*off++), INT, 0, 0);
+               r = block(UMUL, r, NIL, INT, 0, 0);
+
+                       r = buildtree(ASSIGN, r, t);
+               if (q == NULL)
+                       q = r;
+               else
+                       q = block(CM, q, r, INT, 0, 0);
+       }
+
+       if (parent->n_op == CM) {
+               parent->n_left = q;
+               q = l;
+       } else {
+               q = block(CM, q, l, INT, 0, 0);
+       }
+
+       *regp = reg;
+       return q;
+}
+
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+       int reg = *regp;
+       NODE *q;
+       int lastarg;
+
+       /* alignment */
+       ++reg;
+       reg &= ~1;
+
+       lastarg = A0 + nargregs - 1;
+       if (reg > lastarg) {
+               *regp = reg;
+               return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap);
+       }
+
+       q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       q->n_rval = A0A1 + (reg - A0);
+       q = buildtree(ASSIGN, q, p);
+
+       *regp = reg + 2;
+       return q;
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+       int reg = *regp;
+       NODE *q;
+
+       q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       q->n_rval = reg++;
+       q = buildtree(ASSIGN, q, p);
+
+       *regp = reg;
+       return q;
+}
+
+static NODE *
+moveargs(NODE *p, int *regp)
+{
+        NODE *r, **rp;
+       int lastreg;
+       int reg;
+
+        if (p->n_op == CM) {
+                p->n_left = moveargs(p->n_left, regp);
+                r = p->n_right;
+               rp = &p->n_right;
+        } else {
+               r = p;
+               rp = &p;
+       }
+
+       lastreg = A0 + nargregs - 1;
+        reg = *regp;
+
+       if (reg > lastreg && r->n_op != STARG)
+               *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
+       else if (r->n_op == STARG) {
+               *rp = movearg_struct(r, p, regp);
+       } else if (DEUNSIGN(r->n_type) == LONGLONG) {
+               *rp = movearg_64bit(r, regp);
+       } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
+               /* XXX bounce in and out of temporary to change to longlong */
+               NODE *t1 = tempnode(0, LONGLONG, 0, 0);
+               int tmpnr = regno(t1);
+               NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+               t1 =  movearg_64bit(t1, regp);
+               r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
+               if (p->n_op == CM) {
+                       p->n_left = buildtree(CM, p->n_left, t1);
+                       p->n_right = r;
+               } else {
+                       p = buildtree(CM, t1, r);
+               }
+       } else if (r->n_type == FLOAT) {
+               /* XXX bounce in and out of temporary to change to int */
+               NODE *t1 = tempnode(0, INT, 0, 0);
+               int tmpnr = regno(t1);
+               NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+               t1 =  movearg_32bit(t1, regp);
+               r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
+               if (p->n_op == CM) {
+                       p->n_left = buildtree(CM, p->n_left, t1);
+                       p->n_right = r;
+               } else {
+                       p = buildtree(CM, t1, r);
+               }
+       } else {
+               *rp = movearg_32bit(r, regp);
+       }
+
+       return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       int regnum = A0;
+       NODE *l, *r, *t, *q;
+       int ty;
+
+       l = p->n_left;
+       r = p->n_right;
+
+       /*
+        * if returning a structure, make the first argument
+        * a hidden pointer to return structure.
+        */
+       ty = DECREF(l->n_type);
+       if (ty == STRTY+FTN || ty == UNIONTY+FTN) {
+               ty = DECREF(l->n_type) - FTN;
+               q = tempnode(0, ty, l->n_df, l->n_ap);
+               q = buildtree(ADDROF, q, NIL);
+               if (r->n_op != CM) {
+                       p->n_right = block(CM, q, r, INCREF(ty),
+                           l->n_df, l->n_ap);
+               } else {
+                       for (t = r; t->n_left->n_op == CM; t = t->n_left)
+                               ;
+                       t->n_left = block(CM, q, t->n_left, INCREF(ty),
+                           l->n_df, l->n_ap);
+               }
+       }
+
+       p->n_right = moveargs(p->n_right, &regnum);
+
+       return p;
+}
+
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       uerror("missing builtin_cfa");
+       return bcon(0);
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       uerror("missing builtin_frame_address");
+       return bcon(0);
+}
+
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{       
+       uerror("missing builtin_return_address");
+       return bcon(0);
+}
+
diff --git a/lang/pcc/pcc/arch/mips/local.c b/lang/pcc/pcc/arch/mips/local.c
new file mode 100644 (file)
index 0000000..b7e2f57
--- /dev/null
@@ -0,0 +1,796 @@
+/*     $Id: local.c,v 1.38 2016/03/05 15:56:14 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include "pass1.h"
+
+#ifndef LANG_CXX
+#define NODE P1ND
+#define ccopy p1tcopy
+#define tcopy p1tcopy
+#define tfree p1tfree
+#define nfree p1nfree
+#define fwalk p1fwalk
+#define talloc p1alloc
+#endif
+
+#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+/* this is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ */
+NODE *
+clocal(NODE *p)
+{
+       struct symtab *q;
+       NODE *r, *l;
+       int o;
+       int m;
+       TWORD ty;
+       int tmpnr, isptrvoid = 0;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal in: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       switch (o = p->n_op) {
+
+       case UCALL:
+       case CALL:
+       case STCALL:
+       case USTCALL:
+               if (p->n_type == VOID)
+                       break;
+               /*
+                * if the function returns void*, ecode() invokes
+                * delvoid() to convert it to uchar*.
+                * We just let this happen on the ASSIGN to the temp,
+                * and cast the pointer back to void* on access
+                * from the temp.
+                */
+               if (p->n_type == PTR+VOID)
+                       isptrvoid = 1;
+               r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               tmpnr = regno(r);
+               r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
+
+               p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+               if (isptrvoid) {
+                       p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0);
+               }
+               p = buildtree(COMOP, r, p);
+               break;
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       slval(r, 0);
+                       r->n_rval = FP;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case STATIC:
+                       if (q->slevel == 0)
+                               break;
+                       slval(p, 0);
+                       p->n_sp = q;
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       slval(p, 0);
+                       p->n_rval = q->soffset;
+                       break;
+
+               }
+               break;
+
+       case FUNARG:
+               /* Args smaller than int are given as int */
+               if (p->n_type != CHAR && p->n_type != UCHAR && 
+                   p->n_type != SHORT && p->n_type != USHORT)
+                       break;
+               p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
+               p->n_type = INT;
+               p->n_ap = 0;
+               p->n_rval = SZINT;
+               break;
+
+       case CBRANCH:
+               l = p->n_left;
+
+               /*
+                * Remove unnecessary conversion ops.
+                */
+               if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+                       if (coptype(l->n_op) != BITYPE)
+                               break;
+                       if (l->n_right->n_op == ICON) {
+                               r = l->n_left->n_left;
+                               if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+                                       break;
+                               /* Type must be correct */
+                               ty = r->n_type;
+                               nfree(l->n_left);
+                               l->n_left = r;
+                               l->n_type = ty;
+                               l->n_right->n_type = ty;
+                       }
+#if 0
+                         else if (l->n_right->n_op == SCONV &&
+                           l->n_left->n_type == l->n_right->n_type) {
+                               r = l->n_left->n_left;
+                               nfree(l->n_left);
+                               l->n_left = r;
+                               r = l->n_right->n_left;
+                               nfree(l->n_right);
+                               l->n_right = r;
+                       }
+#endif
+               }
+               break;
+
+       case PCONV:
+               /* Remove redundant PCONV's. Be careful */
+               l = p->n_left;
+               if (l->n_op == ICON) {
+                       slval(l, (unsigned)glval(l));
+                       goto delp;
+               }
+               if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+                       /* float etc? */
+                       p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0);
+                       break;
+               }
+               /* if left is SCONV, cannot remove */
+               if (l->n_op == SCONV)
+                       break;
+
+               /* avoid ADDROF TEMP */
+               if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+                       break;
+
+               /* if conversion to another pointer type, just remove */
+               if (p->n_type > BTMASK && l->n_type > BTMASK)
+                       goto delp;
+               break;
+
+       delp:   l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_ap = p->n_ap;
+               nfree(p);
+               p = l;
+               break;
+
+       case SCONV:
+               l = p->n_left;
+
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       p = l;
+                       break;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) ==
+                   tsize(l->n_type, l->n_df, l->n_ap)) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       p = l;
+                                       break;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       p = l;
+               }
+
+               if (DEUNSIGN(p->n_type) == SHORT &&
+                   DEUNSIGN(l->n_type) == SHORT) {
+                       nfree(p);
+                       p = l;
+               }
+
+               /* convert float/double to int before to (u)char/(u)short */
+               if ((DEUNSIGN(p->n_type) == CHAR ||
+                   DEUNSIGN(p->n_type) == SHORT) &&
+                    (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       break;
+                }
+
+               /* convert (u)char/(u)short to int before float/double */
+               if  ((p->n_type == FLOAT || p->n_type == DOUBLE ||
+                   p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
+                   DEUNSIGN(l->n_type) == SHORT)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       break;
+                }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       CONSZ val = glval(l);
+
+                       if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+                           switch (m) {
+                       case BOOL:
+                               val = nncon(l) ? (val != 0) : 1;
+                               slval(l, val);
+                               l->n_sp = NULL;
+                               break;
+                       case CHAR:
+                               slval(l, (char)val);
+                               break;
+                       case UCHAR:
+                               slval(l, val & 0377);
+                               break;
+                       case SHORT:
+                               slval(l, (short)val);
+                               break;
+                       case USHORT:
+                               slval(l, val & 0177777);
+                               break;
+                       case ULONG:
+                       case UNSIGNED:
+                               slval(l, val & 0xffffffff);
+                               break;
+                       case LONG:
+                       case INT:
+                               slval(l, (int)val);
+                               break;
+                       case LONGLONG:
+                               slval(l, (long long)val);
+                               break;
+                       case ULONGLONG:
+                               slval(l, val);
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = fltallo();
+                               FCAST(l->n_dcon)->fp = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", m);
+                       }
+                       l->n_type = m;
+                       nfree(p);
+                       p = l;
+               } else if (o == FCON) {
+                       CONSZ lv;
+                       if (p->n_type == BOOL)
+                               lv = !FLOAT_ISZERO(FCAST(l->n_dcon));
+                       else {
+                               FLOAT_FP2INT(lv, FCAST(l->n_dcon), m);
+                       }
+                       slval(l, lv);
+                       l->n_sp = NULL;
+                       l->n_op = ICON;
+                       l->n_type = m;
+                       l->n_ap = 0;
+                       nfree(p);
+                       p = clocal(l);
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
+               p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
+               p = block(SCONV, p, NIL, p->n_type, 0, 0);
+               p->n_left->n_type = INT;
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = RETREG(p->n_type);
+               break;
+       }
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal out: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+
+       if (p->n_op != FCON) 
+               return;
+
+       /* Write float constants to memory */
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       slval(p, 0);
+       p->n_sp = sp;
+
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
+               return(1);
+       return 0; /* XXX - fix reg assignment in pftn.c */
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+       int nbytes = off / SZCHAR;
+
+       p = buildtree(MUL, p, bcon(nbytes));
+       p = buildtree(PLUS, p, bcon(7));
+       p = buildtree(AND, p, bcon(~7));
+
+       /* subtract the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       slval(sp, 0);
+       sp->n_rval = SP;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       sp->n_rval = SP;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+        union { float f; double d; int i[2]; } u;
+        struct symtab *q;
+        TWORD t;
+#ifndef USE_GAS
+        int i, j;
+#endif
+
+        t = p->n_type;
+        if (t > BTMASK)
+               p->n_type = t = INT; /* pointer */
+
+        if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+                uerror("element not constant");
+
+        switch (t) {
+        case LONGLONG:
+        case ULONGLONG:
+#ifdef USE_GAS
+                printf("\t.dword %lld\n", (long long)glval(p));
+#else
+               i = glval(p) >> 32;
+                j = glval(p) & 0xffffffff;
+                p->n_type = INT;
+               if (bigendian) {
+                       slval(p, j);
+                       ninval(off, 32, p);
+                       slval(p, i);
+                       ninval(off+32, 32, p);
+               } else {
+                       slval(p, i);
+                       ninval(off, 32, p);
+                       slval(p, j);
+                       ninval(off+32, 32, p);
+               }
+#endif
+                break;
+        case INT:
+        case UNSIGNED:
+                printf("\t.word " CONFMT, (CONSZ)glval(p));
+                if ((q = p->n_sp) != NULL) {
+                        if ((q->sclass == STATIC && q->slevel > 0)) {
+                                printf("+" LABFMT, q->soffset);
+                        } else
+                                printf("+%s", getexname(q));
+                }
+                printf("\n");
+                break;
+        case SHORT:
+        case USHORT:
+               astypnames[SHORT] = astypnames[USHORT] = "\t.half";
+                return 0;
+        case LDOUBLE:
+        case DOUBLE:
+                u.d = (double)FCAST(p->n_dcon)->fp;
+               if (bigendian) {
+                       printf("\t.word\t%d\n", u.i[0]);
+                       printf("\t.word\t%d\n", u.i[1]);
+               } else {
+                       printf("\t.word\t%d\n", u.i[1]);
+                       printf("\t.word\t%d\n", u.i[0]);
+               }
+                break;
+        case FLOAT:
+                u.f = (float)FCAST(p->n_dcon)->fp;
+                printf("\t.word\t0x%x\n", u.i[0]);
+                break;
+        default:
+                return 0;
+        }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+       if (p == NULL)
+               return "";
+       return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+
+       }
+       return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off;
+
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       printf("        .%scomm ", sp->sclass == STATIC ? "l" : "");
+       if (sp->slevel == 0)
+               printf("%s,0%o\n", getexname(sp), off);
+       else
+               printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+
+#ifdef notdef
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+
+       printf("        .comm %s,%d\n", exname(q->soname), off);
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       if (q->slevel == 0)
+               printf("\t.lcomm %s,%d\n", exname(q->soname), off);
+       else
+               printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+/* ro-text, rw-data, ro-data, ro-strings */
+static char *loctbl[] = { "text", "data", "rdata", "rdata" };
+
+void
+setloc1(int locc)
+{
+       if (locc == lastloc && locc != STRNG)
+               return;
+       if (locc == RDATA && lastloc == STRNG)
+               return;
+
+       if (locc != lastloc) {
+               lastloc = locc;
+               printf("\t.%s\n", loctbl[locc]);
+       }
+
+       if (locc == STRNG)
+               printf("\t.align 2\n");
+}
+#endif
+
+/*
+ * va_start(ap, last) implementation.
+ *
+ * f is the NAME node for this builtin function.
+ * a is the argument list containing:
+ *        CM
+ *     ap   last
+ *
+ * It turns out that this is easy on MIPS.  Just write the
+ * argument registers to the stack in va_arg_start() and
+ * use the traditional method of walking the stackframe.
+ */
+NODE *
+mips_builtin_stdarg_start(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q;
+       int sz = 1;
+
+       /* check num args and type */
+       if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+           !ISPTR(a->n_left->n_type))
+               goto bad;
+
+       /* must first deal with argument size; use int size */
+       p = a->n_right;
+       if (p->n_type < INT) {
+               /* round up to word */
+               sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
+       }
+
+       p = buildtree(ADDROF, p, NIL);  /* address of last arg */
+       p = optim(buildtree(PLUS, p, bcon(sz)));
+       q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+       q = buildtree(CAST, q, p);
+       p = q->n_right;
+       nfree(q->n_left);
+       nfree(q);
+       p = buildtree(ASSIGN, a->n_left, p);
+       nfree(a);
+
+       return p;
+
+bad:
+       uerror("bad argument to __builtin_stdarg_start");
+       return bcon(0);
+}
+
+NODE *
+mips_builtin_va_arg(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q, *r;
+       int sz, tmpnr;
+
+       /* check num args and type */
+       if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+           !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+               goto bad;
+
+       r = a->n_right;
+
+       /* get type size */
+       sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
+       if (sz < SZINT/SZCHAR) {
+               werror("%s%s promoted to int when passed through ...",
+                       r->n_type & 1 ? "unsigned " : "",
+                       DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+               sz = SZINT/SZCHAR;
+       }
+
+       /* alignment */
+       p = tcopy(a->n_left);
+       if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
+               p = buildtree(PLUS, p, bcon(7));
+               p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
+       }
+
+       /* create a copy to a temp node */
+       q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+       tmpnr = regno(q);
+       p = buildtree(ASSIGN, q, p);
+
+       q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
+       q = buildtree(PLUS, q, bcon(sz));
+       q = buildtree(ASSIGN, a->n_left, q);
+
+       q = buildtree(COMOP, p, q);
+
+       nfree(a->n_right);
+       nfree(a);
+
+       p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
+       p = buildtree(UMUL, p, NIL);
+       p = buildtree(COMOP, q, p);
+
+       return p;
+
+bad:
+       uerror("bad argument to __builtin_va_arg");
+       return bcon(0);
+}
+
+NODE *
+mips_builtin_va_end(const struct bitable *bt, NODE *a)
+{
+       tfree(a);
+       return bcon(0);
+}
+
+NODE *
+mips_builtin_va_copy(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+
+       if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+               goto bad;
+       f = buildtree(ASSIGN, a->n_left, a->n_right);
+       nfree(a);
+       return f;
+
+bad:
+       uerror("bad argument to __buildtin_va_copy");
+       return bcon(0);
+}
+
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+
+       if (strcmp(str, "tls") == 0) { 
+               uerror("thread-local storage not supported for this target");
+               return 1;
+       } 
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+               printf("\t.section .%ctors,\"aw\",@progbits\n",
+                   constructor ? 'c' : 'd');
+               printf("\t.p2align 2\n");
+               printf("\t.long %s\n", exname(sp->sname));
+               printf("\t.previous\n");
+               constructor = destructor = 0;
+       }
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/mips/local2.c b/lang/pcc/pcc/arch/mips/local2.c
new file mode 100644 (file)
index 0000000..f3c8d6f
--- /dev/null
@@ -0,0 +1,1339 @@
+/*     $Id: local2.c,v 1.31 2016/01/06 16:11:24 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+#ifdef TARGET_BIG_ENDIAN
+int bigendian = 1;
+#else
+int bigendian = 0;
+#endif
+
+int nargregs = MIPS_O32_NARGREGS;
+
+static int argsiz(NODE *p);
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static int regoff[32];
+static TWORD ftype;
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog * ipp)
+{
+       int i, j, addto;
+
+       addto = p2maxautooff;
+
+       for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
+               if (i & 1) {
+                       addto += SZINT / SZCHAR;
+                       regoff[j] = addto;
+               }
+       }
+
+        /* round to 8-byte boundary */
+        addto += 7;
+        addto &= ~7;
+
+       return addto;
+}
+
+/*
+ * Print out the prolog assembler.
+ */
+void
+prologue(struct interpass_prolog * ipp)
+{
+       int addto;
+       int i, j;
+
+       ftype = ipp->ipp_type;
+       printf("\t.align 2\n");
+       if (ipp->ipp_vis)
+               printf("\t.globl %s\n", ipp->ipp_name);
+       printf("\t.ent %s\n", ipp->ipp_name);
+       printf("%s:\n", ipp->ipp_name);
+
+       addto = offcalc(ipp);
+
+       /* emit PIC only if -fpic or -fPIC set */
+       if (kflag > 0) {
+               printf("\t.frame %s,%d,%s\n",
+                   rnames[FP], ARGINIT/SZCHAR, rnames[RA]);
+               printf("\t.set noreorder\n");
+               printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n");
+               printf("\t.set reorder\n");
+       }
+
+       printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]);
+       printf("\t.set noreorder\n");
+       printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n");
+       printf("\t.set reorder\n");
+
+       printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR);
+       /* emit PIC only if -fpic or -fPIC set */
+       if (kflag > 0)
+               printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n");
+
+       printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]);
+       printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]);
+       printf("\tmove %s,%s\n", rnames[FP], rnames[SP]);
+
+#ifdef notyet
+       /* profiling */
+       if (pflag) {
+               printf("\t.set noat\n");
+               printf("\tmove %s,%s\t# save current return address\n",
+                   rnames[AT], rnames[RA]);
+               printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n",
+                   rnames[SP], rnames[SP]);
+               printf("\tjal %s\n", exname("_mcount"));
+               printf("\tnop\n");
+               printf("\t.set at\n");
+       }
+#endif
+
+       if (addto)
+               printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto);
+
+       for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++)
+               if (i & 1)
+                       printf("\tsw %s,-%d(%s) # save permanent\n",
+                               rnames[j], regoff[j], rnames[FP]);
+
+}
+
+void
+eoftn(struct interpass_prolog * ipp)
+{
+       int i, j;
+
+       (void) offcalc(ipp);
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return;         /* no code needs to be generated */
+
+       /* return from function code */
+       for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
+               if (i & 1)
+                       printf("\tlw %s,-%d(%s)\n\tnop\n",
+                               rnames[j], regoff[j], rnames[FP]);
+       }
+
+       printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR);
+       printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR,  rnames[SP]);
+       printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR,  rnames[SP]);
+
+       printf("\tjr %s\n", rnames[RA]);
+       printf("\tnop\n");
+
+#ifdef USE_GAS
+       printf("\t.end %s\n", ipp->ipp_name);
+       printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
+#endif
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case EQ:
+               str = "beqz";   /* pseudo-op */
+               break;
+       case NE:
+               str = "bnez";   /* pseudo-op */
+               break;
+       case ULE:
+       case LE:
+               str = "blez";
+               break;
+       case ULT:
+       case LT:
+               str = "bltz";
+               break;
+       case UGE:
+       case GE:
+               str = "bgez";
+               break;
+       case UGT:
+       case GT:
+               str = "bgtz";
+               break;
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0;        /* XXX gcc */
+       }
+
+       printf("%s%c", str, f);
+}
+
+char *
+rnames[] = {
+#ifdef USE_GAS
+       /* gnu assembler */
+       "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7",
+       "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+       "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+       "$24", "$25",
+       "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra",
+       "$2!!$3!!",
+       "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!",
+       "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!",
+       "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!",
+       "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!",
+       "$20!$21!", "$21!$22!", "$22!$23!",
+#else
+       /* mips assembler */
+        "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
+       "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
+       "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
+       "$t8", "$t9",
+       "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
+       "$v0!$v1!",
+       "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!",
+       "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!",
+       "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!",
+       "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
+       "$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
+#endif
+       "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
+       "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
+       "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
+       "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
+};
+
+char *
+rnames_n32[] = {
+       /* mips assembler */
+       "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
+       "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
+       "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
+       "$t8", "$t9",
+       "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
+       "$v0!$v1!",
+       "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!",
+       "$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!",
+       "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!",
+       "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
+       "$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
+       "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
+       "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
+       "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
+       "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
+};
+
+int
+tlen(NODE *p)
+{
+       switch (p->n_type) {
+       case CHAR:
+       case UCHAR:
+               return (1);
+
+       case SHORT:
+       case USHORT:
+               return (SZSHORT / SZCHAR);
+
+       case DOUBLE:
+               return (SZDOUBLE / SZCHAR);
+
+       case INT:
+       case UNSIGNED:
+       case LONG:
+       case ULONG:
+               return (SZINT / SZCHAR);
+
+       case LONGLONG:
+       case ULONGLONG:
+               return SZLONGLONG / SZCHAR;
+
+       default:
+               if (!ISPTR(p->n_type))
+                       comperr("tlen type %d not pointer");
+               return SZPOINT(p->n_type) / SZCHAR;
+       }
+}
+
+
+/*
+ * Push a structure on stack as argument.
+ */
+static void
+starg(NODE *p)
+{
+       int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       //assert(p->n_rval == A1);
+       printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], sz);
+       /* A0 = dest, A1 = src, A2 = len */
+       printf("\tmove %s,%s\n", rnames[A0], rnames[SP]);
+       printf("\tli %s,%d\t# structure size\n", rnames[A2], sz);
+       printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+       printf("\tjal %s\t# structure copy\n", exname("memcpy"));
+       printf("\tnop\n");
+       printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+/*
+ * Structure assignment.
+ */
+static void
+stasg(NODE *p)
+{
+       assert(p->n_right->n_rval == A1);
+       /* A0 = dest, A1 = src, A2 = len */
+       printf("\tli %s,%d\t# structure size\n", rnames[A2],
+           attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
+       if (p->n_left->n_op == OREG) {
+               printf("\taddiu %s,%s," CONFMT "\t# dest address\n",
+                   rnames[A0], rnames[p->n_left->n_rval],
+                   getlval(p->n_left));
+       } else if (p->n_left->n_op == NAME) {
+               printf("\tla %s,", rnames[A0]);
+               adrput(stdout, p->n_left);
+               printf("\n");
+       }
+       printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+       printf("\tjal %s\t# structure copy\n", exname("memcpy"));
+       printf("\tnop\n");
+       printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+static void
+shiftop(NODE *p)
+{
+       NODE *r = p->n_right;
+       TWORD ty = p->n_type;
+
+       if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) {
+               expand(p, INBREG, "\tsrl A1,AL,");
+               printf(CONFMT "\t# 64-bit left-shift\n", 32 - getlval(r));
+               expand(p, INBREG, "\tsll U1,UL,AR\n");
+               expand(p, INBREG, "\tor U1,U1,A1\n");
+               expand(p, INBREG, "\tsll A1,AL,AR\n");
+       } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) {
+               expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
+               expand(p, INBREG, "\tsll U1,AL,");
+               printf(CONFMT "\n", getlval(r) - 32);
+       } else if (p->n_op == LS && r->n_op == ICON) {
+               expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
+               expand(p, INBREG, "\tli U1,0\n");
+       } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) {
+               expand(p, INBREG, "\tsll U1,UL,");
+               printf(CONFMT "\t# 64-bit right-shift\n", 32 - getlval(r));
+               expand(p, INBREG, "\tsrl A1,AL,AR\n");
+               expand(p, INBREG, "\tor A1,A1,U1\n");
+               if (ty == LONGLONG)
+                       expand(p, INBREG, "\tsra U1,UL,AR\n");
+               else
+                       expand(p, INBREG, "\tsrl U1,UL,AR\n");
+       } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) {
+               if (ty == LONGLONG) {
+                       expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n");
+                       expand(p, INBREG, "\tsra A1,UL,");
+               }else {
+                       expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n");
+                       expand(p, INBREG, "\tsrl A1,UL,");
+               }
+               printf(CONFMT "\n", getlval(r) - 32);
+       } else if (p->n_op == LS && r->n_op == ICON) {
+               expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n");
+               expand(p, INBREG, "\tli U1,0\n");
+       } else {
+               comperr("shiftop");
+       }
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
+ */
+static void
+fpemulop(NODE *p)
+{
+       NODE *l = p->n_left;
+       char *ch = NULL;
+
+       if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+       else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+       else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
+
+       else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+       else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+       else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
+
+       else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+       else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+       else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
+
+       else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+       else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+       else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
+
+       else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+       else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+       else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
+
+       else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+       else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+       else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
+
+       else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+       else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+       else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
+
+       else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+       else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+       else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
+
+       else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+       else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+       else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
+
+       else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+       else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+       else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
+
+       else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+       else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+       else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
+
+       else if (p->n_op == SCONV && p->n_type == FLOAT) {
+               if (l->n_type == DOUBLE) ch = "truncdfsf2";
+               else if (l->n_type == LDOUBLE) ch = "trunctfsf2";
+               else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/
+               else if (l->n_type == LONGLONG) ch = "floatdisf";
+               else if (l->n_type == LONG) ch = "floatsisf";
+               else if (l->n_type == ULONG) ch = "floatunsisf";
+               else if (l->n_type == INT) ch = "floatsisf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+       } else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+               if (l->n_type == FLOAT) ch = "extendsfdf2";
+               else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+               else if (l->n_type == LONGLONG) ch = "floatdidf";
+               else if (l->n_type == LONG) ch = "floatsidf";
+               else if (l->n_type == ULONG) ch = "floatunsidf";
+               else if (l->n_type == INT) ch = "floatsidf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+       } else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+               if (l->n_type == FLOAT) ch = "extendsftf2";
+               else if (l->n_type == DOUBLE) ch = "extenddfdf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+               else if (l->n_type == LONGLONG) ch = "floatdidf";
+               else if (l->n_type == LONG) ch = "floatsidf";
+               else if (l->n_type == ULONG) ch = "floatunssidf";
+               else if (l->n_type == INT) ch = "floatsidf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+       } else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+               if (l->n_type == FLOAT) ch = "fixunssfdi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+       } else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+               if (l->n_type == FLOAT) ch = "fixsfdi";
+               else if (l->n_type == DOUBLE) ch = "fixdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+       } else if (p->n_op == SCONV && p->n_type == LONG) {
+               if (l->n_type == FLOAT) ch = "fixsfsi";
+               else if (l->n_type == DOUBLE) ch = "fixdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+       } else if (p->n_op == SCONV && p->n_type == ULONG) {
+               if (l->n_type == FLOAT) ch = "fixunssfsi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+       } else if (p->n_op == SCONV && p->n_type == INT) {
+               if (l->n_type == FLOAT) ch = "fixsfsi";
+               else if (l->n_type == DOUBLE) ch = "fixdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+       } else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+               if (l->n_type == FLOAT) ch = "fixunssfsi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+       }
+
+       if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+       if (p->n_op == SCONV) {
+               if (l->n_type == FLOAT) {
+                       printf("\tmfc1 %s,", rnames[A0]);
+                       adrput(stdout, l);
+                       printf("\n\tnop\n");
+               }  else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) {
+                       printf("\tmfc1 %s,", rnames[A1]);
+                       upput(l, 0);
+                       printf("\n\tnop\n");
+                       printf("\tmfc1 %s,", rnames[A0]);
+                       adrput(stdout, l);
+                       printf("\n\tnop\n");
+               }
+       } else {
+               comperr("ZF: incomplete softfloat - put args in registers");
+       }
+
+       printf("\tjal __%s\t# softfloat operation\n", exname(ch));
+       printf("\tnop\n");
+
+       if (p->n_op >= EQ && p->n_op <= GT)
+               printf("\tcmp %s,0\n", rnames[V0]);
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+static void
+emulop(NODE *p)
+{
+       char *ch = NULL;
+
+       if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+       else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
+           DEUNSIGN(p->n_type) == INT))
+               ch = "ashlsi3";
+
+       else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+       else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
+               ch = "lshrsi3";
+
+       else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+       else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
+               ch = "ashrsi3";
+       
+       else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+       else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
+               ch = "divsi3";
+
+       else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+       else if (p->n_op == DIV && (p->n_type == ULONG ||
+           p->n_type == UNSIGNED))
+               ch = "udivsi3";
+
+       else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+       else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
+               ch = "modsi3";
+
+       else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+       else if (p->n_op == MOD && (p->n_type == ULONG ||
+           p->n_type == UNSIGNED))
+               ch = "umodsi3";
+
+       else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+       else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
+               ch = "mulsi3";
+
+       else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+       else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
+
+       else ch = 0, comperr("ZE");
+       printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+       printf("\tjal __%s\t# emulated operation\n", exname(ch));
+       printf("\tnop\n");
+       printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int o = p->n_op;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       if (o >= ULE)
+               o -= (ULE-LE);
+       switch (o) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n");
+       if (cb1) {
+               printf("\t");
+               hopcode(' ', cb1);
+               expand(p, 0, "A1");
+               printf("," LABFMT "\n", s);
+               printf("\tnop\n");
+       }
+       if (cb2) {
+               printf("\t");
+               hopcode(' ', cb2);
+               expand(p, 0, "A1");
+               printf("," LABFMT "\n", e);
+               printf("\tnop\n");
+       }
+       expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n");
+       printf("\t");
+       hopcode(' ', o);
+       expand(p, 0, "A1");
+       printf("," LABFMT "\n", e);
+       printf("\tnop\n");
+       deflab(s);
+}
+
+static void
+fpcmpops(NODE *p)
+{
+       NODE *l = p->n_left;
+
+       switch (p->n_op) {
+       case EQ:
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tc.eq.s AL,AR\n");
+               else
+                       expand(p, 0, "\tc.eq.d AL,AR\n");
+               expand(p, 0, "\tnop\n\tbc1t LC\n");
+               break;
+       case NE:
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tc.eq.s AL,AR\n");
+               else
+                       expand(p, 0, "\tc.eq.d AL,AR\n");
+               expand(p, 0, "\tnop\n\tbc1f LC\n");
+               break;
+       case LT:
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tc.lt.s AL,AR\n");
+               else
+                       expand(p, 0, "\tc.lt.d AL,AR\n");
+               expand(p, 0, "\tnop\n\tbc1t LC\n");
+               break;
+       case GE:
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tc.lt.s AL,AR\n");
+               else
+                       expand(p, 0, "\tc.lt.d AL,AR\n");
+               expand(p, 0, "\tnop\n\tbc1f LC\n");
+               break;
+       case LE:
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tc.le.s AL,AR\n");
+               else
+                       expand(p, 0, "\tc.le.d AL,AR\n");
+               expand(p, 0, "\tnop\n\tbc1t LC\n");
+               break;
+       case GT:
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tc.le.s AL,AR\n");
+               else
+                       expand(p, 0, "\tc.le.d AL,AR\n");
+               expand(p, 0, "\tnop\n\tbc1f LC\n");
+               break;
+       }
+       printf("\tnop\n\tnop\n");
+}
+
+void
+zzzcode(NODE * p, int c)
+{
+       int sz;
+
+       switch (c) {
+
+       case 'C':       /* remove arguments from stack after subroutine call */
+               sz = p->n_qual > 16 ? p->n_qual : 16;
+               printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz);
+               break;
+
+       case 'D':       /* long long comparison */
+               twollcomp(p);
+               break;
+
+       case 'E':       /* emit emulated ops */
+               emulop(p);
+               break;
+
+       case 'F':       /* emit emulate floating point ops */
+               fpemulop(p);
+               break;
+
+       case 'G':       /* emit hardware floating-point compare op */
+               fpcmpops(p);
+               break;
+
+       case 'H':       /* structure argument */
+               starg(p);
+               break;
+
+       case 'I':               /* high part of init constant */
+               if (p->n_name[0] != '\0')
+                       comperr("named highword");
+               printf(CONFMT, (getlval(p) >> 32) & 0xffffffff);
+               break;
+
+        case 'O': /* 64-bit left and right shift operators */
+               shiftop(p);
+               break;
+
+       case 'Q':               /* emit struct assign */
+               stasg(p);
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+/* ARGSUSED */
+int
+rewfld(NODE * p)
+{
+       return (1);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+        CONSZ val;
+
+        if (p->n_op == ASSIGN)
+                p = p->n_left;
+        switch (**cp) {
+        case 'S':
+                printf("%d", UPKFSZ(p->n_rval));
+                break;
+        case 'H':
+                printf("%d", UPKFOFF(p->n_rval));
+                break;
+        case 'M':
+        case 'N':
+                val = (CONSZ)1 << UPKFSZ(p->n_rval);
+                --val;
+                val <<= UPKFOFF(p->n_rval);
+                printf("0x%llx", (**cp == 'M' ? val : ~val)  & 0xffffffff);
+                break;
+        default:
+                comperr("fldexpand");
+        }
+        return 1;
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE * p)
+{
+       int o = p->n_op;
+
+       if (o == OREG || o == REG || o == NAME)
+               return SRDIR;   /* Direct match */
+       if (o == UMUL && shumul(p->n_left, SOREG))
+               return SROREG;  /* Convert into oreg */
+       return SRREG;           /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE * p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG)
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return (0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return (0);
+       return (1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = getlval(p);
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (getlval(p))
+                               fprintf(fp, "+%d", val);
+               } else
+                       fprintf(fp, "%d", val);
+               return;
+
+       default:
+               comperr("illegal conput");
+       }
+}
+
+/* ARGSUSED */
+void
+insput(NODE * p)
+{
+       comperr("insput");
+}
+
+/*
+ * Print lower or upper name of 64-bit register.
+ */
+static void
+print_reg64name(FILE *fp, int rval, int hi)
+{
+        int off = 4 * (hi != 0);
+       char *regname = rnames[rval];
+
+        fprintf(fp, "%c%c",
+                 regname[off],
+                 regname[off + 1]);
+        if (regname[off + 2] != '!')
+                fputc(regname[off + 2], fp);
+        if (regname[off + 3] != '!')
+                fputc(regname[off + 3], fp);
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE * p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
+                       print_reg64name(stdout, p->n_rval, 1);
+               else
+                       printf("%s", rnames[p->n_rval]);
+               break;
+
+       case NAME:
+       case OREG:
+               setlval(p, getlval(p) + size);
+               adrput(stdout, p);
+               setlval(p, getlval(p) - size);
+               break;
+       case ICON:
+               printf(CONFMT, getlval(p) >> 32);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE * io, NODE * p)
+{
+       /* output an address, with offsets, from p */
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0')
+                       fputs(p->n_name, io);
+               if (getlval(p) != 0)
+                       fprintf(io, "+" CONFMT, getlval(p));
+               return;
+
+       case OREG:
+               if (getlval(p))
+                       fprintf(io, "%d", (int) getlval(p));
+               fprintf(io, "(%s)", rnames[p->n_rval]);
+               return;
+
+       case ICON:
+               /* addressable value of the constant */
+               conput(io, p);
+               return;
+
+       case REG:
+               if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
+                       print_reg64name(io, p->n_rval, 0);
+               else
+                       fputs(rnames[p->n_rval], io);
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+}
+
+void
+myreader(struct interpass * ipole)
+{
+}
+
+#if 0
+/*
+ *  Calculate the stack size for arguments
+ */
+static int stacksize;
+
+static void
+calcstacksize(NODE *p, void *arg)
+{
+       int sz;
+
+       printf("op=%d\n", p->n_op);
+
+       if (p->n_op != CALL && p->n_op != STCALL)
+               return;
+
+       sz = argsiz(p->n_right);
+       if (sz > stacksize)
+               stacksize = sz;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("stacksize: %d\n", stacksize);
+#endif
+}
+#endif
+
+/*
+ * If we're big endian, then all OREG loads of a type
+ * larger than the destination, must have the
+ * offset changed to point to the correct bytes in memory.
+ */
+static void
+offchg(NODE *p, void *arg)
+{
+       NODE *l;
+
+       if (p->n_op != SCONV)
+               return;
+
+       l = p->n_left;
+
+       if (l->n_op != OREG)
+               return;
+
+       switch (l->n_type) {
+       case SHORT:
+       case USHORT:
+               if (DEUNSIGN(p->n_type) == CHAR)
+                       setlval(l, getlval(l) + 1);
+               break;
+       case LONG:
+       case ULONG:
+       case INT:
+       case UNSIGNED:
+               if (DEUNSIGN(p->n_type) == CHAR)
+                       setlval(l, getlval(l + 3));
+               else if (DEUNSIGN(p->n_type) == SHORT)
+                       setlval(l, getlval(l + 2));
+               break;
+       case LONGLONG:
+       case ULONGLONG:
+               if (DEUNSIGN(p->n_type) == CHAR)
+                       setlval(l, getlval(l + 7));
+               else if (DEUNSIGN(p->n_type) == SHORT)
+                       setlval(l, getlval(l + 6));
+               else if (DEUNSIGN(p->n_type) == INT ||
+                   DEUNSIGN(p->n_type) == LONG)
+                       setlval(l, getlval(l + 4));
+               break;
+       default:
+               comperr("offchg: unknown type");
+               break;
+       }
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE * p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE * p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass * ipole)
+{
+       struct interpass *ip;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("myoptim:\n");
+#endif
+
+#if 0
+       stacksize = 0;
+#endif
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               if (bigendian)
+                       walkf(ip->ip_node, offchg, 0);
+#if 0
+               walkf(ip->ip_node, calcstacksize, 0);
+#endif
+       }
+}
+
+/*
+ * Move data between registers.  While basic registers aren't a problem,
+ * we have to handle the special case of overlapping composite registers.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+        switch (t) {
+        case LONGLONG:
+        case ULONGLONG:
+                if (s == d+1) {
+                        /* dh = sl, copy low word first */
+                        printf("\tmove ");
+                       print_reg64name(stdout, d, 0);
+                       printf(",");
+                       print_reg64name(stdout, s, 0);
+                       printf("\t# 64-bit rmove\n");
+                        printf("\tmove ");
+                       print_reg64name(stdout, d, 1); 
+                       printf(",");
+                       print_reg64name(stdout, s, 1);
+                       printf("\n");
+                } else {
+                        /* copy high word first */
+                        printf("\tmove ");
+                       print_reg64name(stdout, d, 1);
+                       printf(",");
+                       print_reg64name(stdout, s, 1);
+                       printf(" # 64-bit rmove\n");
+                        printf("\tmove ");
+                       print_reg64name(stdout, d, 0);
+                       printf(",");
+                       print_reg64name(stdout, s, 0);
+                       printf("\n");
+                }
+                break;
+       case FLOAT:
+       case DOUBLE:
+        case LDOUBLE:
+               if (t == FLOAT)
+                       printf("\tmov.s ");
+               else
+                       printf("\tmov.d ");
+               print_reg64name(stdout, d, 0);
+               printf(",");
+               print_reg64name(stdout, s, 0);
+               printf("\t# float/double rmove\n");
+                break;
+        default:
+                printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]);
+        }
+}
+
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ *
+ * On MIPS, we have:
+ *
+ * 32 32-bit registers (8 reserved)
+ * 26 64-bit pseudo registers (1 unavailable)
+ * 16 floating-point register pairs
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num = 0;
+
+        switch (c) {
+        case CLASSA:
+                num += r[CLASSA];
+                num += 2*r[CLASSB];
+                return num < 24;
+        case CLASSB:
+                num += 2*r[CLASSB];
+                num += r[CLASSA];
+                return num < 25;
+       case CLASSC:
+               num += r[CLASSC];
+               return num < 6;
+        }
+       comperr("COLORMAP");
+        return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == LONGLONG || t == ULONGLONG)
+               return CLASSB;
+       if (t >= FLOAT && t <= LDOUBLE)
+               return CLASSC;
+       return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       int sz;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("lastcall:\n");
+#endif
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+
+       sz = argsiz(p->n_right);
+
+       if ((sz > 4*nargregs) && (sz & 7) != 0) {
+               printf("\tsubu %s,%s,4\t# align stack\n",
+                   rnames[SP], rnames[SP]);
+               sz += 4;
+               assert((sz & 7) == 0);
+       }
+
+       p->n_qual = sz; /* XXX */
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t;
+       int size = 0;
+       int sz = 0;
+
+       if (p->n_op == CM) {
+               size = argsiz(p->n_left);
+               p = p->n_right;
+       }
+
+       t = p->n_type;
+       if (t < LONGLONG || t > BTMASK)
+               sz = 4;
+       else if (DEUNSIGN(t) == LONGLONG)
+               sz = 8;
+       else if (t == DOUBLE || t == LDOUBLE)
+               sz = 8;
+       else if (t == FLOAT)
+               sz = 4;
+       else if (t == STRTY || t == UNIONTY)
+               sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+
+       if (p->n_type == STRTY || p->n_type == UNIONTY) {
+               return (size + sz);
+       }
+
+       /* alignment */
+       if (sz == 8 && (size & 7) != 0)
+               sz += 4;
+
+//     printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
+       return (size + sz);
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       int o = p->n_op;
+
+       if (o != ICON || p->n_name[0] != 0)
+               return SRNOPE;
+
+       switch(shape) {
+       case SPCON:
+               if ((getlval(p) & ~0xffff) == 0)
+                       return SRDIR;
+               break;
+       }
+
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+       if (strcasecmp(str, "big-endian") == 0) {
+               bigendian = 1;
+       } else if (strcasecmp(str, "little-endian") == 0) {
+               bigendian = 0;
+       } else {
+               fprintf(stderr, "unknown m option '%s'\n", str);
+               exit(1);
+       }
+
+#if 0
+        else if (strcasecmp(str, "ips2")) {
+       } else if (strcasecmp(str, "ips2")) {
+       } else if (strcasecmp(str, "ips3")) {
+       } else if (strcasecmp(str, "ips4")) {
+       } else if (strcasecmp(str, "hard-float")) {
+       } else if (strcasecmp(str, "soft-float")) {
+       } else if (strcasecmp(str, "abi=32")) {
+               nargregs = MIPS_O32_NARGREGS;
+       } else if (strcasecmp(str, "abi=n32")) {
+               nargregs = MIPS_N32_NARGREGS;
+       } else if (strcasecmp(str, "abi=64")) {
+               nargregs = MIPS_N32_NARGREGS;
+       }
+#endif
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/mips/macdefs.h b/lang/pcc/pcc/arch/mips/macdefs.h
new file mode 100644 (file)
index 0000000..7bf9577
--- /dev/null
@@ -0,0 +1,359 @@
+/*     $Id: macdefs.h,v 1.23 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+#if defined(os_netbsd) || defined(os_litebsd)
+#define USE_GAS
+#endif
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise 
+ * treat it as an integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT                (16*8)  /* # bits above fp where arguments start */
+#define AUTOINIT       (0)     /* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         32
+#define SZINT          32
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      64
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         32
+#define ALINT          32
+#define ALFLOAT                32
+#define ALDOUBLE       64
+#define ALLDOUBLE      64
+#define ALLONG         32
+#define ALLONGLONG     64
+#define ALSHORT                16
+#define ALPOINT                32
+#define ALSTRUCT       64
+#define ALSTACK                32 
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         (-0x7fffffff-1)
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffffU
+#define        MIN_LONG        MIN_INT
+#define        MAX_LONG        MAX_INT
+#define        MAX_ULONG       MAX_UNSIGNED
+#define        MIN_LONGLONG    (-0x7fffffffffffffffLL-1)
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+#undef CHAR_UNSIGNED
+#define BOOL_TYPE      INT
+
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#ifdef USE_GAS
+#define LABFMT "$L%d"          /* format for printing labels */
+#define        STABLBL "$LL%d"         /* format for stab (debugging) labels */
+#else
+#define LABFMT "L%d"           /* format for printing labels */
+#define        STABLBL "LL%d"          /* format for stab (debugging) labels */
+#endif
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_LE
+#define        MYALIGN
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+
+#define        szty(t)         (((t) == DOUBLE || (t) == LDOUBLE || \
+       DEUNSIGN(t) == LONGLONG) ? 2 : 1)
+
+/*
+ * Register names.  These must match rnames[] and rstatus[] in local2.c.
+ */
+#define ZERO   0
+#define AT     1
+#define V0     2
+#define V1     3
+#define A0     4
+#define A1     5
+#define A2     6
+#define A3     7
+#define A4     8
+#define A5     9
+#define A6     10
+#define A7     11
+#if defined(MIPS_N32) || defined(MIPS_N64)
+#define T0     12
+#define T1     13
+#define        T2      14
+#define        T3      15
+#else
+#define        T0      8
+#define        T1      9
+#define        T2      10
+#define        T3      11
+#endif
+#define        T4      12
+#define        T5      13
+#define        T6      14
+#define        T7      15
+#define S0     16
+#define S1     17
+#define S2     18
+#define S3     19
+#define S4     20
+#define S5     21
+#define S6     22
+#define S7     23
+#define T8     24
+#define T9     25
+#define K0     26
+#define K1     27
+#define GP     28
+#define SP     29
+#define FP     30
+#define RA     31
+
+#define V0V1   32
+#define A0A1   33
+#define A1A2   34
+#define A2A3   35
+
+/* we just use o32 naming here, but it works ok for n32/n64 */
+#define A3T0   36
+#define T0T1   37
+#define T1T2   38
+#define T2T3   39
+#define T3T4   40
+#define T4T5   41
+#define T5T6   42
+#define T6T7   43
+#define T7T8   44
+
+#define T8T9   45
+#define S0S1   46
+#define S1S2   47
+#define S2S3   48
+#define S3S4   49
+#define S4S5   50
+#define S5S6   51
+#define S6S7   52
+
+#define F0     53
+#define F2     54
+#define F4     55
+#define F6     56
+#define F8     57
+#define F10    58
+#define F12    59
+#define F14    60
+#define F16    61
+#define F18    62
+#define F20    63
+/* and the rest for later */
+#define F22    64
+#define F24    65
+#define F26    66
+#define F28    67
+#define F30    68
+
+#define MAXREGS 64
+#define NUMCLASS 3
+
+#define RETREG(x)      (DEUNSIGN(x) == LONGLONG ? V0V1 : \
+                           (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \
+                           F0 : V0)
+#define FPREG  FP      /* frame pointer */
+
+#define MIPS_N32_NARGREGS      8
+#define MIPS_O32_NARGREGS      4
+
+#define RSTATUS \
+       0, 0,                                                           \
+       SAREG|TEMPREG, SAREG|TEMPREG,                                   \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|TEMPREG, SAREG|TEMPREG,                                   \
+       0, 0,                                                           \
+       0, 0, 0, 0,                                                     \
+       \
+       SBREG|TEMPREG,                                                  \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,                    \
+       SBREG|TEMPREG,                                                  \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,                    \
+       SBREG|TEMPREG, SBREG|TEMPREG,                                   \
+       SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,     \
+       SBREG, SBREG, SBREG, SBREG,                                     \
+       SBREG, SBREG, SBREG,                                            \
+       SCREG, SCREG, SCREG, SCREG,                                     \
+       SCREG, SCREG, SCREG, SCREG,                                     \
+       SCREG, SCREG, SCREG,                                            \
+
+#define ROVERLAP \
+       { -1 },                         /* $zero */                     \
+       { -1 },                         /* $at */                       \
+       { V0V1, -1 },                   /* $v0 */                       \
+       { V0V1, -1 },                   /* $v1 */                       \
+       { A0A1, -1 },                   /* $a0 */                       \
+       { A0A1, A1A2, -1 },             /* $a1 */                       \
+       { A1A2, A2A3, -1 },             /* $a2 */                       \
+       { A2A3, A3T0, -1 },             /* $a3 */                       \
+       { A3T0, T0T1, -1 },             /* $t0 */                       \
+       { T0T1, T1T2, -1 },             /* $t1 */                       \
+       { T1T2, T2T3, -1 },             /* $t2 */                       \
+       { T2T3, T3T4, -1 },             /* $t3 */                       \
+       { T3T4, T4T5, -1 },             /* $t4 */                       \
+       { T4T5, T5T6, -1 },             /* $t5 */                       \
+       { T6T7, T7T8, -1 },             /* $t6 */                       \
+       { T7T8, T8T9, -1 },             /* $t7 */                       \
+       \
+       { S0S1, -1 },                   /* $s0 */                       \
+       { S0S1, S1S2, -1 },             /* $s1 */                       \
+       { S1S2, S2S3, -1 },             /* $s2 */                       \
+       { S2S3, S3S4, -1 },             /* $s3 */                       \
+       { S3S4, S4S5, -1 },             /* $s4 */                       \
+       { S4S5, S5S6, -1 },             /* $s5 */                       \
+       { S5S6, S6S7, -1 },             /* $s6 */                       \
+       { S6S7, -1 },                   /* $s7 */                       \
+       \
+       { T7T8, T8T9, -1 },             /* $t8 */                       \
+       { T8T9, -1 },                   /* $t9 */                       \
+       \
+       { -1 },                         /* $k0 */                       \
+       { -1 },                         /* $k1 */                       \
+       { -1 },                         /* $gp */                       \
+       { -1 },                         /* $sp */                       \
+       { -1 },                         /* $fp */                       \
+       { -1 },                         /* $ra */                       \
+       \
+       { V0, V1, -1 },                 /* $v0:$v1 */                   \
+       \
+       { A0, A1, A1A2, -1 },           /* $a0:$a1 */                   \
+       { A1, A2, A0A1, A2A3, -1 },     /* $a1:$a2 */                   \
+       { A2, A3, A1A2, A3T0, -1 },     /* $a2:$a3 */                   \
+       { A3, T0, A2A3, T0T1, -1 },     /* $a3:$t0 */                   \
+       { T0, T1, A3T0, T1T2, -1 },     /* $t0:$t1 */                   \
+       { T1, T2, T0T1, T2T3, -1 },     /* $t1:$t2 */                   \
+       { T2, T3, T1T2, T3T4, -1 },     /* $t2:$t3 */                   \
+       { T3, T4, T2T3, T4T5, -1 },     /* $t3:$t4 */                   \
+       { T4, T5, T3T4, T5T6, -1 },     /* $t4:$t5 */                   \
+       { T5, T6, T4T5, T6T7, -1 },     /* $t5:$t6 */                   \
+       { T6, T7, T5T6, T7T8, -1 },     /* $t6:$t7 */                   \
+       { T7, T8, T6T7, T8T9, -1 },     /* $t7:$t8 */                   \
+       { T8, T9, T7T8, -1 },           /* $t8:$t9 */                   \
+       \
+       { S0, S1, S1S2, -1 },           /* $s0:$s1 */                   \
+       { S1, S2, S0S1, S2S3, -1 },                                     \
+       { S2, S3, S1S2, S3S4, -1 },                                     \
+       { S3, S4, S2S3, S4S5, -1 },                                     \
+       { S4, S5, S3S4, S5S6, -1 },                                     \
+       { S5, S6, S4S5, S6S7, -1 },                                     \
+       { S6, S7, S5S6, -1 },                                           \
+       \
+       { -1 }, { -1 }, { -1 }, { -1 },                                 \
+       { -1 }, { -1 }, { -1 }, { -1 },                                 \
+       { -1 }, { -1 }, { -1 },                                         \
+
+#define GCLASS(x)      (x < 32 ? CLASSA : (x < 52 ? CLASSB : CLASSC))
+#define PCLASS(p)      (1 << gclass((p)->n_type))
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+#define ENCRD(x)       (x)                     /* Encode dest reg in n_reg */
+
+int COLORMAP(int c, int *r);
+
+extern int bigendian;
+extern int nargregs;
+
+#define SPCON           (MAXSPECIAL+1)  /* positive constant */
+
+#define TARGET_STDARGS
+#define TARGET_BUILTINS                                                        \
+       { "__builtin_stdarg_start", mips_builtin_stdarg_start,         \
+                                               0, 2, 0, VOID },        \
+       { "__builtin_va_start", mips_builtin_stdarg_start,             \
+                                               0, 2, 0, VOID },        \
+       { "__builtin_va_arg", mips_builtin_va_arg, BTNORVAL|BTNOPROTO, \
+                                                       2, 0, 0 },      \
+       { "__builtin_va_end", mips_builtin_va_end, 0, 1, 0, VOID },    \
+       { "__builtin_va_copy", mips_builtin_va_copy, 0, 2, 0, VOID },
+
+#ifdef LANG_CXX
+#define P1ND struct node
+#else
+#define P1ND struct p1node
+#endif
+struct node;
+struct bitable;
+P1ND *mips_builtin_stdarg_start(const struct bitable *, P1ND *a);
+P1ND *mips_builtin_va_arg(const struct bitable *, P1ND *a);
+P1ND *mips_builtin_va_end(const struct bitable *, P1ND *a);
+P1ND *mips_builtin_va_copy(const struct bitable *, P1ND *a);
+#undef P1ND
diff --git a/lang/pcc/pcc/arch/mips/order.c b/lang/pcc/pcc/arch/mips/order.c
new file mode 100644 (file)
index 0000000..24f6351
--- /dev/null
@@ -0,0 +1,259 @@
+/*     $Id: order.c,v 1.12 2008/11/30 21:00:24 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include "pass2.h"
+
+/*
+ * is it legal to make an OREG or NAME entry which has an offset of off,
+ * (from a register of r), if the resulting thing had type t
+ */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       /*
+        * although the hardware doesn't permit offsets greater
+        * than +/- 32K, the assembler fixes it for us.
+        */
+       return 0;               /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+void
+offstar(NODE * p, int shape)
+{
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (p->n_op == PLUS || p->n_op == MINUS) {
+               if (p->n_right->n_op == ICON) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE * q)
+{
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Always turn it into OREG */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE * p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE * p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return (0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE * p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ * - left is the register that left node wants.
+ * - right is the register that right node wants.
+ * - res is in which register the result will end up.
+ * - mask is registers that will be clobbered.
+ */
+struct rspecial *
+nspecial(struct optab * q)
+{
+       switch (q->op) {
+
+       case SCONV:
+               if (q->lshape == SBREG && q->rshape == SCREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, A0A1 },
+                               { NRES, F0 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SCREG && q->rshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, F0 },
+                               { NRES, A0A1 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG && q->rshape == SCREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, A0 },
+                               { NRES, F0 },
+                               { 0 }
+                       };
+                       return s;
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, A0A1 },
+                               { NRIGHT, A2A3 },
+                               { NRES, V0V1 },
+                               { 0 },
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, A0 },
+                               { NRIGHT, A1 },
+                               { NRES, V0 },
+                               { 0 },
+                       };
+                       return s;
+               }
+
+       case RS:
+       case LS:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, A0A1 },
+                               { NRIGHT, A2 },
+                               { NRES, V0V1 },
+                               { 0 },
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, A0 },
+                               { NRIGHT, A1 },
+                               { NRES, V0 },
+                               { 0 },
+                       };
+                       return s;
+               }
+               break;
+
+       case STARG:
+                {
+                        static struct rspecial s[] = {
+                                { NEVER, A0 },
+                                { NLEFT, A1 },
+                                { NEVER, A2 },
+                                { 0 }
+                       };
+                        return s;
+                }
+
+        case STASG:
+                {
+                        static struct rspecial s[] = {
+                                { NEVER, A0 },
+                                { NRIGHT, A1 },
+                                { NEVER, A2 },
+                                { 0 }
+                       };
+                        return s;
+                }
+       }
+
+       comperr("nspecial entry %d: %s", q - table, q->cstring);
+
+       return 0;               /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE * p)
+{
+       return 0;               /* nothing differs */
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[1] = { -1 }; /* Terminate with -1 */
+
+       return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/mips/table.c b/lang/pcc/pcc/arch/mips/table.c
new file mode 100644 (file)
index 0000000..94c55b6
--- /dev/null
@@ -0,0 +1,1326 @@
+/*     $Id: table.c,v 1.18 2016/01/05 12:23:22 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ *
+ * It appears that the target machine was big endian.  The original
+ * code contained many endian aspects which are now handled in
+ * machine-independent code.
+ * 
+ * On MIPS, the assembler does an amazing amount of work for us.
+ * We don't have to worry about PIC, nor about finding the address
+ * of SNAMES.  Whenever possible, we defer the work to the assembler.
+ */
+
+#include "pass2.h"
+
+#define TUWORD TUNSIGNED|TULONG
+#define TSWORD TINT|TLONG
+#define TWORD TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "       # convert between word and pointer", },
+
+/*
+ * Conversions of integral types (register-register)
+ *
+ * For each deunsigned type, they look something like this:
+ *
+ * signed -> bigger signed      - nothing to do
+ * unsigned -> bigger           - nothing to do
+ *
+ * signed -> bigger unsigned    - clear the top bits (of source type)
+ * signed -> smaller signed     - sign-extend the bits (to dest type)
+ * signed -> smaller unsigned   - clear the top bits (of dest type)
+ * unsigned -> smaller signed   - sign-extend top bits (to dest type)
+ * unsigned -> smaller unsigned - clear the top bits (of dest type)
+ *
+ */
+
+/* convert between int and ptr */
+{ SCONV,       INAREG,
+       SAREG,  TPOINT|TWORD,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "", },
+
+/* convert between LL and uLL */
+{ SCONV,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TULONGLONG|TLONGLONG,
+               0,      RLEFT,
+               "", },
+
+/* (u)char to (u)char/(u)short/(u)int */
+{ SCONV,       INAREG,
+       SAREG,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR|TWORD|TSHORT|TUSHORT,
+               0,      RLEFT,
+               "", },
+
+/* (u)short to (u)int */
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TWORD|TSHORT|TUSHORT,
+               0,      RLEFT,
+               "", },
+
+/* (u)int to (u)int */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "", },
+
+/* (u)int/(u)short to char */
+{ SCONV,       INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sll A1,AL,24\n"
+               "       sra A1,A1,24\n", },
+
+/* (u)int/(u)short to uchar */
+{ SCONV,       INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT,
+       SAREG,  TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       andi A1,AL,255\n", },
+
+/* (u)int to short */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TSHORT,
+               NAREG|NASL,     RESC1,
+               "       sll A1,AL,16\n"
+               "       sra A1,A1,16\n", },
+
+/* (u)int to ushort */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       andi A1,AL,65535\n", },
+
+/* longlong casts below */
+{ SCONV,       INBREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SBREG,  TLONGLONG,
+               NBREG,  RESC1,
+               "       move A1,AL      # convert int/short/char to longlong\n"
+               "       sra U1,AL,31\n", },
+
+{ SCONV,       INBREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SBREG,  TULONGLONG,
+               NBREG,  RESC1,
+               "       move A1,AL      # convert int/short/char to ulonglong\n"
+               "       move U1,$zero\n", },
+
+{ SCONV,       INBREG,
+       SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       move A1,AL      # convert (u)int/(u)short/(u)char to ulonglong\n"
+               "       move U1,$zero\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TWORD,
+               NAREG,  RESC1,
+               "       move A1,AL      # convert (u)longlong to int\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TSHORT,
+               NAREG,  RESC1,
+               "       sll A1,AL,16    # convert (u)longlong to short\n"
+               "       sra A1,A1,16\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TCHAR,
+               NAREG,  RESC1,
+               "       sll A1,AL,24    # convert (u)longlong to char\n"
+               "       sra A1,A1,24\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TUSHORT,
+               NAREG,  RESC1,
+               "       andi A1,AL,65535        # convert (u)longlong to ushort\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TUCHAR,
+               NAREG,  RESC1,
+               "       andi A1,AL,255  # convert (u)longlong to uchar\n", },
+
+{ SCONV,       INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       cvt.d.s A1,AL   # convert float to (l)double\n", },
+
+{ SCONV,       INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       cvt.s.d A1,AL   # convert (l)double to float\n", },
+
+{ SCONV,       INCREG,
+       SAREG,  TWORD,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       mtc1 AL,A1      # convert (u)int to float\n"
+               "       nop\n"
+               "       cvt.s.w A1,A1\n", },
+
+{ SCONV,       INCREG,
+       SOREG,  TWORD,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       l.s A1,AL       # convert (u)int to float\n"
+               "       nop\n"
+               "       cvt.s.w A1,A1\n", },
+
+{ SCONV,       INCREG,
+       SAREG,  TWORD,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       mtc1 AL,A1      # convert (u)int to (l)double\n"
+               "       nop\n"
+               "       cvt.d.w A1,A1\n", },
+
+{ SCONV,       INCREG,
+       SOREG,  TWORD,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       l.d A1,AL       # convert (u)int to (l)double\n"
+               "       nop\n"
+               "       cvt.d.w A1,A1\n", },
+
+{ SCONV,       INAREG,
+       SCREG,  TFLOAT,
+       SAREG,  TWORD,
+               NCREG|NAREG,    RESC1,
+               "       cvt.w.s A2,AL   # convert float to (u)int\n"
+               "       mfc1 A1,A2\n"
+               "       nop\n", },
+
+{ SCONV,       FOREFF,
+       SCREG,  TFLOAT,
+       SOREG,  TWORD,
+               NCREG,  RDEST,
+               "       cvt.w.s A1,AL   # convert float to (u)int\n"
+               "       s.s A1,AR\n"
+               "       nop\n", },
+
+{ SCONV,       INAREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TWORD,
+               NCREG|NAREG,    RESC1,
+               "       cvt.w.d A2,AL   # convert (l)double to (u)int\n"
+               "       mfc1 A1,A2\n"
+               "       nop\n", },
+
+{ SCONV,       INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               "       # convert between double and ldouble\n", },
+
+{ SCONV,       INCREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TFLOAT,
+               NSPECIAL|NCREG, RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NCREG, RESC1,
+               "ZF", },
+
+{ SCONV,       INBREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+{ SCONV,       INBREG,
+       SCREG,  TFLOAT,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG,         RESC1,
+               "ZF", },
+
+/*
+ * Multiplication and division
+ */
+
+{ MUL, INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+               NAREG|NASR|NASL,        RESC1,
+               "       multu AL,AR     # unsigned multiply\n"
+               "       nop\n"
+               "       nop\n"
+               "       mflo A1\n" },
+
+/* this previous will match on unsigned/unsigned multiplication first */
+{ MUL, INAREG,
+       SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+       SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+               NAREG|NASR|NASL,        RESC1,
+               "       mult AL,AR      # signed multiply\n"
+               "       nop\n"
+               "       nop\n"
+               "       mflo A1\n", },
+
+{ MUL, INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               2*NBREG,        RESC1,
+               "       multu AL,AR\n"
+               "       mfhi U1\n"
+               "       mflo A1\n"
+               "       mult AL,UR\n"
+               "       mflo A2\n"
+               "       nop\n"
+               "       nop\n"
+               "       addu A2,U1,A2\n"
+               "       mult UL,AR\n"
+               "       mflo U2\n"
+               "       nop\n"
+               "       nop\n"
+               "       addu U1,A2,U2\n", },
+
+{ MUL, INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       mul.s A1,AL,AR          # floating-point multiply\n", },
+
+{ MUL, INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1, 
+               "       mul.d   A1,AL,AR        # double-floating-point multiply\n", },
+
+{ DIV, INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+               NAREG|NASR|NASL,        RESC1,
+               "       divu AL,AR      # unsigned division\n"
+               "       mflo A1\n"
+               "       nop\n"
+               "       nop\n", },
+
+/* the previous rule will match unsigned/unsigned first */
+{ DIV, INAREG,
+       SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+       SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+               NAREG|NASR|NASL,        RESC1,
+               "       div AL,AR       # signed division\n"
+               "       mflo A1\n"
+               "       nop\n"
+               "       nop\n", },
+
+{ DIV, INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ DIV, INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       div.s A1,AL,AR          # floating-point division\n", },
+
+{ DIV, INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1, 
+               "       div.d   A1,AL,AR        # double-floating-point division\n", },
+
+{ MOD,  INAREG,
+        SAREG,  TUWORD|TUSHORT|TUCHAR,
+        SAREG,  TUWORD|TUSHORT|TUCHAR,
+                NAREG,  RESC1,
+                "       divu AL,AR     # signed modulo\n"
+               "       mfhi A1\n"
+               "       nop\n"
+               "       nop\n", },
+
+/* the previous rule will match unsigned%unsigned first */
+{ MOD,  INAREG,
+        SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+        SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+                NAREG,  RESC1,
+                "      div AL,AR       # signed modulo\n"
+               "       mfhi A1\n"
+               "       nop\n"
+               "       nop\n", },
+
+{ MOD,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+                NSPECIAL|NBREG,  RESC1,
+                "ZE", },
+    
+/*
+ * Templates for unsigned values needs to come before OPSIMP 
+ */
+
+{ PLUS,        INBREG,
+       SBREG,  TULONGLONG|TLONGLONG,
+       SBREG,  TULONGLONG|TLONGLONG,
+               2*NBREG,        RESC1,
+               "       addu A1,AL,AR   # 64-bit addition\n"
+               "       sltu A2,A1,AR\n"
+               "       addu U1,UL,UR\n"
+               "       addu U1,U1,A2\n", },
+
+{ PLUS,        INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SSCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       addi A1,AL,AR\n", },
+
+{ PLUS,        INAREG,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SSCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       addiu A1,AL,AR\n", },
+
+{ PLUS,        INAREG,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       addu A1,AL,AR\n", },
+
+{ PLUS,        INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+               NAREG|NASL,     RESC1,
+               "       add A1,AL,AR\n", },
+
+{ PLUS,        INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "       add.s A1,AL,AR\n", },
+
+{ PLUS,        INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       add.d A1,AL,AR\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               2*NBREG,        RESC1,
+               "       sltu A2,AL,AR   # 64-bit subtraction\n"
+               "       subu A1,AL,AR\n"
+               "       subu U1,UL,UR\n"
+               "       subu U1,U1,A2\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SSCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       subu A1,AL,AR\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SSCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       sub A1,AL,AR\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sub A1,AL,AR\n", },
+
+{ MINUS,       INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "       sub.s A1,AL,AR\n", },
+
+{ MINUS,       INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       sub.d A1,AL,AR\n", },
+
+{ UMINUS,      INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       neg A1,AL\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SANY,   TANY,
+               NBREG|NAREG|NBSL,       RESC2,
+               "       subu A1,$zero,AL\n"
+               "       subu U1,$zero,UL\n"
+               "       sltu A2,$zero,A1\n"
+               "       subu U1,U1,A2\n", },
+
+{ UMINUS,      INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG|NCSL,     RESC1,
+               "       neg.s A1,AL\n", },
+
+{ UMINUS,      INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       neg.d A1,AL\n", },
+
+/* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */
+
+{ OPSIMP,      INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSR|NBSL,        RESC1,
+               "       O A1,AL,AR\n"
+               "       O U1,UL,UR\n", },
+    
+{ OPSIMP,      INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+               NAREG|NASR|NASL,        RESC1,
+               "       O A1,AL,AR\n", },
+
+{ OPSIMP,      INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       Oi A1,AL,AR\n", },
+
+/*
+ * Shift instructions
+ */
+
+{ RS,  INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sra A1,AL,AR    # shift right by constant\n", },
+
+{ RS,  INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srl A1,AL,AR    # shift right by constant\n", },
+
+{ LS,  INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sll A1,AL,AR    # shift left by constant\n", },
+    
+{ RS,  INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srav A1,AL,AR   # shift right by register\n", },
+
+{ RS,  INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srlv A1,AL,AR   # shift right by register\n", },
+
+{ LS,  INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sllv A1,AL,AR   # shift left by register\n", }, 
+
+{ RS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "ZO", },
+
+{ LS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "ZO", },
+
+{ RS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ LS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+/*
+ * Rule for unary one's complement
+ */
+
+{ COMPL,        INAREG,
+        SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SANY,   TANY,
+                NAREG|NASL,   RESC1,
+                "      nor A1,$zero,AL # complement\n", },
+    
+{ COMPL,        INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+        SANY,   TANY,
+                NBREG|NBSL,   RESC1,
+                "      nor A1,$zero,AL # complement\n"
+                "      nor U1,$zero,UL\n", },
+    
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TWORD|TPOINT,
+       SAREG,          TWORD|TPOINT,
+               0,      RDEST,
+               "       sw AR,AL                # store (u)int/(u)long\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RDEST,
+               "       sh AR,AL                # store (u)short\n"
+               "       nop\n", },      
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG|SNAME,    TCHAR|TUCHAR,
+       SAREG,          TCHAR|TUCHAR,
+               0,      RDEST,
+               "       sb AR,AL                # store (u)char\n"
+               "       nop\n", },      
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG|SNAME,    TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               0,      RDEST,
+               "       sw UR,UL                # store (u)longlong\n"
+               "       nop\n"
+               "       sw AR,AL\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               0,      RDEST,
+               "       move UL,UR              # register move\n"
+               "       move AL,AR\n", },
+    
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               0,      RDEST,
+               "       move AL,AR              # register move\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               0,      RDEST,
+               "       mov.s AL,AR             # register move\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       mov.d AL,AR             # register move\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SNAME|SOREG,    TFLOAT,
+       SCREG,          TFLOAT,
+               0,      RDEST,
+               "       s.s AR,AL               # store floating-point reg to oreg/sname\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SNAME|SOREG,    TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       s.d AR,AL               # store double floating-point reg to oreg/sname\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,           TANY,
+       SOREG|SNAME,    TANY,
+               3*NAREG,        RDEST,
+               "       lw A1,AR                # bit-field assignment\n"
+               "       li A3,M\n"
+               "       lw A2,AL\n"
+               "       sll A1,A1,H\n"
+               "       and A1,A1,A3\n"
+               "       nor A3,$zero,A3\n"
+               "       and A2,A2,A3\n"
+               "       or A2,A2,A1\n"
+               "       sw A2,AL\n"
+               "F      lw AD,AR\n"
+               "F      nop\n"
+               "F      sll AD,AD,32-S\n"
+               "F      sra AD,AD,32-S\n", },
+
+/* XXX we can optimise this away */
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,           TANY,
+       SCON,           TANY,
+               3*NAREG,        RDEST,
+               "       li A1,AR                # bit-field assignment\n"
+               "       lw A2,AL\n"
+               "       li A3,M\n"
+               "       sll A1,A1,H\n"
+               "       and A1,A1,A3\n"
+               "       nor A3,$zero,A3\n"
+               "       and A2,A2,A3\n"
+               "       or A2,A2,A1\n"
+               "       sw A2,AL\n"
+               "F      li AD,AR\n"
+               "F      sll AD,AD,32-S\n"
+               "F      sra AD,AD,32-S\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,           TANY,
+       SAREG,          TANY,
+               3*NAREG,        RDEST,
+               "       move A1,AR              # bit-field assignment\n"
+               "       lw A2,AL\n"
+               "       li A3,M\n"
+               "       sll A1,A1,H\n"
+               "       and A1,A1,A3\n"
+               "       nor A3,$zero,A3\n"
+               "       and A2,A2,A3\n"
+               "       or A2,A2,A1\n"
+               "       sw A2,AL\n"
+               "F      move AR,AD\n"
+               "F      sll AD,AD,32-S\n"
+               "F      sra AD,AD,32-S\n", },
+
+{ STASG,        INAREG|FOREFF,
+        SOREG|SNAME,   TANY,
+        SAREG,         TPTRTO|TANY,
+                NSPECIAL,       RDEST,
+                "ZQ", },
+
+/*
+ * Compare instructions
+ */
+
+{ EQ,  FORCC,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                0,      RESCC,
+                "      beq AL,AR,LC\n"
+               "       nop\n", },
+
+{ NE,  FORCC,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                0,      RESCC,
+                "      bne AL,AR,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SZERO,         TANY,
+                0,      RESCC,
+                "      O AL,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                NAREG|NASL,     RESCC,
+               "       sub A1,AL,AR\n"
+                "      O A1,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+        SAREG,         TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SSCON,         TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                NAREG|NASL,     RESCC,
+               "       sub A1,AL,AR\n"
+                "      O A1,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NAREG,  RESCC,
+               "ZD", },
+
+{ OPLOG,       FORCC,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RESCC,
+               "ZG", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TCHAR,
+               NAREG,  RESC1,
+               "       lb A1,AL        # load char to reg\n"
+               "       nop\n", },
+       
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TUCHAR,
+               NAREG,  RESC1,
+               "       lbu A1,AL       # load uchar to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TSHORT,
+               NAREG,  RESC1,
+               "       lh A1,AL        # load short to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TUSHORT,
+               NAREG,  RESC1,
+               "       lhu A1,AL       # load ushort to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       lw A1,AL        # load (u)int/(u)long to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       lw U1,UL        # load (u)longlong to reg\n"
+               "       nop\n"
+               "       lw A1,AL\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON,   TPOINT,
+               NAREG,  RESC1,
+               "       la A1,AL        # load constant address to reg\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SZERO,  TANY,
+               NAREG,  RESC1,
+               "       move A1,$zero   # load 0 to reg\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON,   TANY,
+               NAREG,  RESC1,
+               "       li A1,AL        # load constant to reg\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SZERO,  TANY,
+               NBREG,  RESC1,
+               "       move A1,$zero   # load 0 to reg\n"
+               "       move U1,$zero\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "       li A1,AL        # load constant to reg\n"
+               "       li U1,UL\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               NAREG,  RESC1,
+               "       move A1,AL\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TANY,
+       SZERO,  TFLOAT,
+               NCREG,  RESC1,
+               "       mtc1 $zero,A1   # load 0 to float reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TANY,
+       SZERO,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       mtc1 $zero,A1   # load 0 to (l)double reg\n"
+               "       mtc1 $zero,U1\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TANY,
+       SOREG|SNAME,    TFLOAT,
+               NCREG,  RESC1,
+               "       l.s A1,AL       # load into floating-point reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TANY,
+       OREG|SNAME,     TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       l.d A1,AL       # load into double floating-point reg\n"
+               "       nop\n", },
+    
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       j LL            # goto label\n"
+               "       nop\n"
+               "       nop\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,         FOREFF,
+        SCON,          TANY,
+        SANY,           TANY,
+                0,      0,
+                "      subu $sp,$sp,16 # call (args, no result) to scon/sname\n"
+                "      jal CL\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        FOREFF,
+        SCON,          TANY,
+        SANY,           TANY,
+                0,      0,
+                "      jal CL                  # call (no args, no result) to scon/sname\n"
+               "       nop\n", },
+
+{ CALL,         INAREG,
+        SCON,          TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,  /* should be 0 */
+                "      subu $sp,$sp,16 # call (args, result in v0) to scon/sname\n"
+               "       jal CL\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        INAREG,
+        SCON,          TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,  /* should be 0 */
+                "      jal CL   # call (no args, result in v0) to scon/sname\n"
+               "       nop\n",
+ },
+
+{ CALL,         INBREG,
+        SCON,          TANY,
+        SBREG,          TANY,
+                NBREG,     RESC1,  /* should be 0 */
+                "      subu $sp,$sp,16 # call (args, result in v0:v1) to scon/sname\n"
+               "       jal CL\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        INBREG,
+        SCON,          TANY,
+        SBREG,          TANY,
+                NBREG,     RESC1,  /* should be 0 */
+                "      jal CL   # call (no args, result in v0:v1) to scon/sname\n"
+               "       nop\n",
+ },
+
+{ CALL,         INCREG,
+        SCON,          TANY,
+        SCREG,          TANY,
+                NCREG,     RESC1,  /* should be 0 */
+                "      subu $sp,$sp,16 # call (args, result in f0:f1) to scon/sname\n"
+               "       jal CL\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        INCREG,
+        SCON,          TANY,
+        SCREG,          TANY,
+                NCREG,     RESC1,  /* should be 0 */
+                "      jal CL   # call (no args, result in v0:v1) to scon/sname\n"
+               "       nop\n",
+ },
+
+{ CALL,         FOREFF,
+        SAREG,         TANY,
+        SANY,          TANY,
+                0,      0,
+                "      subu $sp,$sp,16 # call (args, no result) to reg\n"
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        FOREFF,
+        SAREG,         TANY,
+        SANY,          TANY,
+                0,      0,
+               "       move $25,AL\n"
+                "      jal $25                 # call (no args, no result) to reg\n"
+               "       nop\n", },
+
+{ CALL,         INAREG,
+        SAREG,         TANY,
+        SAREG,         TANY,
+                NAREG,     RESC1,  /* should be 0 */
+                "      subu $sp,$sp,16 # call (args, result) to reg\n"
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        INAREG,
+        SAREG,         TANY,
+        SAREG,         TANY,
+                NAREG,     RESC1,  /* should be 0 */
+               "       move $25,AL\n"
+                "      jal $25         # call (no args, result) to reg\n"
+               "       nop\n", },
+
+{ CALL,         INBREG,
+        SAREG,         TANY,
+        SBREG,         TANY,
+                NBREG,     RESC1,  /* should be 0 */
+                "      subu $sp,$sp,16 # call (args, result) to reg\n"
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        INBREG,
+        SAREG,         TANY,
+        SBREG,         TANY,
+                NBREG,     RESC1,  /* should be 0 */
+               "       move $25,AL\n"
+                "      jal $25                 # call (no args, result) to reg\n"
+               "       nop\n", },
+
+{ CALL,         INCREG,
+        SAREG,         TANY,
+        SCREG,         TANY,
+                NCREG,     RESC1,  /* should be 0 */
+                "      subu $sp,$sp,16 # call (args, result) to reg\n"
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n"
+               "ZC", },
+
+{ UCALL,        INCREG,
+        SCREG,         TANY,
+        SCREG,         TANY,
+                NCREG,     RESC1,  /* should be 0 */
+               "       move $25,AL\n"
+                "      jal $25                 # call (no args, result) to reg\n"
+               "       nop\n", },
+
+
+/* struct return */
+{ USTCALL,      FOREFF,
+       SCON|SNAME,     TANY,
+       SANY,           TANY,
+               0,      0,
+               "       jal CL\n"
+               "       nop\n", },
+
+{ USTCALL,      FOREFF,
+       SAREG,          TANY,
+       SANY,           TANY,
+               0,      0,
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n", },
+
+{ USTCALL,      INAREG,
+       SCON|SNAME,     TANY,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1,
+               "       jal CL\n"
+               "       nop\n", },
+
+{ USTCALL,      INAREG,
+       SAREG,          TANY,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1,
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n", },
+
+{ STCALL,      FOREFF,
+       SCON|SNAME,     TANY,
+       SANY,           TANY,
+               0,      0,
+                "      subu $sp,$sp,16\n"
+               "       jal CL\n"
+               "       nop\n"
+               "ZC", },
+
+{ STCALL,      FOREFF,
+       SAREG,  TANY,
+       SANY,           TANY,
+               0,      0,
+                "      subu $sp,$sp,16\n"
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n"
+               "ZC", },
+
+{ STCALL,      INAREG,
+       SCON|SNAME,     TANY,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1,
+                "      subu $sp,$sp,16\n"
+               "       jal CL\n"
+               "       nop\n"
+               "ZC", },
+
+{ STCALL,      INAREG,
+       SAREG,  TANY,
+       SANY,           TANY,
+               0,      0,
+                "      subu $sp,$sp,16\n"
+               "       move $25,AL\n"
+                "      jal $25\n"
+               "       nop\n"
+               "ZC", },
+
+
+/*
+ *  Function arguments
+ */
+
+#if 0
+
+/* intentionally write out the register for (u)short/(u)char */
+{ FUNARG,       FOREFF,
+        SAREG,  TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR,
+        SANY,   TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR,
+                0,      0,
+                "      subu $sp,$sp,4          # save function arg to stack\n"
+               "       sw AL,($sp)\n"
+               "       #nop\n", },
+
+{ FUNARG,      FOREFF,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SANY,   TLONGLONG|TULONGLONG,
+               0,      0,
+               "       addi $sp,$sp,-8         # save function arg to stack (endian problem here?\n"
+               "       sw UL,4($sp)\n"
+               "       sw AL,($sp)\n"
+               "       #nop\n", },
+
+{ FUNARG,      FOREFF,
+       SCREG,  TFLOAT,
+       SANY,   TFLOAT,
+               0,      0,
+               "       addi $sp,$sp,-4         # save function arg to stack\n"
+               "       s.s AL,($sp)\n"
+               "       #nop\n", },
+
+{ FUNARG,      FOREFF,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SANY,   TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       addi $sp,$sp,-8         # save function arg to stack\n"
+               "       s.d AL,($sp)\n"
+               "       #nop\n", },
+
+#endif
+
+{ STARG,       FOREFF,
+       SAREG,          TANY,
+       SANY,           TSTRUCT,
+               NSPECIAL,       0,
+               "ZH", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG,     RESC1,
+               "       lw A1,AL                # word load\n"
+               "       nop\n", },
+
+{ UMUL, INAREG,
+       SANY,   TSHORT|TUSHORT,
+       SOREG,  TSHORT|TUSHORT,
+               NAREG,     RESC1,
+               "       lh A1,AL                # (u)short load\n"
+               "       nop\n", },
+
+{ UMUL, INAREG,
+       SANY,   TCHAR|TUCHAR,
+       SOREG,  TCHAR|TUCHAR,
+               NAREG,     RESC1,
+               "       lb A1,AL                # (u)char load\n"
+               "       nop\n", },
+
+{ UMUL,        INBREG,
+       SANY,   TLONGLONG|TULONGLONG,
+       SOREG,  TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       lw A1,AL                # (u)longlong load - endian problem here?\n"
+               "       nop\n"
+               "       lw U1,UL\n"
+               "       nop\n", },
+
+{ UMUL,        INCREG,
+       SANY,   TFLOAT,
+       SOREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       l.s A1,AL               # float load\n"
+               "       nop\n", },
+
+{ UMUL,        INCREG,
+       SANY,   TDOUBLE|TLDOUBLE,
+       SOREG,  TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       l.d A1,AL               # float load\n"
+               "       nop\n", },
+
+#if 0
+{ UMUL,        INCREG,
+       SANY,   TDOUBLE|TLDOUBLE,
+       SAREG,  TPOINT,
+               NCREG,  RESC1,
+               "       l.d A1,(AL)\n"
+               "       nop\n", },
+    
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SNAME,  TPOINT|TWORD,
+               NAREG,     RESC1,
+               "       la A1,AL                # sname word load\n"
+               "       lw A1,(A1)\n"
+               "       nop\n", },
+
+{ UMUL, INAREG,
+       SANY,   TSHORT|TUSHORT,
+       SNAME,  TSHORT|TUSHORT,
+               NAREG,     RESC1,
+               "       la A1,AL                # sname (u)short load\n"
+               "       lh A1,(A1)\n"
+               "       nop\n", },
+
+{ UMUL, INAREG,
+       SANY,   TCHAR|TUCHAR,
+       SNAME,  TCHAR|TUCHAR,
+               NAREG,     RESC1,
+               "       la A1,AL                # sname (u)char load\n"
+               "       lb A1,(A1)\n"
+               "       nop\n", },
+
+{ UMUL, INBREG,
+       SANY,   TLONGLONG|TULONGLONG,
+       SNAME,  TLONGLONG|TULONGLONG,
+               NBREG|NAREG,    RESC1,
+               "       la A2,AL                # sname (u)long long load - endian problems here?\n"
+               "       lw A1,(A1)\n"
+               "       nop\n"
+               "       lw U1,4(A1)\n"
+               "       nop\n", },
+#endif
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SAREG,  TPOINT|TWORD,
+               NAREG,     RESC1,
+               "       lw A1,(AL)              # word load\n"
+               "       nop\n", },
+
+#if 0
+{ UMUL, INAREG,
+       SANY,   TSHORT|TUSHORT,
+       SAREG,  TPTRTO|TSHORT|TUSHORT,
+               NAREG,     RESC1,
+               "       lh A1,(AL)              # (u)short load\n"
+               "       nop\n", },
+
+{ UMUL, INAREG,
+       SANY,   TCHAR|TUCHAR,
+       SAREG,  TPTRTO|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       lb A1,(AL)              # (u)char load\n"
+               "       nop\n", },
+
+{ UMUL, INBREG,
+       SANY,   TLONGLONG|TULONGLONG,
+       SAREG,  TPTRTO|TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       lw A1,(AL)              # (u)long long load - endianness problems?\n"
+               "       nop\n"
+               "       lw U1,4(AL)"
+               "       nop\n", },
+#endif
+
+#define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ FLD, DF(FLD), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/nova/README b/lang/pcc/pcc/arch/nova/README
new file mode 100644 (file)
index 0000000..d133174
--- /dev/null
@@ -0,0 +1,245 @@
+Calling conventions, stack frame and zero page:
+
+The variables that normally are placed on the stack or in registers in C
+are instead allocated in the zero page and saved on a (fictive) stack
+when calling functions.  Some locations have predefined functions though.
+Arrays allocated as automatics are stored on the stack with a pointer
+in zero page to its destination.
+
+0-7    Unused (by us)
+10     Stack pointer
+11     Frame pointer
+12-14  Unused
+15     Prolog private word
+16     Prolog address, written in crt0
+17     Epilog address, written in crt0
+20-27  (Auto-increment), scratch
+30-37  (Auto-decrement), scratch
+40-47  Used by HW stack and MMPU
+50-77  Permanent, save before use.
+100-377        Addresses for subroutines, written by the linker
+
+The normal registers (AC0-AC3) are all considered scratch registers.
+
+Register classes are assigned as:
+       AC0-AC3: AREGs.
+       AC2-AC3: BREGs.
+       ...and eventually register pairs/floats as EREGs, double in FREGs.
+
+In byte code the left half of a word is the first byte (big-endian).
+This is bit 0-7 in Nova syntax.
+The stack is growing towards lower adresses (as opposed to the Eclipse stack).
+Stack pointer points to the last used stack entry, which means:
+PUSH: dec sp, store value
+POP:  fetch val, inc sp
+
+Note that internally is the first 24 words stored in loc 50-77!
+So an offset is subtracted in adrput().
+
+Stack layout:
+
+       ! arg1  ! 1
+ fp -> ! arg0  ! 0
+       ! old pc! -1
+       ! old fp! -2
+ sp -> ! saved ! -3
+
+
+Stack references to zero page are converted to NAMEs, using word addresses.
+References to the stack itself are using byte offsets.
+
+Arguments are transferred on the stack.  To avoid unneccessary double instructions
+they are copied to the zp use area initially. XXX? Need tests here.
+Return values in ac0 and ac1.
+
+A reference to a struct member in assembler, a = b->c; b is in ZP 50 (or on stack)
++ is zeropage-addressing
+* is fp-adressing, assume fp in ac3
+
+# offset 0
++      lda 0,@50       # load value from indirect ZP 50 into ac0
+or
+*      lda 2,,3        # load value from (ac3) into ac2
+*      lda 0,,2        # load value from (ac2) into ac0
+
+# offset 12
++      lda 2,50        # load value from ZP 50 into ac2
++      lda 0,12,2      # load value from (ac2+12) into ac0
+or
+*      lda 2,,3        # load value from (ac3) into ac2
+*      lda 0,12,2      # load value from 12(ac2) into ac0
+
+# offset 517
++      lda %2,50       # load value from ZP 50 into ac2
++      lda %0,.L42-.,%1        # load offset from .L42 PC-indexed
++      addz %0,%2,skp  # add offset to ac2 and skip
++.L42: .word 517       # offset value
++      lda %0,,%2      # load value from (ac2) into ac0
+or
+
+The prolog/epilog; they are implemented as subroutines.
+Both can be omitted if the function do not need it.
+
+
+       .word 012       # total words that needs to be saved
+func:
+       mov 3,0         # avoid trashing return address
+       jsr @prolog     # go to prolog
+       ...
+       jmp @epilog     # jump to epilog
+
+#ifdef prolog
+       lda 0,sp
+       sta 3,@sp
+       lda 1,fp
+       sta 1,@sp
+       sta 0,fp
+       lda 1,[Css]
+       sub 1,0
+       sta 0,sp
+#endif
+
+...
+
+       lda 2,fp
+       lda 3,-1,2
+       lda 0,-2,2
+       sta 0,fp
+       sta 2,sp
+       jmp 0,3
+
+
+#
+# decrement from stack, and save permanent registers.
+#      push retreg
+#      push fp
+#      mov sp,fp
+#      sub $w,sp
+#      
+# prolog: return in ac3, fun in ac0.
+prolog:        lda 1,sp
+       sta 0,@sp
+       lda 0,fp
+       sta 0,@sp
+       sta 1,fp
+       lda 0,-3,3
+       sub 0,1
+       sta 1,sp
+       jmp 0,3
+
+epilog:        lda 3,fp
+       sta 3,sp
+       lda 3,@fp
+       lda 2,@fp
+       sta 2,fp
+       jmp 0,3
+
+       
+
+
+
+
+
+prolog:
+       lda 2,sp        # sp points to the first argument
+       sta 2,30        # store at auto-dec location
+       sta 0,@30       # store fun return address
+       lda 0,fp        # fetch old fp
+       sta 0,@30       # store saved fp
+       sta 2,fp        # save frame pointer
+
+       lda 0,-3,3      # stack size to subtract
+       neg 0,0,snr     # Any words?
+       jmp 1f          # no, get away
+       lda 1,$51       # fetch zp offset
+       sub 0,1         # get highest word
+       sta 1,31        # at auto-dec location
+
+2:     lda 1,@31       # fetch word to copy
+       sta 1,@30       # on stack
+       inc 0,0,szr     # count words
+       jmp 1b          # more to go
+
+1:     lda 0,30        # finished, get stackptr
+       sta 0,sp        #
+       jmp 0,3         # get back!
+
+# epilog, need save frame pointer in ac3
+epilog:
+       lda 0,-3,3      # get words to save
+       neg 0,0,snr     # any words to save?
+       jmp 1f          # No, get out
+
+       lda 1,$51       # get zp offset
+       sub 0,1         # Highest word
+       sta 1,31        # auto-dec loc
+
+       lda 2,fp        # get fp
+       adczl 1,1       # -2
+       add 1,2         # 2 now offset
+       sta 2,30        # auto-dec loc
+
+2:     lda 1,@30
+       sta 1,@31
+       inc 0,0,szr
+       jmp 2b
+
+1:     lda 2,fp        # fetch current fp
+       lda 3,-1,2      # return pc
+       lda 0,-2,2      # fetch old fp
+       sta 0,fp        # restore fp
+       sta 2,sp        # stack pointer restored
+       jmp 0,3         # Done!
+
+#if 0
+Assembler syntax and functions.
+
+The assembler syntax mimics the DG assembler but uses AT&T syntax.
+Load and store to addresses is written "lda 0,foo" to load from address foo.
+If foo is not in zero page then the assembler will put the lda in the
+text area close to the instruction and do an indirect pc-relative load.
+
+Arithmetic instruction:        
+       subsl#  %0,%1,snr               skip code may be omitted
+       subsl#  %0,%1
+
+Load/store/jmp/jsr/isz/dsz:
+       lda %1,@disp,2          or
+       mov *disp(%2),%1
+               index may be omitted if 0 (ZP)
+               disp can only be +-127 words.
+
+       It's allowed to write "mov $32,%0" which will be converted
+       to an indirect load by the assembler.
+
+       Example of AT&T arguments:
+               01234   - Zero-page
+               L11     - Relative.  Will be converted to
+                         indirect + addr if distance too long
+               (%2)    - indexed
+               012(%2) - indexed with offset
+               * in front of any of these will generate indirection
+#endif
+
+lbyte:  movr 2,2        # get byte ID into C bit
+        lda 0,,2        # word into ac0
+        mov 2,2,snc     # skip if right byte
+        movs 0,0        # swap bytes
+        jmp 0,3         # get back
+
+sbyte:  sta 3,@sp
+
+        movr 2,2        # get byte ID into C bit
+        lda 1,,2        # get word
+        lda 3,[377]     # get mask
+        and 3,0,snc     # clear left input + skip if right byte
+        movs 1,1        # swap bytes
+        and 3,1         # clear old bits
+        add 0,1,snc     # swap back if necessary
+        movs 1,1        # swap
+        sta 1,2
+
+        lda 3,sp
+        isz sp
+        jmp @0,3
+
diff --git a/lang/pcc/pcc/arch/nova/code.c b/lang/pcc/pcc/arch/nova/code.c
new file mode 100644 (file)
index 0000000..07f3d56
--- /dev/null
@@ -0,0 +1,259 @@
+/*     $Id: code.c,v 1.11 2014/06/03 20:19:50 ragge Exp $      */
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ * never called for text segment.
+ */
+void
+defalign(int n)
+{
+       /* alignment are always correct */
+}
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+       case UDATA: break;
+       default:
+               cerror((char *)__func__);
+       }
+       printf("\t%s\n", name);
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+
+       if (ISFTN(sp->stype))
+               return;
+       if (sp->sclass == EXTDEF)
+               printf("\t.globl %s\n", name);
+       if (sp->slevel == 0)
+               printf("%s:\n", name);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off, al;
+       char *name;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+       al = talign(sp->stype, sp->sap)/SZCHAR;
+
+       if (sp->sclass == STATIC) {
+               if (sp->slevel == 0) {
+                       printf("\t.local %s\n", name);
+               } else
+                       printf("\t.local " LABFMT "\n", sp->soffset);
+       }
+       if (sp->slevel == 0) {
+               printf("\t.comm %s,0%o,%d\n", name, off, al);
+       } else
+               printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+}
+
+
+//static int ac3temp;
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       NODE *p, *q;
+//     int sz;
+
+#if 0
+       /* restore ac3 */
+       p = block(REG, 0, 0, INT, 0, 0);
+       regno(p) = 3;
+       q = tempnode(ac3temp, INT, 0, 0);
+       ecomp(buildtree(ASSIGN, p, q));
+#endif
+
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+cerror("efcode");
+       /* address of return struct is in eax */
+       /* create a call to memcpy() */
+       /* will get the result in eax */
+       p = block(REG, NIL, NIL, CHAR+PTR, 0, 0);
+//     p->n_rval = EAX;
+       q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0);
+//     q->n_rval = EBP;
+       q->n_lval = 8; /* return buffer offset */
+       p = block(CM, q, p, INT, 0, 0);
+//     sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+//     p = block(CM, p, bcon(sz), INT, 0, 0);
+       p->n_right->n_name = "";
+       p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0);
+       p->n_left->n_name = "memcpy";
+       p = clocal(p);
+       send_passt(IP_NODE, p);
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+//     NODE *p, *q;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (a[i]->stype == CHAR)
+                       a[i]->stype = INT;
+               if (a[i]->stype == UCHAR)
+                       a[i]->stype = UNSIGNED;
+       }
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+cerror("bfcode");
+       /* Function returns struct, adjust arg offset */
+       for (i = 0; i < n; i++)
+               a[i]->soffset += SZPOINT(INT);
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+}
+
+void
+bjobcode(void)
+{
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       NODE *r, *l;
+
+       /* Fix function call arguments. On nova, just add funarg */
+       for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+               if (r->n_right->n_op != STARG)
+                       r->n_right = block(FUNARG, r->n_right, NIL,
+                           r->n_right->n_type, r->n_right->n_df,
+                           r->n_right->n_ap);
+       }
+       if (r->n_op != STARG) {
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_type = l->n_type;
+       }
+
+       return p;
+}
+
+/*
+ * Return return as given by a.
+ */
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       cerror((char *)__func__);
+       return 0;
+}
+
+/*
+ * Return frame as given by a.
+ */
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       cerror((char *)__func__);
+       return 0;
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       cerror((char *)__func__);
+       return 0;
+}
+
diff --git a/lang/pcc/pcc/arch/nova/local.c b/lang/pcc/pcc/arch/nova/local.c
new file mode 100644 (file)
index 0000000..0fd593f
--- /dev/null
@@ -0,0 +1,649 @@
+/*     $Id: local.c,v 1.17 2015/08/18 10:15:08 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*     this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(NODE *p)
+{
+       struct symtab *q;
+       NODE *r, *l;
+       TWORD t;
+       int o;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal\n");
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       switch( o = p->n_op ){
+       case NAME:
+               /* handle variables */
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+               switch (q->sclass) {
+               case PARAM:
+               case AUTO:
+                       if (0 && q->soffset < MAXZP * SZINT &&
+                           q->sclass != PARAM) {
+                               p->n_lval = -(q->soffset/SZCHAR) + ZPOFF*2;
+                               p->n_sp = NULL;
+                       } else {
+                               /* fake up a structure reference */
+                               r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                               r->n_lval = 0;
+                               r->n_rval = FPREG;
+                               p = stref(block(STREF, r, p, 0, 0, 0));
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case PMCONV:
+       case PVCONV:
+                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+                nfree(p);
+                p = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+               break;
+
+       case PCONV:
+               t = p->n_type;
+               if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
+                   t == INCREF(BOOL) || t == INCREF(VOID))
+                       break;
+               l = p->n_left;
+               t = l->n_type;
+               if (t == INCREF(CHAR) || t == INCREF(UCHAR) ||
+                   t == INCREF(BOOL) || t == INCREF(VOID))
+                       break;
+               if (p->n_type <= UCHAR || l->n_type <= UCHAR)
+                       break; /* must do runtime ptr conv */
+               /* if conversion to another pointer type, just remove */
+               if (p->n_type > BTMASK && l->n_type > BTMASK)
+                       goto delp;
+               if (l->n_op == ICON && l->n_sp == NULL)
+                       goto delp;
+               break;
+
+       delp:   l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_ap = p->n_ap;
+               p = nfree(p);
+               break;
+       }
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end\n");
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+#if 0
+       register struct symtab *q;
+       register NODE *r, *l;
+       register int o;
+       register int m;
+       TWORD t;
+
+//printf("in:\n");
+//fwalk(p, eprint, 0);
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case STATIC:
+                       if (q->slevel == 0)
+                               break;
+                       p->n_lval = 0;
+                       p->n_sp = q;
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+                       }
+               break;
+
+       case STCALL:
+       case CALL:
+               /* Fix function call arguments. On x86, just add funarg */
+               for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+                       if (r->n_right->n_op != STARG &&
+                           r->n_right->n_op != FUNARG)
+                               r->n_right = block(FUNARG, r->n_right, NIL, 
+                                   r->n_right->n_type, r->n_right->n_df,
+                                   r->n_right->n_sue);
+               }
+               if (r->n_op != STARG && r->n_op != FUNARG) {
+                       l = talloc();
+                       *l = *r;
+                       r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
+               }
+               break;
+               
+       case CBRANCH:
+               l = p->n_left;
+
+               /*
+                * Remove unnecessary conversion ops.
+                */
+               if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+                       if (coptype(l->n_op) != BITYPE)
+                               break;
+                       if (l->n_right->n_op == ICON) {
+                               r = l->n_left->n_left;
+                               if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+                                       break;
+                               /* Type must be correct */
+                               t = r->n_type;
+                               nfree(l->n_left);
+                               l->n_left = r;
+                               l->n_type = t;
+                               l->n_right->n_type = t;
+                       }
+               }
+               break;
+
+       case PCONV:
+               /* Remove redundant PCONV's. Be careful */
+               l = p->n_left;
+               if (l->n_op == ICON) {
+                       l->n_lval = (unsigned)l->n_lval;
+                       goto delp;
+               }
+               if (l->n_type < INT || l->n_type == LONGLONG || 
+                   l->n_type == ULONGLONG) {
+                       /* float etc? */
+                       p->n_left = block(SCONV, l, NIL,
+                           UNSIGNED, 0, 0);
+                       break;
+               }
+               /* if left is SCONV, cannot remove */
+               if (l->n_op == SCONV)
+                       break;
+               /* if conversion to another pointer type, just remove */
+               if (p->n_type > BTMASK && l->n_type > BTMASK)
+                       goto delp;
+               break;
+
+       delp:   l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_sue = p->n_sue;
+               nfree(p);
+               p = l;
+               break;
+
+       case SCONV:
+               l = p->n_left;
+
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       return l;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       return l;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       return l;
+               }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       CONSZ val = l->n_lval;
+
+                       if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+                           switch (m) {
+                       case CHAR:
+                               l->n_lval = (char)val;
+                               break;
+                       case UCHAR:
+                               l->n_lval = val & 0377;
+                               break;
+                       case SHORT:
+                               l->n_lval = (short)val;
+                               break;
+                       case USHORT:
+                               l->n_lval = val & 0177777;
+                               break;
+                       case ULONG:
+                       case UNSIGNED:
+                               l->n_lval = val & 0xffffffff;
+                               break;
+                       case LONG:
+                       case INT:
+                               l->n_lval = (int)val;
+                               break;
+                       case LONGLONG:
+                               l->n_lval = (long long)val;
+                               break;
+                       case ULONGLONG:
+                               l->n_lval = val;
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", m);
+                       }
+                       l->n_type = m;
+                       l->n_sue = 0;
+                       nfree(p);
+                       return l;
+               }
+               if (DEUNSIGN(p->n_type) == SHORT &&
+                   DEUNSIGN(l->n_type) == SHORT) {
+                       nfree(p);
+                       p = l;
+               }
+               if ((p->n_type == CHAR || p->n_type == UCHAR ||
+                   p->n_type == SHORT || p->n_type == USHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               break;
+
+       case MOD:
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
+               p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
+               p = block(SCONV, p, NIL, p->n_type, 0, 0);
+               p->n_left->n_type = INT;
+               break;
+
+       case PMCONV:
+       case PVCONV:
+                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = RETREG(p->n_type);
+               break;
+
+       case LS:
+       case RS:
+               /* shift count must be in a char
+                * unless longlong, where it must be int */
+               if (p->n_right->n_op == ICON)
+                       break; /* do not do anything */
+               if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
+                       if (p->n_right->n_type != INT)
+                               p->n_right = block(SCONV, p->n_right, NIL,
+                                   INT, 0, 0);
+                       break;
+               }
+               if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+                       break;
+               p->n_right = block(SCONV, p->n_right, NIL,
+                   CHAR, 0, 0);
+               break;
+       }
+//printf("ut:\n");
+//fwalk(p, eprint, 0);
+
+#endif
+
+       return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+       NODE *l, *r;
+       int o = p->n_op;
+
+       switch (o) {
+       case NAME: /* reading from a name must be done with a subroutine */
+               if (p->n_type != CHAR && p->n_type != UCHAR)
+                       break;
+               l = buildtree(ADDROF, ccopy(p), NIL);
+               r = block(NAME, NIL, NIL, INT, 0, 0);
+
+               r->n_sp = lookup(addname("__nova_rbyte"), SNORMAL);
+               if (r->n_sp->sclass == SNULL) {
+                       r->n_sp->sclass = EXTERN;
+                       r->n_sp->stype = INCREF(p->n_type)+(FTN-PTR);
+               }
+               r->n_type = r->n_sp->stype;
+               r = clocal(r);
+               r = optim(buildtree(CALL, r, l));
+               *p = *r;
+               nfree(r);
+               break;
+
+       case FCON:
+               sp = tmpalloc(sizeof(struct symtab));
+               sp->sclass = STATIC;
+               sp->sap = 0;
+               sp->slevel = 1; /* fake numeric label */
+               sp->soffset = getlab();
+               sp->sflags = 0;
+               sp->stype = p->n_type;
+               sp->squal = (CON >> TSHIFT);
+
+               defloc(sp);
+               ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+               p->n_op = NAME;
+               p->n_lval = 0;
+               p->n_sp = sp;
+       }
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       return 1; /* try to put anything in a register */
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For nova, return the type-specific index number which calculation
+ * is based on its size. For example, char a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap)
+{
+       register NODE *p;
+
+       if (xdebug)
+               printf("offcon: OFFSZ %ld type %x dim %p siz %ld\n",
+                   off, t, d, tsize(t, d, ap));
+
+       p = bcon(off/SZINT);
+       if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(VOID))
+               p->n_lval = off/SZCHAR; /* pointer to char */
+       return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+cerror("spalloc");
+       if ((off % SZINT) == 0)
+               p =  buildtree(MUL, p, bcon(off/SZINT));
+       else if ((off % SZSHORT) == 0) {
+               p = buildtree(MUL, p, bcon(off/SZSHORT));
+               p = buildtree(PLUS, p, bcon(1));
+               p = buildtree(RS, p, bcon(1));
+       } else if ((off % SZCHAR) == 0) {
+               p = buildtree(MUL, p, bcon(off/SZCHAR));
+               p = buildtree(PLUS, p, bcon(3));
+               p = buildtree(RS, p, bcon(2));
+       } else
+               cerror("roundsp");
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+       /* add the size to sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       switch (p->n_type) {
+       case FLOAT:
+       case DOUBLE:
+       case LDOUBLE:
+               cerror("ninval");
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+       if (p == NULL)
+               return "";
+       return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONGLONG:
+               MODTYPE(type,LONG);
+               break;
+
+       case ULONGLONG:
+               MODTYPE(type,ULONG);
+               break;
+       case SHORT:
+               MODTYPE(type,INT);
+               break;
+       case USHORT:
+               MODTYPE(type,UNSIGNED);
+               break;
+       }
+       return (type);
+}
+
+#if 0
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the storage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+       return(EXTERN);
+}
+#endif
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+#if 0
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       printf("        .comm %s,0%o\n", exname(q->soname), off);
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       if (q->slevel == 0)
+               printf("        .lcomm %s,0%o\n", exname(q->soname), off);
+       else
+               printf("        .lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
+
+void
+setloc1(int locc)
+{
+       if (locc == lastloc)
+               return;
+       lastloc = locc;
+       printf("        .%s\n", loctbl[locc]);
+}
+#endif
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ * On Nova we put symbols over the size of an int above 24 bytes in
+ * offset and leave zeropage for small vars.
+ */
+void
+fixdef(struct symtab *sp)
+{
+#if 0
+       if (sp->sclass != AUTO)
+               return; /* not our business */
+       if (ISPTR(sp->stype) || sp->stype < LONG)
+               return;
+       if (sp->soffset >= (MAXZP * SZINT))
+               return; /* already above */
+       /* have to move */
+       /* XXX remember old autooff for reorg of smaller vars */
+       if (autooff < MAXZP * SZINT)
+               autooff = MAXZP * SZINT;
+       oalloc(sp, &autooff);
+#endif
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/nova/local2.c b/lang/pcc/pcc/arch/nova/local2.c
new file mode 100644 (file)
index 0000000..59d20aa
--- /dev/null
@@ -0,0 +1,622 @@
+/*     $Id: local2.c,v 1.13 2015/03/28 08:28:46 ragge Exp $    */
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int totstk;
+
+       totstk = p2maxautooff/(SZINT/SZCHAR);
+
+       if (totstk)
+               printf("        .word 0%o\n", totstk);
+       printf("%s:\n", ipp->ipp_name);
+       if (ipp->ipp_vis)
+               printf("        .globl %s\n", ipp->ipp_name);
+       printf("        mov 3,0\n");    /* put ret pc in ac0 */
+       printf("        jsr @16\n");    /* jump to prolog */
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       printf("        jmp @17\n");
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str = 0;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               cerror("hopcode OR");
+               break;
+       case ER:
+               cerror("hopcode xor");
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+#if 0
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+#endif
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       return 0;
+}
+
+#if 0
+/*
+ * Assign to a bitfield.
+ * Clumsy at least, but what to do?
+ */
+static void
+bfasg(NODE *p)
+{
+       NODE *fn = p->n_left;
+       int shift = UPKFOFF(fn->n_rval);
+       int fsz = UPKFSZ(fn->n_rval);
+       int andval, tch = 0;
+
+       /* get instruction size */
+       switch (p->n_type) {
+       case CHAR: case UCHAR: tch = 'b'; break;
+       case SHORT: case USHORT: tch = 'w'; break;
+       case INT: case UNSIGNED: tch = 'l'; break;
+       default: comperr("bfasg");
+       }
+
+       /* put src into a temporary reg */
+       printf("        mov%c ", tch);
+       adrput(stdout, getlr(p, 'R'));
+       printf(",");
+       adrput(stdout, getlr(p, '1'));
+       printf("\n");
+
+       /* AND away the bits from dest */
+       andval = ~(((1 << fsz) - 1) << shift);
+       printf("        and%c $%d,", tch, andval);
+       adrput(stdout, fn->n_left);
+       printf("\n");
+
+       /* AND away unwanted bits from src */
+       andval = ((1 << fsz) - 1);
+       printf("        and%c $%d,", tch, andval);
+       adrput(stdout, getlr(p, '1'));
+       printf("\n");
+
+       /* SHIFT left src number of bits */
+       if (shift) {
+               printf("        sal%c $%d,", tch, shift);
+               adrput(stdout, getlr(p, '1'));
+               printf("\n");
+       }
+
+       /* OR in src to dest */
+       printf("        or%c ", tch);
+       adrput(stdout, getlr(p, '1'));
+       printf(",");
+       adrput(stdout, fn->n_left);
+       printf("\n");
+}
+#endif
+
+#if 0
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+       int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       printf("        subl $%d,%%esp\n", sz);
+       printf("        pushl $%d\n", sz);
+       expand(p, 0, "  pushl AL\n");
+       expand(p, 0, "  leal 8(%esp),A1\n");
+       expand(p, 0, "  pushl A1\n");
+       printf("        call memcpy\n");
+       printf("        addl $12,%%esp\n");
+}
+#endif
+
+void
+zzzcode(NODE *p, int c)
+{
+       int pr;
+
+       switch (c) {
+
+       case 'C':  /* remove from stack after subroutine call */
+               pr = p->n_qual;
+               switch (pr) {
+               case 1:
+                       printf("\tisz sp\n");
+                       break;
+               case 2:
+                       printf("\tisz sp\n\tisz sp\n");
+                       break;
+               case 3:
+                       printf("\tisz sp\n\tisz sp\n\tisz sp\n");
+                       break;
+               case 4:
+                       printf("\tisz sp\n\tisz sp\n\tisz sp\n\tisz sp\n");
+                       break;
+               default:
+                       printf("        lda 2,[0%o]\n", pr);
+                       printf("        lda 3,sp\n");
+                       printf("        add 2,3\n");
+                       printf("        sta 3,sp\n");
+                       break;
+               }
+               break;
+#if 0
+       case 'A': /* print out a skip ending if any numbers in queue */
+               if (ldq == NULL)
+                       return;
+               printf(",skp\n.LP%d:    .word 0%o", ldq->lab, ldq->val);
+               if (ldq->name && *ldq->name)
+                       printf("+%s", ldq->name);
+               printf("\n");
+               ldq = ldq->next;
+               break;
+
+       case 'B': /* print a label for later load */
+               ld = tmpalloc(sizeof(struct ldq));
+               ld->val = p->n_lval;
+               ld->name = p->n_name;
+               ld->lab = prolnum++;
+               ld->next = ldq;
+               ldq = ld;
+               printf(".LP%d-.", ld->lab);
+               break;
+
+       case 'C': /* fix reference to external variable via indirection */
+               zzzcode(p->n_left, 'B');
+               break;
+
+       case 'D': /* fix reference to external variable via indirection */
+               zzzcode(p, 'B');
+               break;
+#endif
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       int o = p->n_op;
+
+cerror("flshape");
+       if (o == OREG || o == REG || o == NAME)
+               return SRDIR; /* Direct match */
+       if (o == UMUL && shumul(p->n_left, SOREG))
+               return SROREG; /* Convert into oreg */
+       return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("[" CONFMT "]", val);
+}
+
+/*
+ * Conput prints out a constant.
+ */
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = p->n_lval;
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+0%o", val);
+               } else
+                       fprintf(fp, "0%o", val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+comperr("upput");
+#if 0
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%%%s", &rnames[p->n_rval][3]);
+               break;
+
+       case NAME:
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+       case ICON:
+               printf("$" CONFMT, p->n_lval >> 32);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+#endif
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       int i;
+       /* output an address, with offsets, from p */
+
+static int looping = 7;
+if (looping == 0) {
+       looping = 1;
+       printf("adrput %p\n", p);
+       fwalk(p, e2print, 0);
+       looping = 0;
+}
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case ICON:
+               /* addressable value of the constant */
+               fputc('[', io);
+               if (p->n_type == INCREF(CHAR) || p->n_type == INCREF(UCHAR))
+                       printf(".byteptr ");
+               conput(io, p);
+               fputc(']', io);
+               break;
+
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       fputs(p->n_name, io);
+                       if (p->n_lval != 0)
+                               fprintf(io, "+" CONFMT, p->n_lval);
+               } else
+                       fprintf(io, CONFMT, p->n_lval);
+               break;;
+
+       case OREG:
+               if (p->n_name[0])
+                       comperr("name in OREG");
+               i = (int)p->n_lval;
+               if (i < 0) {
+                       putchar('-');
+                       i = -i;
+               }
+               printf("0%o,%s", i, rnames[regno(p)]);
+               break;
+
+       case REG:
+               fprintf(io, "%s", rnames[p->n_rval]);
+               break;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               break;
+
+       }
+}
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       comperr("cbgen");
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       if (x2debug)
+               printip(ipole);
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+       comperr("rmove");
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ * Return true if we always can find a color.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num = 0;
+
+       switch (c) {
+       case CLASSA:
+               num = (r[CLASSA]+r[CLASSB]) < AREGCNT;
+               break;
+       case CLASSB:
+               num = (r[CLASSB]+r[CLASSA]) < BREGCNT;
+               break;
+       case CLASSC:
+               num = r[CLASSC] < CREGCNT;
+               break;
+       case CLASSD:
+               num = r[CLASSD] < DREGCNT;
+               break;
+       case CLASSE:
+               num = r[CLASSE] < EREGCNT;
+               break;
+       }
+       return num;
+}
+
+char *rnames[] = {
+       "0", "1", "2", "3", "2", "3", "fp", "sp"
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       return ISPTR(t) ? CLASSB : CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left) { 
+               if (p->n_right->n_op != ASSIGN)
+                       size += szty(p->n_right->n_type);
+       }
+       if (p->n_op != ASSIGN)
+               size += szty(p->n_type);
+
+        op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       switch (shape) {
+       case SLDFPSP:
+               return regno(p) == FPREG || regno(p) == STKREG;
+       }
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
+
+void
+storemod(NODE *q, int off, int reg)
+{
+       NODE *l, *r, *p;
+
+       if (off < MAXZP*2) {
+               q->n_op = NAME;
+               q->n_name = "";
+               q->n_lval = -off/2 + ZPOFF;
+       } else {
+               l = mklnode(REG, 0, reg, INCREF(q->n_type));
+               r = mklnode(ICON, off, 0, INT);
+               p = mkbinode(PLUS, l, r, INCREF(q->n_type));
+               q->n_op = UMUL;
+               q->n_left = p;
+       }
+       q->n_rval = q->n_su = 0;
+}
diff --git a/lang/pcc/pcc/arch/nova/macdefs.h b/lang/pcc/pcc/arch/nova/macdefs.h
new file mode 100644 (file)
index 0000000..0dcd205
--- /dev/null
@@ -0,0 +1,179 @@
+/*     $Id: macdefs.h,v 1.10 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for Data General Nova.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|(val);
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         8
+#define SZINT          16
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      64
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     16      /* Actually 15 */
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         8
+#define ALINT          16
+#define ALFLOAT                16
+#define ALDOUBLE       16
+#define ALLDOUBLE      16
+#define ALLONG         16
+#define ALLONGLONG     16
+#define ALSHORT                16
+#define ALPOINT                16
+#define ALSTRUCT       16
+#define ALSTACK                16 
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         MIN_SHORT
+#define        MAX_INT         MAX_SHORT
+#define        MAX_UNSIGNED    MAX_USHORT
+#define        MIN_LONG        0x80000000L
+#define        MAX_LONG        0x7fffffffL
+#define        MAX_ULONG       0xffffffffUL
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+/* Default char is unsigned */
+#define        CHAR_UNSIGNED
+#define WORD_ADDRESSED
+#define        BOOL_TYPE       UCHAR
+#define        MYALIGN         /* provide private alignment function */
+
+/*
+ * Use large-enough types.
+ */
+typedef        long CONSZ;
+typedef        unsigned long U_CONSZ;
+typedef long OFFSZ;
+
+#define CONFMT "0%lo"          /* format for printing constants */
+#define LABFMT "L%d"           /* format for printing labels */
+#define        STABLBL "LL%d"          /* format for stab (debugging) labels */
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+#define ARGINIT                0       /* first arg at 0 offset */
+#define AUTOINIT       32      /* first var below 32-bit offset */
+
+
+#undef FIELDOPS        /* no bit-field instructions */
+#define TARGET_ENDIAN  TARGET_BE
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&01)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define        szty(t) ((t) == DOUBLE || (t) == LDOUBLE || \
+       (t) == LONGLONG || (t) == ULONGLONG ? 4 : \
+       ((t) == LONG || (t) == ULONG || (t) == FLOAT) ? 2 : 1)
+
+/*
+ * The Nova has two register classes.  Note that the space used in 
+ * zero page is considered stack.
+ * Register 6 and 7 are FP and SP (in zero page).
+ *
+ * The classes used on Nova are:
+ *     A - AC0-AC3 (as non-index registers)    : reg 0-3
+ *     B - AC2-AC3 (as index registers)        : reg 4-5
+ * FP/SP as 6/7.
+ */
+#define        MAXREGS 8       /* 0-29 */
+
+#define        RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SBREG|TEMPREG, SBREG|TEMPREG, 0, 0
+
+#define        ROVERLAP \
+       { -1 }, { -1 }, { 4, -1 }, { 5, -1 }, { 2, -1 }, { 3, -1 },     \
+       { -1 }, { -1 }
+
+/* Return a register class based on the type of the node */
+/* Used in tshape, avoid matching fp/sp as reg */
+#define PCLASS(p) (p->n_op == REG && regno(p) > 5 ? 0 :        \
+       ISPTR(p->n_type) ? SBREG : SAREG)
+
+#define        NUMCLASS        2       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define        GCLASS(x) (x < 4 ? CLASSA : CLASSB)
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define        ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 6)      /* A1 */
+#define ENCRA2(x)      ((x) << 12)     /* A2 */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+#define        RETREG(x)       (0) /* ? Sanity */
+
+#define FPREG  6       /* frame pointer */
+#define STKREG 7       /* stack pointer */
+
+#define        MAXZP   030     /* number of locations used as stack */
+#define        ZPOFF   050     /* offset of zero page regs */
+
+#define        MYSTOREMOD
+#define        MYLONGTEMP(p,w) {                                       \
+       if (w->r_class == 0) {                                  \
+               w->r_color = freetemp(szty(p->n_type));         \
+               w->r_class = FPREG;                             \
+       }                                                       \
+       if (w->r_color < MAXZP*2) { /* color in bytes */        \
+               p->n_op = NAME;                                 \
+               p->n_lval = w->r_color/2 + ZPOFF;               \
+               p->n_name = "";                                 \
+               break;                                          \
+       }                                                       \
+}
+
+/*
+ * special shapes for sp/fp.
+ */
+#define        SLDFPSP         (MAXSPECIAL+1)  /* load fp or sp */
diff --git a/lang/pcc/pcc/arch/nova/order.c b/lang/pcc/pcc/arch/nova/order.c
new file mode 100644 (file)
index 0000000..fa35c8f
--- /dev/null
@@ -0,0 +1,173 @@
+/*     $Id: order.c,v 1.6 2014/06/03 20:19:50 ragge Exp $      */
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       if (r != 4 && r != 5)
+               return 1; /* can only index ac2 and ac3 */
+#if 0
+       if (t == CHAR || t == UCHAR) {
+               if (off < -256 || off > 254)
+                       return 1;
+       } else
+#endif
+       if (off < -128 || off > 127)
+               return 1;
+       return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *r;
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (regno(p) == 4 || regno(p) == 5)
+               return; /* Is already OREG */
+
+       r = p->n_right;
+       if ((p->n_op == PLUS || p->n_op == MINUS) && r->n_op == ICON) {
+               if (!isreg(p->n_left) ||
+                   (regno(p->n_left) != 4 && regno(p->n_left) != 5))
+                       (void)geninsn(p->n_left, INBREG);
+               return;
+       }
+       (void)geninsn(p, INBREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on x86 */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0;
+}
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[1] = { -1 }; /* Terminate with -1 */
+
+       return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/nova/table.c b/lang/pcc/pcc/arch/nova/table.c
new file mode 100644 (file)
index 0000000..69fab42
--- /dev/null
@@ -0,0 +1,1572 @@
+/*     $Id: table.c,v 1.3 2014/06/03 20:19:50 ragge Exp $      */
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define ANYREG (INAREG|INBREG|INCREG)
+# define TUWORD TUNSIGNED|TULONG
+# define TSWORD TINT|TLONG
+# define TWORD TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/*
+ * All ASSIGN entries.
+ */
+/* reg->reg */
+{ ASSIGN,      FOREFF|INAREG|INBREG,
+       SAREG|SBREG,    TWORD|TPOINT,
+       SAREG|SBREG,    TWORD|TPOINT,
+               0,      RDEST,
+               "       mov AR,AL\n", },
+/* reg->mem */
+{ ASSIGN,      FOREFF|INAREG|INBREG,
+       SNAME|SOREG,    TWORD|TPOINT,
+       SAREG|SBREG,    TWORD|TPOINT,
+               0,      RDEST,
+               "       sta AR,AL\n", },
+/* mem->reg */
+{ ASSIGN,      FOREFF|INAREG|INBREG,
+       SAREG|SBREG,    TWORD|TPOINT,
+       SNAME|SOREG,    TWORD|TPOINT,
+               0,      RDEST,
+               "       lda AL,AR\n", },
+
+/*
+ * LEAF type movements.
+ */
+/* 0 -> reg */
+{ OPLTYPE,     INAREG|INBREG,
+       SANY,   TANY,
+       SZERO,  TWORD,
+               NAREG,  RESC1,
+               "       subo A1,A1\n", },
+
+/* 1 -> reg */
+{ OPLTYPE,     INAREG|INBREG,
+       SANY,   TANY,
+       SONE,   TWORD,
+               NAREG|NBREG,    RESC1,
+               "       subzl A1,A1     # 1\n", },
+
+/* constant -> reg */
+{ OPLTYPE,     INAREG|INBREG,
+       SANY,   TANY,
+       SCON,   TWORD|TPOINT,
+               NAREG|NBREG,    RESC1,
+               "       lda A1,AR\n", },
+
+/* mem -> reg */
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME|SOREG,    TWORD,
+               NAREG,  RESC1,
+               "       lda A1,AR\n", },
+
+/* reg -> A-reg */
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SAREG|SBREG,    TWORD,
+               NAREG,  RESC1,
+               "       mov AR,A1\n", },
+
+/* reg -> B-reg */
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SAREG|SBREG,    TWORD,
+               NBREG,  RESC1,
+               "       mov AR,A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SNAME|SOREG,    TPOINT,
+               NBREG,  RESC1,
+               "       lda A1,AR\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SLDFPSP,        TANY,
+               NBREG,  RESC1,
+               "       lda A1,AR\n", },
+
+/*
+ * Simple ops.
+ */
+{ PLUS,                INBREG|INAREG,
+       SAREG|SBREG,    TWORD|TPOINT,
+       SONE,           TANY,
+               0,      RLEFT,
+               "       inc AL,AL\n", },
+
+{ OPSIMP,      INBREG|INAREG|FOREFF,
+       SAREG|SBREG,    TWORD|TPOINT,
+       SAREG|SBREG,    TWORD|TPOINT,
+               0,      RLEFT,
+               "       O AR,AL\n", },
+
+/*
+ * Indirections
+ */
+{ UMUL,        INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "       lda A1,AL #\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       lda A1,AL #\n", },
+
+{ UMUL,        INBREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NBREG|NBSL,     RESC1,
+               "       lda A1,AL  # #\n", },
+
+#if 0
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV,       INCH,
+       SHCH,   TCHAR|TUCHAR,
+       SHCH,   TCHAR|TUCHAR,
+               0,      RLEFT,
+               "", },
+
+/* convert pointers to int. */
+{ SCONV,       ININT,
+       SHINT,  TPOINT|TWORD,
+       SANY,   TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV,       INLL,
+       SHLL,   TLL,
+       SHLL,   TLL,
+               0,      RLEFT,
+               "", },
+
+/* convert double <-> float. nothing to do here */
+{ SCONV,       INFL,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "", },
+
+/* convert pointers to pointers. */
+{ SCONV,       ININT,
+       SHINT,  TPOINT,
+       SANY,   TPOINT,
+               0,      RLEFT,
+               "", },
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV,       ININT,
+       SBREG|SOREG|SNAME,      TCHAR,
+       SAREG,  TSHORT|TUSHORT,
+               NASL|NAREG,     RESC1,
+               "       movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV,       ININT,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SAREG,  TSHORT|TUSHORT,
+               NASL|NAREG,     RESC1,
+               "       movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV,       ININT,
+       SHCH|SOREG|SNAME,       TCHAR,
+       SAREG,  TWORD|TPOINT,
+               NASL|NAREG,     RESC1,
+               "       movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV,       ININT,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV,       INLL,
+       SHCH|SOREG|SNAME,       TCHAR,
+       SANY,   TLL,
+               NSPECIAL|NAREG|NASL,    RESC1,
+               "       movsbl AL,%eax\n        cltd\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,       INLL,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SANY,                   TLL,
+               NCREG|NCSL,     RESC1,
+               "       movzbl AL,A1\n  xorl U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+{ SCONV,       INFL,
+       SHCH|SOREG|SNAME,       TCHAR,
+       SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG,       RESC2,
+               "       movsbl AL,A1\n  pushl A1\n"
+               "       fildl (%esp)\n  addl $4,%esp\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+{ SCONV,       INFL,
+       SHCH|SOREG|SNAME,       TUCHAR,
+       SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG,       RESC2,
+               "       movzbl AL,A1\n  pushl A1\n"
+               "       fildl (%esp)\n  addl $4,%esp\n", },
+
+/* short to something */
+
+/* convert short (in memory) to char */
+{ SCONV,       INCH,
+       SNAME|SOREG,    TSHORT|TUSHORT,
+       SHCH,           TCHAR|TUCHAR,
+               NBREG|NBSL,     RESC1,
+               "       movb AL,A1\n", },
+
+/* convert short (in reg) to char. */
+{ SCONV,       INCH,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZM", },
+
+/* convert short to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV,       ININT,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG,     RESC1,
+               "       movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV,       INLL,
+       SAREG|SOREG|SNAME,      TSHORT,
+       SHLL,                   TLL,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "       movswl AL,%eax\n        cltd\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,       INLL,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SHLL,                   TLL,
+               NCREG|NCSL,     RESC1,
+               "       movzwl AL,A1\n  xorl U1,U1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV,       INFL,
+       SOREG|SNAME,    TSHORT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       fild AL\n", },
+
+/* convert short (in register) to float/double */
+{ SCONV,       INFL,
+       SAREG,  TSHORT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,    RESC1,
+               "       pushw AL\n      fild (%esp)\n   addl $2,%esp\n", },
+
+/* convert unsigned short to double XXX - use NTEMP */
+{ SCONV,       INFL,
+       SAREG|SOREG|SNAME,      TUSHORT,
+       SHFL,                   TLDOUBLE|TDOUBLE|TFLOAT,
+               NAREG|NASL|NDREG|NTEMP, RESC2,
+               "       movzwl AL,A1\n  pushl A1\n"
+               "       fildl (%esp)\n  addl $4,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV,       INCH,
+       SAREG,  TWORD,
+       SANY,   TCHAR|TUCHAR,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZM", },
+
+/* convert int to short. Nothing to do */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TSHORT|TUSHORT,
+               0,      RLEFT,
+               "", },
+
+/* convert int to long long */
+{ SCONV,       INLL,
+       SAREG,  TWORD|TPOINT,
+       SCREG,  TLONGLONG,
+               NSPECIAL|NCREG|NCSL,    RESC1,
+               "       cltd\n", },
+
+/* convert int to unsigned long long */
+{ SCONV,       INLL,
+       SAREG|SOREG|SNAME,      TWORD|TPOINT,
+       SHLL,   TULONGLONG,
+               NCSL|NCREG,     RESC1,
+               "       movl AL,A1\n    xorl U1,U1\n", },
+
+/* convert int (in memory) to double */
+{ SCONV,       INFL,
+       SOREG|SNAME,    TWORD,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       fildl AL\n", },
+
+/* convert int (in register) to double */
+{ SCONV,       INFL,
+       SAREG,  TWORD,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,    RESC1,
+               "       pushl AL\n      fildl (%esp)\n  addl $4,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV,       INCH,
+       SOREG|SNAME,    TLL,
+       SANY,   TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       movb AL,A1\n", },
+
+/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV,       INCH,
+       SHLL,   TLL,
+       SANY,   TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "ZS", },
+
+/* convert (u)long long to (u)short (mem->reg) */
+{ SCONV,       INAREG,
+       SOREG|SNAME,    TLL,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       movw AL,A1\n", },
+
+/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */
+{ SCONV,       INAREG,
+       SHLL|SOREG|SNAME,       TLL,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "ZS", },
+
+/* convert long long to int (mem->reg) */
+{ SCONV,       INAREG,
+       SOREG|SNAME,    TLL,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+/* convert long long to int (reg->reg, hopefully nothing) */
+{ SCONV,       INAREG,
+       SHLL|SOREG|SNAME,       TLL,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "ZS", },
+
+/* convert long long (in memory) to floating */
+{ SCONV,       INFL,
+       SOREG|SNAME,    TLONGLONG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "       fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV,       INFL,
+       SHLL,   TLONGLONG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               NTEMP|NDREG,    RESC1,
+               "       pushl UL\n      pushl AL\n"
+               "       fildq (%esp)\n  addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV,       INFL,
+       SCREG,  TULONGLONG,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NDREG,  RESC1,
+               "ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV,       INCH,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHCH,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "       subl $4,%esp\n  fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV,       INCH,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHCH,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NCREG,  RESC1,
+               "       subl $4,%esp\n  fistpl (%esp)\n popl A1\n", },
+#endif
+
+/* convert float/double to (u)int. XXX should use NTEMP here */
+{ SCONV,       INAREG,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SAREG,  TWORD,
+               NAREG,  RESC1,
+               "       subl $4,%esp\n  fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double (in register) to (unsigned) long long */
+/* XXX - unsigned is not handled correct */
+{ SCONV,       INLL,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHLL,   TLONGLONG|TULONGLONG,
+               NCREG,  RESC1,
+               "       subl $8,%esp\n  fistpq (%esp)\n"
+               "       popl A1\n       popl U1\n", },
+
+/* slut sconv */
+#endif
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       jsr CL\nZC", },
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       jsr CL\n", },
+
+{ CALL,                INAREG|FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       jsr CL\nZC", },
+
+{ UCALL,       INAREG|FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       jsr CL\n", },
+
+#if 0
+{ CALL,        INAREG,
+       SCON,   TANY,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SAREG,  TWORD|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call CL\n", },
+
+{ CALL,        INBREG,
+       SCON,   TANY,
+       SBREG,  TCHAR|TUCHAR,
+               NBREG,  RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TCHAR|TUCHAR,
+               NBREG,  RESC1,  /* should be 0 */
+               "       call CL\n", },
+
+{ CALL,                INCREG,
+       SCON,   TANY,
+       SCREG,  TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INCREG,
+       SCON,   TANY,
+       SCREG,  TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call CL\n", },
+
+{ CALL,        INDREG,
+       SCON,   TANY,
+       SDREG,  TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ UCALL,       INDREG,
+       SCON,   TANY,
+       SDREG,  TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call CL\nZC", },
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       call *AL\nZC", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INBREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INCREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INCREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ CALL,                INDREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+{ UCALL,       INDREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NDREG|NDSL,     RESC1,  /* should be 0 */
+               "       call *AL\nZC", },
+
+/* struct return */
+{ USTCALL,     FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     0,
+               "ZP     call CL\nZC", },
+
+{ USTCALL,     INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call CL\nZC", },
+
+{ USTCALL,     INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call *AL\nZC", },
+
+{ STCALL,      FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     0,
+               "ZP     call CL\nZC", },
+
+{ STCALL,      INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call CL\nZC", },
+
+{ STCALL,      INAREG,
+       SNAME|SAREG,    TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "ZP     call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Special treatment for long long */
+{ PLUS,                INLL|FOREFF,
+       SHLL,           TLL,
+       SHLL|SNAME|SOREG,       TLL,
+               0,      RLEFT,
+               "       addl AR,AL\n    adcl UR,UL\n", },
+
+/* Special treatment for long long  XXX - fix commutative check */
+{ PLUS,                INLL|FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SHLL,                   TLL,
+               0,      RRIGHT,
+               "       addl AL,AR\n    adcl UL,UR\n", },
+
+{ PLUS,                INFL,
+       SHFL,           TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       faddl AR\n", },
+
+{ PLUS,                INFL|FOREFF,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       faddp\n", },
+
+{ PLUS,                INAREG,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incl AL\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TWORD|TPOINT,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       leal CR(AL),A1\n", },
+
+{ PLUS,                INCH,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SONE,   TANY,
+               0,      RLEFT,
+               "       incb AL\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               NAREG|NASL|NASR,        RESC1,
+               "       leal (AL,AR),A1\n", },
+
+
+/* address as register offset, negative */
+{ MINUS,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       leal -CR(AL),A1\n", },
+
+{ MINUS,       INLL|FOREFF,
+       SHLL,   TLL,
+       SHLL|SNAME|SOREG,       TLL,
+               0,      RLEFT,
+               "       subl AR,AL\n    sbbl UR,UL\n", },
+
+{ MINUS,       INFL,
+       SHFL,   TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       fsubl AR\n", },
+
+{ MINUS,       INFL|FOREFF,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+{ OPSIMP,      INAREG|FOREFF,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+               0,      RLEFT,
+               "       Ol AR,AL\n", },
+
+{ OPSIMP,      INAREG|FOREFF,
+       SHINT,          TSHORT|TUSHORT,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       Ow AR,AL\n", },
+
+{ OPSIMP,      INCH|FOREFF,
+       SHCH,           TCHAR|TUCHAR,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       Ob AR,AL\n", },
+
+{ OPSIMP,      INAREG|FOREFF,
+       SAREG,  TWORD|TPOINT,
+       SCON,   TWORD|TPOINT,
+               0,      RLEFT,
+               "       Ol AR,AL\n", },
+
+{ OPSIMP,      INAREG|FOREFF,
+       SHINT|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       Ow AR,AL\n", },
+
+{ OPSIMP,      INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       Ob AR,AL\n", },
+
+{ OPSIMP,      INLL|FOREFF,
+       SHLL,   TLL,
+       SHLL|SNAME|SOREG,       TLL,
+               0,      RLEFT,
+               "       Ol AR,AL\n      Ol UR,UL\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)longlong left shift is emulated */
+{ LS,  INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SHCH,           TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sall AR,AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG,  TWORD,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       sall AR,AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shlw AR,AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       shlw AR,AL\n", },
+
+{ LS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       salb AR,AL\n", },
+
+{ LS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SCON,                   TANY,
+               0,      RLEFT,
+               "       salb AR,AL\n", },
+
+/* (u)longlong right shift is emulated */
+{ RS,  INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSWORD,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSWORD,
+       SCON,                   TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,              RLEFT,
+               "       sarl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUWORD,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUWORD,
+       SCON,                   TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,              RLEFT,
+               "       shrl AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrw AR,AL\n", },
+
+{ RS,  INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrw AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       sarb AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       sarb AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TUCHAR,
+       SHCH,                   TCHAR|TUCHAR,
+               NSPECIAL,       RLEFT,
+               "       shrb AR,AL\n", },
+
+{ RS,  INCH|FOREFF,
+       SHCH|SNAME|SOREG,       TUCHAR,
+       SCON,                   TANY,
+               0,              RLEFT,
+               "       shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN,      FOREFF,
+       SHLL|SNAME|SOREG,       TLL,
+       SCON,           TANY,
+               0,      0,
+               "       movl AR,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SHLL,           TLL,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movl AR,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SCON,           TANY,
+               0,      0,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SCON,           TANY,
+               0,      0,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      0,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCH,
+       SHCH,           TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      RDEST,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INLL,
+       SHLL|SNAME|SOREG,       TLL,
+       SHLL,                   TLL,
+               0,      RDEST,
+               "       movl AR,AL\n    movl UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SAREG,          TWORD|TPOINT,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+               0,      RDEST,
+               "       movl AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               0,      RDEST,
+               "       movw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCH,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+       SHCH,           TCHAR|TUCHAR|TWORD,
+               0,      RDEST,
+               "       movb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,           TANY,
+       SAREG,  TANY,
+               NAREG,  RDEST,
+               "ZE", },
+
+{ ASSIGN,      FOREFF,
+       SFLD,           TANY,
+       SAREG|SNAME|SOREG|SCON, TANY,
+               NAREG,  0,
+               "ZE", },
+
+{ ASSIGN,      INDREG|FOREFF,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TLDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fstt AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TLDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       fstpt AL\n", },
+
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fstl AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TDOUBLE,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       fstpl AL\n", },
+
+{ ASSIGN,      INFL,
+       SNAME|SOREG,    TFLOAT,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fsts AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TFLOAT,
+       SHFL,   TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      0,
+               "       fstps AL\n", },
+/* end very important order */
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TLDOUBLE,
+       SHFL|SOREG|SNAME,       TLDOUBLE,
+               0,      RDEST,
+               "       fldt AR\n", },
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TDOUBLE,
+       SHFL|SOREG|SNAME,       TDOUBLE,
+               0,      RDEST,
+               "       fldl AR\n", },
+
+{ ASSIGN,      INFL|FOREFF,
+       SHFL,           TFLOAT,
+       SHFL|SOREG|SNAME,       TFLOAT,
+               0,      RDEST,
+               "       flds AR\n", },
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME|SAREG,      TPTRTO|TSTRUCT,
+       SFUNCALL,       TPTRTO|TSTRUCT,
+               0,      RRIGHT,
+               "", },
+#endif
+
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SAREG|SOREG|SNAME,      TPTRTO|TANY,
+               NSPECIAL,       RRIGHT,
+               "ZQ", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* long long div is emulated */
+{ DIV, INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SCREG|SNAME|SOREG|SCON, TLL,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ DIV, INAREG,
+       SAREG,                  TSWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               NSPECIAL,       RDEST,
+               "       cltd\n  idivl AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TUWORD|TPOINT,
+               NSPECIAL,       RDEST,
+               "       xorl %edx,%edx\n        divl AR\n", },
+
+{ DIV, INAREG,
+       SAREG,                  TUSHORT,
+       SAREG|SNAME|SOREG,      TUSHORT,
+               NSPECIAL,       RDEST,
+               "       xorl %edx,%edx\n        divw AR\n", },
+
+{ DIV, INCH,
+       SHCH,                   TUCHAR,
+       SHCH|SNAME|SOREG,       TUCHAR,
+               NSPECIAL,       RDEST,
+               "       xorb %ah,%ah\n  divb AR\n", },
+
+{ DIV, INFL,
+       SHFL,           TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       fdivl AR\n", },
+
+{ DIV, INFL,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fdivZAp\n", },
+
+/* (u)longlong mod is emulated */
+{ MOD, INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SCREG|SNAME|SOREG|SCON, TLL,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ MOD, INAREG,
+       SAREG,                  TSWORD,
+       SAREG|SNAME|SOREG,      TSWORD,
+               NAREG|NSPECIAL, RESC1,
+               "       cltd\n  idivl AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TUWORD|TPOINT,
+       SAREG|SNAME|SOREG,      TUWORD|TPOINT,
+               NAREG|NSPECIAL, RESC1,
+               "       xorl %edx,%edx\n        divl AR\n", },
+
+{ MOD, INAREG,
+       SAREG,                  TUSHORT,
+       SAREG|SNAME|SOREG,      TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       xorl %edx,%edx\n        divw AR\n", },
+
+{ MOD, INCH,
+       SHCH,                   TUCHAR,
+       SHCH|SNAME|SOREG,       TUCHAR,
+               NBREG|NSPECIAL, RESC1,
+               "       xorb %ah,%ah\n  divb AR\n", },
+
+/* (u)longlong mul is emulated */
+{ MUL, INCREG,
+       SCREG|SNAME|SOREG|SCON, TLL,
+       SCREG|SNAME|SOREG|SCON, TLL,
+               NSPECIAL|NCREG|NCSL|NCSR,       RESC1,
+               "ZO", },
+
+{ MUL, INAREG,
+       SAREG,                          TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON,         TWORD|TPOINT,
+               0,      RLEFT,
+               "       imull AR,AL\n", },
+
+{ MUL, INAREG,
+       SAREG,                  TSHORT|TUSHORT,
+       SAREG|SNAME|SOREG,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       imulw AR,AL\n", },
+
+{ MUL, INCH,
+       SHCH,                   TCHAR|TUCHAR,
+       SHCH|SNAME|SOREG,       TCHAR|TUCHAR,
+               NSPECIAL,       RDEST,
+               "       imulb AR\n", },
+
+{ MUL, INFL,
+       SHFL,           TDOUBLE,
+       SNAME|SOREG,    TDOUBLE,
+               0,      RLEFT,
+               "       fmull AR\n", },
+
+{ MUL, INFL,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,           TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,        INLL,
+       SANY,   TANY,
+       SOREG,  TLL,
+               NCREG|NCSL,     RESC1,
+               "       movl UL,U1\n    movl AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ UMUL,        INCH,
+       SANY,   TANY,
+       SOREG,  TCHAR|TUCHAR,
+               NBREG|NBSL,     RESC1,
+               "       movb AL,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SOREG,  TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       movw AL,A1\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TLDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "       fldt AL\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TDOUBLE,
+               NDREG|NDSL,     RESC1,
+               "       fldl AL\n", },
+
+{ UMUL,        INFL,
+       SANY,   TANY,
+       SOREG,  TFLOAT,
+               NDREG|NDSL,     RESC1,
+               "       flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG,       FORCC,
+       SHLL|SOREG|SNAME,       TLL,
+       SHLL,                   TLL,
+               0,      0,
+               "ZD", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TWORD|TPOINT,
+       SCON|SAREG,     TWORD|TPOINT,
+               0,      RESCC,
+               "       cmpl AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SCON|SAREG,     TWORD|TPOINT,
+       SAREG|SOREG|SNAME,      TWORD|TPOINT,
+               0,      RESCC,
+               "       cmpl AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+       SCON|SAREG,     TANY,
+               0,      RESCC,
+               "       cmpw AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SBREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       SCON|SBREG,     TANY,
+               0,      RESCC,
+               "       cmpb AR,AL\n", },
+
+{ OPLOG,       FORCC,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NSPECIAL,       0,
+               "ZG", },
+
+{ OPLOG,       FORCC,
+       SOREG|SNAME,    TDOUBLE|TFLOAT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               NSPECIAL,       0,
+               "ZG", },
+
+#if 0
+/* Ppro and later only */
+{ OPLOG,       FORCC,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+       SDREG,  TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RESCC,
+               "ZA     fucomip %st,%st(1)\n", },
+#endif
+
+{ OPLOG,       FORCC,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND, INAREG|FOREFF,
+       SAREG|SOREG|SNAME,      TWORD,
+       SCON|SAREG,             TWORD,
+               0,      RLEFT,
+               "       andl AR,AL\n", },
+
+{ AND, INCREG|FOREFF,
+       SCREG,                  TLL,
+       SCREG|SOREG|SNAME,      TLL,
+               0,      RLEFT,
+               "       andl AR,AL\n    andl UR,UL\n", },
+
+{ AND, INAREG|FOREFF,
+       SAREG,                  TWORD,
+       SAREG|SOREG|SNAME,      TWORD,
+               0,      RLEFT,
+               "       andl AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+       SCON|SAREG,             TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       andw AR,AL\n", },
+
+{ AND, INAREG|FOREFF,  
+       SAREG,                  TSHORT|TUSHORT,
+       SAREG|SOREG|SNAME,      TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       andw AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+       SBREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       SCON|SBREG,             TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       andb AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+       SBREG,                  TCHAR|TUCHAR,
+       SBREG|SOREG|SNAME,      TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp LL\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO,        FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,     INLL,
+       SANY,   TANY,
+       SCREG|SCON|SOREG|SNAME, TLL,
+               NCREG,  RESC1,
+               "       movl UL,U1\n    movl AL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "       movb AL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT,
+               NAREG,  RESC1,
+               "       movw AL,A1\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TLDOUBLE,
+       SOREG|SNAME,    TLDOUBLE,
+               NDREG,  RESC1,
+               "       fldt AL\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TDOUBLE,
+       SOREG|SNAME,    TDOUBLE,
+               NDREG,  RESC1,
+               "       fldl AL\n", },
+
+{ OPLTYPE,     INDREG,
+       SANY,           TFLOAT,
+       SOREG|SNAME,    TFLOAT,
+               NDREG,  RESC1,
+               "       flds AL\n", },
+
+/* Only used in ?: constructs. The stack already contains correct value */
+{ OPLTYPE,     INDREG,
+       SANY,   TFLOAT|TDOUBLE|TLDOUBLE,
+       SDREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               NDREG,  RESC1,
+               "", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      INCREG|FOREFF,
+       SCREG,  TLL,
+       SCREG,  TLL,
+               0,      RLEFT,
+               "       negl AL\n       adcl $0,UL\n    negl UL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "       negl AL\n", },
+
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       negw AL\n", },
+
+{ UMINUS,      INBREG|FOREFF,
+       SBREG,  TCHAR|TUCHAR,
+       SBREG,  TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       negb AL\n", },
+
+{ UMINUS,      INFL|FOREFF,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+       SHFL,   TLDOUBLE|TDOUBLE|TFLOAT,
+               0,      RLEFT,
+               "       fchs\n", },
+
+{ COMPL,       INCREG,
+       SCREG,  TLL,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notl AL\n       notl UL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notl AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notw AL\n", },
+
+{ COMPL,       INBREG,
+       SBREG,  TCHAR|TUCHAR,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       notb AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,      FOREFF,
+       SCON|SCREG|SNAME|SOREG, TLL,
+       SANY,   TLL,
+               0,      RNULL,
+               "       pushl UL\n      pushl AL\n", },
+#endif
+
+{ FUNARG,      FOREFF,
+       SAREG|SBREG,    TCHAR|TUCHAR|TWORD|TPOINT,
+       SANY,           TCHAR|TUCHAR|TWORD|TPOINT,
+               0,      RNULL,
+               "       sta AL,@sp\n", },
+
+#if 0
+{ FUNARG,      FOREFF,
+       SCON,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SANY,   TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               0,      RNULL,
+               "       pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG|SNAME|SOREG,      TSHORT,
+       SANY,   TSHORT,
+               NAREG,  0,
+               "       movswl AL,ZN\n  pushl ZN\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG|SNAME|SOREG,      TUSHORT,
+       SANY,   TUSHORT,
+               NAREG,  0,
+               "       movzwl AL,ZN\n  pushl ZN\n", },
+
+{ FUNARG,      FOREFF,
+       SHCH|SNAME|SOREG,       TCHAR,
+       SANY,                   TCHAR,
+               NAREG,  0,
+               "       movsbl AL,A1\n  pushl A1\n", },
+
+{ FUNARG,      FOREFF,
+       SHCH|SNAME|SOREG,       TUCHAR,
+       SANY,   TUCHAR,
+               NAREG,  0,
+               "       movzbl AL,A1\n  pushl A1\n", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SOREG,    TDOUBLE,
+       SANY,   TDOUBLE,
+               0,      0,
+               "       pushl UL\n      pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TDOUBLE,
+       SANY,           TDOUBLE,
+               0,      0,
+               "       subl $8,%esp\n  fstpl (%esp)\n", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SOREG,    TFLOAT,
+       SANY,           TFLOAT,
+               0,      0,
+               "       pushl AL\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TFLOAT,
+       SANY,           TFLOAT,
+               0,      0,
+               "       subl $4,%esp\n  fstps (%esp)\n", },
+
+{ FUNARG,      FOREFF,
+       SDREG,  TLDOUBLE,
+       SANY,           TLDOUBLE,
+               0,      0,
+               "       subl $12,%esp\n fstpt (%esp)\n", },
+
+{ STARG,       FOREFF,
+       SAREG|SOREG|SNAME|SCON, TANY,
+       SANY,   TSTRUCT,
+               NSPECIAL|NAREG, 0,
+               "ZF", },
+
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/pdp10/README b/lang/pcc/pcc/arch/pdp10/README
new file mode 100644 (file)
index 0000000..176eca7
--- /dev/null
@@ -0,0 +1,20 @@
+
+
+PDP10 C calling convention
+--------------------------
+Register 1-7 are argument registers.  Types of sizes up to 36 bits are
+given in one register, two otherwise.  CHAR and SHORT are given as INTs.
+
+If the argument that would end up in register 7 requires two registers,
+it is saved on the stack instead and no more registers would end up
+on the stack.
+
+struct return: a hidden argument containing the address of the struct
+is stored as the first argument _on_the_stack_, never in register.
+
+struct argument: always saved on stack, and terminates the list 
+of arguments that are kept in registers.
+
+In case of debugging all arguments are saved on stack in the function.
+
+All variadic arguments are always saved on the stack.
diff --git a/lang/pcc/pcc/arch/pdp10/code.c b/lang/pcc/pcc/arch/pdp10/code.c
new file mode 100644 (file)
index 0000000..fdeede2
--- /dev/null
@@ -0,0 +1,204 @@
+/*     $Id: code.c,v 1.42 2012/04/22 21:07:40 plunky Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *nextsect = NULL;  /* notyet */
+       static char *loctbl[] = { "text", "data", "section .rodata" };
+       static int lastloc = -1;
+       TWORD t;
+       int s;
+
+       if (sp == NULL) {
+               lastloc = -1;
+               return;
+       }
+       t = sp->stype;
+       s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+       if (nextsect) {
+               printf("        .section %s\n", nextsect);
+               nextsect = NULL;
+               s = -1;
+       } else if (s != lastloc)
+               printf("        .%s\n", loctbl[s]);
+       lastloc = s;
+       if (sp->sclass == EXTDEF)
+               printf("        .globl %s\n", sp->soname);
+       if (sp->slevel == 0)
+               printf("%s:\n", sp->soname);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ */
+void
+efcode(void)
+{
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in stab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       NODE *p, *q;
+       int i, n;
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               uerror("no struct return yet");
+       }
+       /* recalculate the arg offset and create TEMP moves */
+       for (n = 1, i = 0; i < cnt; i++) {
+               if (n < 8) {
+                       p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+                       q = block(REG, NIL, NIL,
+                           sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+                       q->n_rval = n;
+                       p = buildtree(ASSIGN, p, q);
+                       sp[i]->soffset = regno(p->n_left);
+                       sp[i]->sflags |= STNODE;
+                       ecomp(p);
+               } else {
+                       sp[i]->soffset += SZINT * n;
+                       if (xtemps) {
+                               /* put stack args in temps if optimizing */
+                               p = tempnode(0, sp[i]->stype,
+                                   sp[i]->sdf, sp[i]->ssue);
+                               p = buildtree(ASSIGN, p, nametree(sp[i]));
+                               sp[i]->soffset = regno(p->n_left);
+                               sp[i]->sflags |= STNODE;
+                               ecomp(p);
+                       }
+               }
+               n += szty(sp[i]->stype);
+       }
+}
+
+
+void
+bjobcode(void)
+{
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+}
+
+/*
+ * Make a register node, helper for funcode.
+ */
+static NODE *
+mkreg(NODE *p, int n)
+{
+       NODE *r;
+
+       r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+       if (szty(p->n_type) == 2)
+               n += 16;
+       r->n_rval = n;
+       return r;
+}
+
+static int regnum;
+/*
+ * Move args to registers and emit expressions bottom-up.
+ */
+static void
+fixargs(NODE *p)
+{
+       NODE *r;
+
+       if (p->n_op == CM) {
+               fixargs(p->n_left);
+               r = p->n_right;
+               if (r->n_op == STARG)
+                       regnum = 9; /* end of register list */
+               else if (regnum + szty(r->n_type) > 8)
+                       p->n_right = block(FUNARG, r, NIL, r->n_type,
+                           r->n_df, r->n_sue);
+               else
+                       p->n_right = buildtree(ASSIGN, mkreg(r, regnum), r);
+       } else {
+               if (p->n_op == STARG) {
+                       regnum = 9; /* end of register list */
+               } else {
+                       r = talloc();
+                       *r = *p;
+                       r = buildtree(ASSIGN, mkreg(r, regnum), r);
+                       *p = *r;
+                       nfree(r);
+               }
+               r = p;
+       }
+       regnum += szty(r->n_type);
+}
+
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+
+       regnum = 1;
+
+       fixargs(p->n_right);
+       return p;
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/pdp10/local.c b/lang/pcc/pcc/arch/pdp10/local.c
new file mode 100644 (file)
index 0000000..44a2930
--- /dev/null
@@ -0,0 +1,838 @@
+/*     $Id: local.c,v 1.78 2014/05/29 19:20:03 plunky Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*     this file contains code which is dependent on the target machine */
+
+static int pointp(TWORD t);
+static struct symtab *newfun(char *name, TWORD type);
+
+#define        PTRNORMAL       1
+#define        PTRCHAR         2
+#define        PTRSHORT        3
+static int xptype(TWORD t);
+
+NODE *
+clocal(NODE *p)
+{
+       /* this is called to do local transformations on
+          an expression tree preparitory to its being
+          written out in intermediate code.
+       */
+
+       /* the major essential job is rewriting the
+          automatic variables and arguments in terms of
+          REG and OREG nodes */
+       /* conversion ops which are not necessary are also clobbered here */
+       /* in addition, any special features (such as rewriting
+          exclusive or) are easily handled here as well */
+
+       register struct symtab *q;
+       register NODE *r, *l, *oop;
+       register int o;
+       register int m, ml;
+       int siz;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+                       /* First 7 parameters are in registers */
+                       /* XXX last may be double */
+                       if (q->soffset/SZINT < 7) {
+                               p->n_op = REG;
+                               p->n_rval = q->soffset/SZINT;
+                               break;
+                       } else
+                               q->soffset -= 7*SZINT;
+                               
+               case AUTO:
+                       /* fake up a structure reference */
+                       if (q->stype == CHAR || q->stype == UCHAR ||
+                           q->stype == SHORT || q->stype == USHORT)
+                               r = block(REG, NIL, NIL, PTR+q->stype, 0, 0);
+                       else
+                               r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case STATIC:
+                       if (q->slevel == 0)
+                               break;
+                       p->n_lval = 0;
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+                       }
+               break;
+
+       case CALL:
+               /* avoid recursive calls */
+               r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+               l = tempnode(regno(r), p->n_type, p->n_df, p->n_sue);
+               ecomp(buildtree(ASSIGN, r, p));
+               p = l;
+               break;
+
+       case PCONV:
+               l = p->n_left;
+               /*
+                * Handle frame pointer directly without conversion,
+                * for efficiency.
+                */
+               if (l->n_op == REG && l->n_rval == 0) {
+rmpc:                  l->n_type = p->n_type;
+                       l->n_df = p->n_df;
+                       l->n_sue = p->n_sue;
+                       nfree(p);
+                       return l;
+               }
+               /* Convert ICON with name to new type */
+               if (l->n_op == ICON && l->n_sp != NULL &&
+                   l->n_type == INCREF(STRTY) && 
+                   (p->n_type == INCREF(CHAR) ||
+                   p->n_type == INCREF(UCHAR) ||
+                   p->n_type == INCREF(SHORT) ||
+                   p->n_type == INCREF(USHORT))) {
+                       l->n_lval *= (BTYPE(p->n_type) == CHAR ||
+                           BTYPE(p->n_type) == UCHAR ? 4 : 2);
+                       goto rmpc;
+               }
+               /* Convert only address constants, never convert other */
+               if (l->n_op == ICON) {
+                       if (l->n_sp == NULL)
+                               goto rmpc;
+                       if (p->n_type == INCREF(CHAR) ||
+                           p->n_type == INCREF(UCHAR) ||
+                           p->n_type == INCREF(VOID))
+                               l->n_lval = (l->n_lval & 07777777777) |
+                                   0700000000000LL;
+                       else if (p->n_type == INCREF(SHORT) ||
+                           p->n_type == INCREF(USHORT))
+                               l->n_lval = (l->n_lval & 07777777777) |
+                                   0750000000000LL;
+                       else
+                               l->n_lval = l->n_lval & 07777777777;
+                       goto rmpc;
+               }
+
+               /* Remove more conversions of identical pointers */
+               /* Be careful! optim() may do bad things */
+               if (ISPTR(DECREF(p->n_type))) {
+                       if (ISPTR(DECREF(l->n_type))) {
+                               if ((coptype(l->n_op) == UTYPE ||
+                                   coptype(l->n_op) == BITYPE) &&
+                                   (l->n_left->n_op == REG))
+                                       l->n_left->n_type = p->n_type;
+                               goto rmpc;
+                       }
+               }
+
+               /* Change PCONV from int to double pointer to right shift */
+               if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type)) &&
+                   (l->n_type == INT || l->n_type == UNSIGNED)) {
+                       p->n_op = RS;
+                       p->n_right = bcon(2);
+                       break;
+               }
+               
+               /* Check for cast integral -> pointer */
+               if (BTYPE(l->n_type) == l->n_type)
+                       break;
+
+               /* Remove conversions to identical pointers */
+               switch (xptype(p->n_type)) {
+               case PTRNORMAL:
+                       if (xptype(l->n_type) == PTRNORMAL)
+                               goto rmpc;
+                       break;
+
+               case PTRSHORT:
+                       if (xptype(l->n_type) == PTRSHORT)
+                               goto rmpc;
+                       break;
+
+               case PTRCHAR:
+                       if (xptype(l->n_type) == PTRCHAR)
+                               goto rmpc;
+                       break;
+               }
+
+               break;
+
+       case SCONV:
+               l = p->n_left;
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                            l->n_type != FLOAT && l->n_type != DOUBLE) {
+                               nfree(p);
+                               return l;
+                       }
+               }
+               /* cast to (void) XXX should be removed in MI code */
+               if (p->n_type == VOID) {
+                       nfree(p);
+                       return l;
+               }
+               m = p->n_type;
+               ml = l->n_type;
+               if (m == ml) {
+                       nfree(p);
+                       return l;
+               }
+               o = l->n_op;
+               if (ml == FLOAT || ml == DOUBLE) {
+                       if (o != FCON)
+                               break;
+                       ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */
+                       r = xbcon(ml == INT ? (int)p->n_left->n_dcon :
+                                             (unsigned)p->n_left->n_dcon,
+                                 NULL, ml);
+                       nfree(p->n_left);
+                       p->n_left = r;
+                       o = ICON;
+                       if (m == ml) {
+                               r = p->n_left;
+                               nfree(p);
+                               return r;
+                       }
+               }
+               if (o == ICON) {
+                       CONSZ val = l->n_lval;
+
+                       switch (m) {
+                       case CHAR:
+                               l->n_lval = val & 0777;
+                               if (val & 0400)
+                                       l->n_lval |= ~((CONSZ)0777);
+                               break;
+                       case UCHAR:
+                               l->n_lval = val & 0777;
+                               break;
+                       case USHORT:
+                               l->n_lval = val & 0777777;
+                               break;
+                       case SHORT:
+                               l->n_lval = val & 0777777;
+                               if (val & 0400000)
+                                       l->n_lval |= ~((CONSZ)0777777);
+                               break;
+                       case UNSIGNED:
+                               l->n_lval = val & 0777777777777LL;
+                               break;
+                       case INT:
+                               l->n_lval = val & 0777777777777LL;
+                               if (val & 0400000000000LL)
+                                       l->n_lval |= ~(0777777777777LL);
+                               break;
+                       case LONGLONG:  /* XXX */
+                       case ULONGLONG:
+                               l->n_lval = val;
+                               break;
+                       case VOID:
+                               break;
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = 0;
+                               break;
+                       default:
+                               cerror("unknown type %d", m);
+                       }
+                       l->n_type = m;
+                       l->n_sue = 0;
+                       nfree(p);
+                       return l;
+               }
+               break;
+
+       case PMCONV:
+       case PVCONV:
+/*                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); */
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+       case RS:
+       case RSEQ:
+               /* convert >> to << with negative shift count */
+               /* Beware! constant shifts will be converted back in optim() */
+
+               if (p->n_right->n_op != UMINUS) {
+                       p->n_right = buildtree(UMINUS, p->n_right, NIL);
+               } else {
+                       r = p->n_right;
+                       p->n_right = p->n_right->n_left;
+                       nfree(r);
+               }
+               if (p->n_op == RS)
+                       p->n_op = LS;
+               else
+                       p->n_op = LSEQ;
+               break;
+
+       case UMUL: /* Convert structure assignment to memcpy() */
+               if (p->n_left->n_op == PLUS &&
+                   p->n_left->n_left->n_op == PCONV &&
+                   p->n_left->n_right->n_op == ICON &&
+                   (p->n_type == CHAR || p->n_type == UCHAR ||
+                   p->n_type == SHORT || p->n_type == USHORT)) {
+                       /* Can remove the left SCONV */
+                       l = p->n_left->n_left;
+                       p->n_left->n_left = l->n_left;
+                       nfree(l);
+                       break;
+
+               }
+               if (p->n_left->n_op != STASG)
+                       break;
+               oop = p;
+               p = p->n_left;
+               siz = p->n_sue->suesize/SZCHAR;
+               l = p->n_left;
+               r = p->n_right;
+               if (l->n_type == STRTY || l->n_type == UNIONTY) {
+                       if (l->n_op == UMUL) {
+                               p->n_left = l->n_left;
+                               nfree(l);
+                               l = p->n_left;
+                       } else {
+                               l = block(ADDROF, l, NIL, INCREF(l->n_type),
+                                   0, 0);
+                       }
+               }
+               if ((l->n_type != (STRTY+PTR) && l->n_type != (UNIONTY+PTR)) ||
+                   (r->n_type != (STRTY+PTR) && r->n_type != (UNIONTY+PTR)))
+                       cerror("bad stasg, l = %o, r = %o", l->n_type, r->n_type);
+               q = newfun("__structcpy", p->n_type);
+
+               /* structure pointer block */
+               l = block(CM, l, r, INT, 0, 0);
+               /* Size block */
+               r = block(CM, l, bcon(siz), INT, 0, 0);
+
+               l = xbcon(0, q, q->stype);
+               p->n_left = l;
+               p->n_right = r;
+               p->n_op = CALL;
+               oop->n_left = p;
+               return oop;
+
+       case FORCE:
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = RETREG(p->n_type);
+               break;
+
+       }
+
+       return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+       NODE *r;
+
+       switch (p->n_op) {
+       case ULT: /* exor sign bit to avoid unsigned comparitions */
+       case ULE:
+       case UGT:
+       case UGE:
+               if (ISLONGLONG(p->n_left->n_type)) {
+                       /* XXX */
+                       r = xbcon(0x8000000000000000ULL, NULL, LONGLONG);
+               } else
+                       r = xbcon(0400000000000LL, NULL, INT);
+               p->n_left = buildtree(ER, p->n_left, r);
+               if (ISUNSIGNED(p->n_left->n_type))
+                       p->n_left->n_type = DEUNSIGN(p->n_left->n_type);
+
+               if (ISLONGLONG(p->n_right->n_type)) {
+                       /* XXX */
+                       r = xbcon(0x8000000000000000ULL, NULL, LONGLONG);
+               } else
+                       r = xbcon(0400000000000LL, NULL, INT);
+               p->n_right = buildtree(ER, p->n_right, r);
+               if (ISUNSIGNED(p->n_right->n_type))
+                       p->n_right->n_type = DEUNSIGN(p->n_right->n_type);
+
+               p->n_op -= (ULT-LT);
+               break;
+       case FCON:
+               cerror("fix float constants");
+       }
+}
+
+
+struct symtab *
+newfun(char *name, TWORD type)
+{
+       struct symtab *sp;
+
+       sp = lookup(name, 0);
+       if (sp->stype == VOID) {
+               sp->stype = INCREF(type | FTN);
+               sp->sclass = EXTERN;
+               sp->soffset = 0;
+       }
+#ifdef notdef
+       else if (!ISFTN(DECREF(sp->stype)))
+               uerror("reserved name '%s' used illegally", name);
+#endif
+       return sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ * Everything is trusted to be in register here.
+ */
+int
+cisreg(TWORD t)
+{
+       return(1);
+}
+
+int
+xptype(TWORD t)
+{
+       int tt = BTYPE(t);
+       int e, rv;
+
+       if (!ISPTR(t))
+               cerror("not a pointer");
+
+       e = t & ~BTMASK;
+       rv = e;
+       while (e) {
+               rv = e;
+               if (DECREF(e) == 0)
+                       break;
+               e = DECREF(e);
+       }
+       if (ISFTN(rv))
+               return PTRNORMAL;
+
+       switch (tt) {
+       case INT:
+       case LONG:
+       case LONGLONG:
+       case FLOAT:
+       case DOUBLE:
+       case STRTY:
+       case UNIONTY:
+       case UNSIGNED:
+       case ULONG:
+       case ULONGLONG:
+               return PTRNORMAL;
+       case VOID:
+       case CHAR:
+       case UCHAR:
+               if (DECREF(t) == tt || ISARY(rv))
+                       return PTRCHAR;
+               return PTRNORMAL;
+       case SHORT:
+       case USHORT:
+               if (DECREF(t) == tt || ISARY(rv))
+                       return PTRSHORT;
+               return PTRNORMAL;
+       default:
+               break;
+       }
+       cerror("unknown type");
+       return PTRNORMAL; /* XXX */
+}
+
+/*
+ * Help routine to the one below; return true if it's not a word pointer.
+ */
+static int
+pointp(TWORD t)
+{
+       int rv = 0;
+
+       if (ISPTR(t) && ((t & TMASK1) == 0))
+               return 1;
+
+       t &= ~BTMASK;
+       while (t) {
+               rv = ISARY(t);
+               t = DECREF(t);
+       }
+       return rv;
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+       register NODE *p;
+
+       if (xdebug)
+               printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+                   off, t, d, sue->suesize);
+
+       p = bcon(0);
+       p->n_lval = off/SZINT;  /* Default */
+       if (ISPTR(DECREF(t)))
+               return p;       /* Pointer/pointer reference */
+       switch (BTMASK & t) {
+       case INT:
+       case UNSIGNED:
+       case LONG:
+       case ULONG:
+       case STRTY:
+       case UNIONTY:
+       case LONGLONG:
+       case ULONGLONG:
+       case FLOAT:
+       case DOUBLE:
+               break;
+
+       case SHORT:
+       case USHORT:
+               if (pointp(t))
+                       p->n_lval = off/SZSHORT;
+               break;
+
+       case VOID: /* void pointers */
+       case CHAR:
+       case UCHAR:
+               if (pointp(t))
+                       p->n_lval = off/SZCHAR;
+               break;
+
+       default:
+               cerror("offcon, off %llo size %d type %x", off, sue->suesize, t);
+       }
+       if (xdebug)
+               printf("offcon return 0%llo\n", p->n_lval);
+       return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ * Be aware that a pointer conversion may be needed when saving 
+ * to node t!
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       if ((off % SZINT) == 0)
+               p =  buildtree(MUL, p, bcon(off/SZINT));
+       else if ((off % SZSHORT) == 0) {
+               p = buildtree(MUL, p, bcon(off/SZSHORT));
+               p = buildtree(PLUS, p, bcon(1));
+               p = buildtree(RS, p, bcon(1));
+       } else if ((off % SZCHAR) == 0) {
+               p = buildtree(MUL, p, bcon(off/SZCHAR));
+               p = buildtree(PLUS, p, bcon(3));
+               p = buildtree(RS, p, bcon(2));
+       } else
+               cerror("roundsp");
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       /* Cast sp to destination type (may be redundant) */
+       sp = buildtree(CAST,
+           block(NAME, NIL, NIL, t->n_type, t->n_df, t->n_sue), sp);
+       nfree(sp->n_left);
+       nfree(sp);
+       sp = sp->n_right;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+       /* add the size to sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+#if 0
+static int inwd;       /* current bit offsed in word */
+static CONSZ word;     /* word being built from fields */
+
+/*
+ * Generate initialization code for assigning a constant c
+ * to a field of width sz
+ * we assume that the proper alignment has been obtained
+ * inoff is updated to have the proper final value
+ * we also assume sz  < SZINT
+ */
+void
+incode(NODE *p, int sz)
+{
+       char *s;
+
+       inoff += sz;
+       if ((sz + inwd) > SZINT)
+               cerror("incode: field > int");
+
+       word |= ((p->n_lval & ((1 << sz) - 1)) << (36 - inwd - sz));
+
+       inwd += sz;
+       if (inoff % SZINT == 0) {
+               s = isinlining ? permalloc(30) : tmpalloc(30);
+               sprintf(s, "\t.long 0%llo\n", word);
+               send_passt(IP_ASM, s);
+               word = inwd = 0;
+       }
+       tfree(p);
+}
+
+/* output code to initialize space of size sz to the value d */
+/* the proper alignment has been obtained */
+/* inoff is updated to have the proper final value */
+/* on the target machine, write it out in octal! */
+void
+fincode(NODE *p, int sz)
+{
+       double d = p->n_dcon;
+
+       if(!nerrors)
+               printf("        %s      0%c%.20e\n",
+                   sz == SZDOUBLE ? ".double" : ".float",
+               sz == SZDOUBLE ? 'd' : 'f', d);
+       inoff += sz;
+}
+
+void
+cinit(NODE *p, int sz)
+{
+       NODE *l;
+
+       /*
+        * as a favor (?) to people who want to write
+        *     int i = 9600/134.5;
+        * we will, under the proper circumstances, do
+        * a coercion here.
+        */
+       switch (p->n_type) {
+       case INT:
+       case UNSIGNED:
+               l = p->n_left;
+               if (l->n_op != SCONV || l->n_left->n_op != FCON)
+                       break;
+               nfree(l);
+               l = l->n_left;
+               l->n_lval = (long)(l->n_dcon);
+               l->n_sp = NULL;
+               l->n_op = ICON;
+               l->n_type = INT;
+               p->n_left = l;
+               break;
+       }
+       /* arrange for the initialization of p into a space of size sz */
+       /* the proper alignment has been opbtained */
+       /* inoff is updated to have the proper final value */
+       ecode( p );
+       inoff += sz;
+}
+
+/*
+ * define n bits of zeros in a vfd
+ */
+void
+vfdzero(int n)
+{
+       char *s;
+
+       inoff += n;
+       inwd += n;
+       if (inoff%ALINT ==0) {
+               s = isinlining ? permalloc(30) : tmpalloc(30);
+               sprintf(s, "\t.long 0%llo\n", word);
+               send_passt(IP_ASM, s);
+               word = inwd = 0;
+       }
+}
+#endif
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+       if (p == NULL)
+               return "";
+       return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+               break;
+       case LDOUBLE:
+               MODTYPE(type,DOUBLE);
+               break;
+       }
+       return (type);
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the stroage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+       return(EXTERN);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off;
+       off = tsize(sp->stype, sp->sdf, sp->ssue);
+       off = (off+(SZINT-1))/SZINT;
+       printf("        .%scomm ", sp->sclass == STATIC ? "l" : "");
+       if (sp->slevel == 0)
+               printf("%s,0%o\n", exname(sp->soname), off);
+       else
+               printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+       cerror("zbits");
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+//     if (idebug)
+//             printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+//                 off, fsz, val, inbits);
+       cerror("infld");
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       cerror("ninval");
+}
+
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+
diff --git a/lang/pcc/pcc/arch/pdp10/local2.c b/lang/pcc/pcc/arch/pdp10/local2.c
new file mode 100644 (file)
index 0000000..e5a2cde
--- /dev/null
@@ -0,0 +1,1321 @@
+/*     $Id: local2.c,v 1.106 2015/01/04 19:17:23 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+
+void acon(FILE *, NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+
+static int offlab;
+int offarg;
+static int addto;
+static int regoff[16];
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int i, j;
+
+       if (ipp->ipp_vis)
+               printf("        .globl %s\n", ipp->ipp_name);
+       printf("%s:\n", ipp->ipp_name);
+       addto = p2maxautooff;
+       if (addto >= AUTOINIT/SZCHAR)
+               addto -= AUTOINIT/SZCHAR;
+       addto /= SZINT/SZCHAR;  /* use words here */
+       printf("        push %s,%s\n",rnames[STKREG], rnames[FPREG]);
+       printf("        move %s,%s\n", rnames[FPREG],rnames[STKREG]);
+
+       for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
+               if (i & 1)
+                       regoff[j] = addto++;
+       }
+       if (addto)
+               printf("        addi %s,0%o\n", rnames[STKREG], addto);
+
+       for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
+               if (i & 1)
+                       printf("        movem %s,%d(%s)\n",
+                           rnames[j], regoff[j], rnames[STKREG]);
+       }
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       int i, j;
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+       for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
+               if (i & 1)
+                       printf("        move %s,%d(%s)\n",
+                           rnames[j], regoff[j], rnames[STKREG]);
+       }
+       printf("        move %s,%s\n", rnames[STKREG], rnames[FPREG]);
+       printf("        pop %s,%s\n", rnames[STKREG], rnames[FPREG]);
+       printf("        popj %s,\n", rnames[STKREG]);
+}
+
+#if 0
+void
+prologue(int regs, int autos)
+{
+       int i, addto;
+
+       offlab = getlab2();
+       if (regs < 0 || autos < 0) {
+               /*
+                * non-optimized code, jump to epilogue for code generation.
+                */
+               ftlab1 = getlab2();
+               ftlab2 = getlab2();
+               printf("        jrst L%d\n", ftlab1);
+               printf("L%d:\n", ftlab2);
+       } else {
+               /*
+                * We here know what register to save and how much to 
+                * add to the stack.
+                */
+               autos = autos + (SZINT-1);
+               addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs);
+               if (addto || gflag) {
+                       printf("        push %s,%s\n",rnames[017], rnames[016]);
+                       printf("        move %s,%s\n", rnames[016],rnames[017]);
+                       for (i = regs; i < MAXRVAR; i++) {
+                               int db = ((i+1) < MAXRVAR);
+                               printf("        %smovem %s,0%o(%s)\n",
+                                   db ? "d" : "",
+                                   rnames[i+1], i+1-regs, rnames[016]);
+                               if (db)
+                                       i++;
+                       }
+                       if (addto)
+                               printf("        addi %s,0%o\n", rnames[017], addto);
+               } else
+                       offarg = 1;
+       }
+}
+
+/*
+ * End of block.
+ */
+void
+eoftn(int regs, int autos, int retlab)
+{
+       register OFFSZ spoff;   /* offset from stack pointer */
+       int i;
+
+       spoff = autos + (SZINT-1);
+       if (spoff >= AUTOINIT)
+               spoff -= AUTOINIT;
+       spoff /= SZINT;
+       /* return from function code */
+       printf("L%d:\n", retlab);
+       if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) {
+               for (i = regs; i < MAXRVAR; i++) {
+                       int db = ((i+1) < MAXRVAR);
+                       printf("        %smove %s,0%o(%s)\n", db ? "d" : "",
+                           rnames[i+1], i+1-regs, rnames[016]);
+                       if (db)
+                               i++;
+               }
+               printf("        move %s,%s\n", rnames[017], rnames[016]);
+               printf("        pop %s,%s\n", rnames[017], rnames[016]);
+       }
+       printf("        popj %s,\n", rnames[017]);
+
+       /* Prolog code */
+       if (isoptim == 0) {
+               printf("L%d:\n", ftlab1);
+               printf("        push %s,%s\n", rnames[017], rnames[016]);
+               printf("        move %s,%s\n", rnames[016], rnames[017]);
+               for (i = regs; i < MAXRVAR; i++) {
+                       int db = ((i+1) < MAXRVAR);
+                       printf("        %smovem %s,0%o(%s)\n", db ? "d" : "",
+                           rnames[i+1], i+1-regs, rnames[016]);
+                       spoff++;
+                       if (db)
+                               i++, spoff++;
+               }
+               if (spoff)
+                       printf("        addi %s,0%llo\n", rnames[017], spoff);
+               printf("        jrst L%d\n", ftlab2);
+       }
+       printf("        .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs);
+       offarg = isoptim = 0;
+}
+#endif
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ *     R - Register
+ *     M - Memory
+ *     C - Constant
+ */
+void
+hopcode(int f, int o)
+{
+       cerror("hopcode: f %d %d", f, o);
+}
+
+char *
+rnames[] = {  /* keyed to register number tokens */
+       "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
+       "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
+       "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
+       "%10", "%11", "%12", "%13", "%14", "%15",
+};
+
+int
+tlen(p) NODE *p;
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               cerror("tlen type %d not pointer");
+                       return SZPOINT(0)/SZCHAR;
+               }
+}
+
+static char *
+binskip[] = {
+       "e",    /* jumpe */
+       "n",    /* jumpn */
+       "le",   /* jumple */
+       "l",    /* jumpl */
+       "ge",   /* jumpge */
+       "g",    /* jumpg */
+};
+
+/*
+ * Extract the higher 36 bits from a longlong.
+ */
+static CONSZ
+gethval(CONSZ lval)
+{
+       CONSZ hval = (lval >> 35) & 03777777777LL;
+
+       if ((hval & 03000000000LL) == 03000000000LL) {
+               hval |= 0777000000000LL;
+       } else if ((hval & 03000000000LL) == 02000000000LL) {
+               hval &= 01777777777LL;
+               hval |= 0400000000000LL;
+       }
+       return hval;
+}
+
+/*
+ * Do a binary comparision, and jump accordingly.
+ */
+static void
+twocomp(NODE *p)
+{
+       int o = p->n_op;
+       extern int negrel[];
+       int isscon = 0, iscon = p->n_right->n_op == ICON;
+
+       if (o < EQ || o > GT)
+               cerror("bad binary conditional branch: %s", opst[o]);
+
+       if (iscon && p->n_right->n_name[0] != 0) {
+               printf("        cam%s ", binskip[negrel[o-EQ]-EQ]);
+               adrput(stdout, getlr(p, 'L'));
+               putchar(',');
+               printf("[ .long ");
+               adrput(stdout, getlr(p, 'R'));
+               putchar(']');
+               printf("\n      jrst L%d\n", p->n_label);
+               return;
+       }
+       if (iscon)
+               isscon = p->n_right->n_lval >= 0 &&
+                   p->n_right->n_lval < 01000000;
+
+       printf("        ca%c%s ", iscon && isscon ? 'i' : 'm',
+           binskip[negrel[o-EQ]-EQ]);
+       adrput(stdout, getlr(p, 'L'));
+       putchar(',');
+       if (iscon && (isscon == 0)) {
+               printf("[ .long ");
+               adrput(stdout, getlr(p, 'R'));
+               putchar(']');
+       } else
+               adrput(stdout, getlr(p, 'R'));
+       printf("\n      jrst L%d\n", p->n_label);
+}
+
+/*
+ * Compare byte/word pointers.
+ * XXX - do not work for highest bit set in address
+ */
+static void
+ptrcomp(NODE *p)
+{
+       printf("        rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n");
+       printf("        rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n");
+       twocomp(p);
+}
+
+/*
+ * Do a binary comparision of two long long, and jump accordingly.
+ * XXX - can optimize for constants.
+ */
+static void     
+twollcomp(NODE *p)
+{       
+       int o = p->n_op;
+       int iscon = p->n_right->n_op == ICON;
+       int m = 0; /* XXX gcc */
+
+       if (o < EQ || o > GT)
+               cerror("bad long long conditional branch: %s", opst[o]);
+
+       /* Special strategy for equal/not equal */
+       if (o == EQ || o == NE) {
+               if (o == EQ)
+                       m = getlab2();
+               printf("        came ");
+               upput(getlr(p, 'L'), SZLONG);
+               putchar(',');
+               if (iscon)
+                       printf("[ .long ");
+               upput(getlr(p, 'R'), SZLONG);
+               if (iscon)
+                       putchar(']');
+               printf("\n      jrst L%d\n", o == EQ ? m : p->n_label);
+               printf("        cam%c ", o == EQ ? 'n' : 'e');
+               adrput(stdout, getlr(p, 'L'));
+               putchar(',');
+               if (iscon)
+                       printf("[ .long ");
+               adrput(stdout, getlr(p, 'R'));
+               if (iscon)
+                       putchar(']');
+               printf("\n      jrst L%d\n", p->n_label);
+               if (o == EQ)
+                       printf("L%d:\n", m);
+               return;
+       }
+       /* First test highword */
+       printf("        cam%ce ", o == GT || o == GE ? 'l' : 'g');
+       adrput(stdout, getlr(p, 'L'));
+       putchar(',');
+       if (iscon)
+               printf("[ .long ");
+       adrput(stdout, getlr(p, 'R'));
+       if (iscon)
+               putchar(']');
+       printf("\n      jrst L%d\n", p->n_label);
+
+       /* Test equality */
+       printf("        came ");
+       adrput(stdout, getlr(p, 'L'));
+       putchar(',');
+       if (iscon)
+               printf("[ .long ");
+       adrput(stdout, getlr(p, 'R'));
+       if (iscon)
+               putchar(']');
+       printf("\n      jrst L%d\n", m = getlab2());
+
+       /* Test lowword. Only works with pdp10 format for longlongs */
+       printf("        cam%c%c ", o == GT || o == GE ? 'l' : 'g',
+           o == LT || o == GT ? 'e' : ' ');
+       upput(getlr(p, 'L'), SZLONG);
+       putchar(',');
+       if (iscon)  
+               printf("[ .long ");
+       upput(getlr(p, 'R'), SZLONG);
+       if (iscon)
+               putchar(']');
+       printf("\n      jrst L%d\n", p->n_label);
+       printf("L%d:\n", m);
+}
+
+/*
+ * Print the correct instruction for constants.
+ */
+static void
+constput(NODE *p)
+{
+       CONSZ val = p->n_right->n_lval;
+       int reg = p->n_left->n_rval;
+
+       /* Only numeric constant */
+       if (p->n_right->n_name[0] == '\0') {
+               if (val == 0) {
+                       printf("movei %s,0", rnames[reg]);
+               } else if ((val & 0777777000000LL) == 0) {
+                       printf("movei %s,0%llo", rnames[reg], val);
+               } else if ((val & 0777777) == 0) {
+                       printf("hrlzi %s,0%llo", rnames[reg], val >> 18);
+               } else {
+                       printf("move %s,[ .long 0%llo]", rnames[reg],
+                           szty(p->n_right->n_type) > 1 ? val :
+                           val & 0777777777777LL);
+               }
+               /* Can have more tests here, hrloi etc */
+               return;
+       } else {
+               printf("xmovei %s,%s", rnames[reg], p->n_right->n_name);
+               if (val)
+                       printf("+" CONFMT, val);
+       }
+}
+
+/*
+ * Return true if the constant can be bundled in an instruction (immediate).
+ */
+static int
+oneinstr(NODE *p)
+{
+       if (p->n_name[0] != '\0')
+               return 0;
+       if ((p->n_lval & 0777777000000ULL) != 0)
+               return 0;
+       return 1;
+}
+
+/*
+ * Emit a halfword or byte instruction, from OREG to REG.
+ * Sign extension must also be done here.
+ */
+static void
+emitshort(NODE *p)
+{
+       CONSZ off = p->n_lval;
+       TWORD type = p->n_type;
+       int reg = p->n_rval;
+       int issigned = !ISUNSIGNED(type);
+       int ischar = type == CHAR || type == UCHAR;
+       int reg1 = getlr(p, '1')->n_rval;
+
+       if (off < 0) { /* argument, use move instead */
+               printf("        move ");
+       } else if (off == 0 && p->n_name[0] == 0) {
+               printf("        ldb %s,%s\n", rnames[reg1], rnames[reg]);
+               /* XXX must sign extend here even if not necessary */
+               switch (type) {
+               case CHAR:
+                       printf("        lsh %s,033\n", rnames[reg1]);
+                       printf("        ash %s,-033\n", rnames[reg1]);
+                       break;
+               case SHORT:
+                       printf("        hrre %s,%s\n",
+                           rnames[reg1], rnames[reg1]);
+                       break;
+               }
+               return;
+       } else if (ischar) {
+               if (off >= 0700000000000LL && p->n_name[0] != '\0') {
+                       cerror("emitsh");
+                       /* reg contains index integer */
+//                     if (!istreg(reg))
+//                             cerror("emitshort !istreg");
+                       printf("        adjbp %s,[ .long 0%llo+%s ]\n",
+                           rnames[reg], off, p->n_name);
+                       printf("        ldb ");
+                       adrput(stdout, getlr(p, '1'));
+                       printf(",%s\n", rnames[reg]);
+                       goto signe;
+               }
+               printf("        ldb ");
+               adrput(stdout, getlr(p, '1'));
+               if (off)
+                       printf(",[ .long 0%02o11%02o%06o ]\n",
+                           (int)(27-(9*(off&3))), reg, (int)off/4);
+               else
+                       printf(",%s\n", rnames[reg]);
+signe:         if (issigned) {
+                       printf("        lsh ");
+                       adrput(stdout, getlr(p, '1'));
+                       printf(",033\n  ash ");
+                       adrput(stdout, getlr(p, '1'));
+                       printf(",-033\n");
+               }
+               return;
+       } else {
+               printf("        h%cr%c ", off & 1 ? 'r' : 'l',
+                   issigned ? 'e' : 'z');
+       }
+       p->n_lval /= (ischar ? 4 : 2);
+       adrput(stdout, getlr(p, '1'));
+       putchar(',');
+       adrput(stdout, getlr(p, 'L'));
+       putchar('\n');
+}
+
+/*
+ * Store a short from a register. Destination is a OREG.
+ */
+static void
+storeshort(NODE *p)
+{
+       NODE *l = p->n_left;
+       CONSZ off = l->n_lval;
+       int reg = l->n_rval;
+       int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR;
+
+       if (l->n_op == NAME) {
+               if (ischar) {
+                       printf("        dpb ");
+                       adrput(stdout, getlr(p, 'R'));
+                       printf(",[ .long 0%02o%010o+%s ]\n",
+                           070+((int)off&3), (int)(off/4), l->n_name);
+                       return;
+               }
+               printf("        hr%cm ", off & 1 ? 'r' : 'l');
+               l->n_lval /= 2;
+               adrput(stdout, getlr(p, 'R'));
+               putchar(',');   
+               adrput(stdout, getlr(p, 'L'));
+               putchar('\n');
+               return;
+       }
+
+       if (off || reg == FPREG) { /* Can emit halfword instructions */
+               if (off < 0) { /* argument, use move instead */
+                       printf("        movem ");
+               } else if (ischar) {
+                       printf("        dpb ");
+                       adrput(stdout, getlr(p, '1'));
+                       printf(",[ .long 0%02o11%02o%06o ]\n",
+                           (int)(27-(9*(off&3))), reg, (int)off/4);
+                       return;
+               } else {
+                       printf("        hr%cm ", off & 1 ? 'r' : 'l');
+               }
+               l->n_lval /= 2;
+               adrput(stdout, getlr(p, 'R'));
+               putchar(',');
+               adrput(stdout, getlr(p, 'L'));
+       } else {
+               printf("        dpb ");
+               adrput(stdout, getlr(p, 'R'));
+               putchar(',');
+               l = getlr(p, 'L');
+               l->n_op = REG;
+               adrput(stdout, l);
+               l->n_op = OREG;
+       }
+       putchar('\n');
+}
+
+/*
+ * Multiply a register with a constant.
+ */
+static void     
+imuli(NODE *p)
+{
+       NODE *r = p->n_right;
+
+       if (r->n_lval >= 0 && r->n_lval <= 0777777) {
+               printf("        imuli ");
+               adrput(stdout, getlr(p, 'L'));
+               printf(",0%llo\n", r->n_lval);
+       } else {
+               printf("        imul ");
+               adrput(stdout, getlr(p, 'L'));
+               printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
+       }
+}
+
+/*
+ * Divide a register with a constant.
+ */
+static void     
+idivi(NODE *p)
+{
+       NODE *r = p->n_right;
+
+       if (r->n_lval >= 0 && r->n_lval <= 0777777) {
+               printf("        idivi ");
+               adrput(stdout, getlr(p, '1'));
+               printf(",0%llo\n", r->n_lval);
+       } else {
+               printf("        idiv ");
+               adrput(stdout, getlr(p, '1'));
+               printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
+       }
+}
+
+/*
+ * move a constant into a register.
+ */
+static void
+xmovei(NODE *p)
+{
+       /*
+        * Trick: If this is an unnamed constant, just move it directly,
+        * otherwise use xmovei to get section number.
+        */
+       if (p->n_name[0] == '\0' || p->n_lval > 0777777) {
+               printf("        ");
+               zzzcode(p, 'D');
+               putchar(' ');
+               adrput(stdout, getlr(p, '1'));
+               putchar(',');
+               zzzcode(p, 'E');
+       } else {
+               printf("        xmovei ");
+               adrput(stdout, getlr(p, '1'));
+               printf(",%s", p->n_name);
+               if (p->n_lval != 0)
+                       printf("+0%llo", p->n_lval);
+       }
+       putchar('\n');
+}
+
+static void
+printcon(NODE *p) 
+{
+       CONSZ cz;
+
+       p = p->n_left;
+       if (p->n_lval >= 0700000000000LL) {
+               /* converted to pointer in clocal() */
+               conput(stdout, p);
+               return;
+       }
+       if (p->n_lval == 0 && p->n_name[0] == '\0') {
+               putchar('0');
+               return;
+       }
+       if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR)
+               cz = (p->n_lval/4) | ((p->n_lval & 3) << 30);
+       else
+               cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30);
+       cz |= 0700000000000LL;
+       printf("0%llo", cz);
+       if (p->n_name[0] != '\0')
+               printf("+%s", p->n_name);
+}
+
+static void
+putcond(NODE *p)
+{               
+       char *c = 0; /* XXX gcc */
+
+       switch (p->n_op) {
+       case EQ: c = "e"; break;
+       case NE: c = "n"; break;
+       case LE: c = "le"; break;
+       case LT: c = "l"; break;
+       case GT: c = "g"; break;
+       case GE: c = "ge"; break;
+       default:
+               cerror("putcond");
+       }
+       printf("%s", c);
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       NODE *l;
+       CONSZ hval;
+
+       switch (c) {
+       case 'A': /* ildb right arg */
+               adrput(stdout, p->n_left->n_left);
+               break;
+
+       case 'B': /* remove from stack after subroutine call */
+               if (p->n_qual)
+                       printf("        subi %%17,0%o\n", p->n_qual);
+               break;
+
+       case 'C':
+               constput(p);
+               break;
+
+       case 'D': /* Find out which type of const load insn to use */
+               if (p->n_op != ICON)
+                       cerror("zzzcode not ICON");
+               if (p->n_name[0] == '\0') {
+                       if ((p->n_lval <= 0777777) && (p->n_lval > 0))
+                               printf("movei");
+                       else if ((p->n_lval & 0777777) == 0)
+                               printf("hrlzi");
+                       else
+                               printf("move");
+               } else
+                       printf("move");
+               break;
+
+       case 'E': /* Print correct constant expression */
+               if (p->n_name[0] == '\0') {
+                       if ((p->n_lval <= 0777777) && (p->n_lval > 0)){
+                               printf("0%llo", p->n_lval);
+                       } else if ((p->n_lval & 0777777) == 0) {
+                               printf("0%llo", p->n_lval >> 18);
+                       } else {
+                               if (p->n_lval < 0)
+                                       printf("[ .long -0%llo]", -p->n_lval);
+                               else
+                                       printf("[ .long 0%llo]", p->n_lval);
+                       }
+               } else {
+                       if (p->n_lval == 0)
+                               printf("[ .long %s]", p->n_name);
+                       else
+                               printf("[ .long %s+0%llo]",
+                                   p->n_name, p->n_lval);
+               }
+               break;
+
+       case 'G': /* structure argument */
+               printf("        addl %%17,0%o\n",
+                   attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR));
+               printf("        foo...\n");
+               break;
+
+       case 'P':
+               p = getlr(p, 'R');
+               /* FALLTHROUGH */
+       case 'O':
+               /*
+                * Print long long expression.
+                */
+               hval = gethval(p->n_lval);
+               printf("[ .long 0%llo,0%llo", hval,
+                   (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL));
+               if (p->n_name[0] != '\0')
+                       printf("+%s", p->n_name);
+               printf(" ]");
+               break;
+
+       case 'F': /* Print an "opsimp" instruction based on its const type */
+               hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op);
+               break;
+
+       case 'H': /* Print a small constant */
+               p = p->n_right;
+               printf("0%llo", p->n_lval & 0777777);
+               break;
+
+       case 'Q': /* two-param long long comparisions */
+               twollcomp(p);
+               break;
+
+       case 'R': /* two-param conditionals */
+               twocomp(p);
+               break;
+
+       case 'U':
+               emitshort(p);
+               break;
+               
+       case 'V':
+               storeshort(p);
+               break;
+
+       case 'Z':
+               ptrcomp(p);
+               break;
+
+       case 'a':
+               imuli(p);
+               break;
+
+       case 'b':
+               idivi(p);
+               break;
+
+       case 'c':
+               xmovei(p);
+               break;
+
+       case 'd':
+               printcon(p);
+               break;
+
+       case 'e':
+               putcond(p);
+               break;
+
+       case 'g':
+               if (p->n_right->n_op != OREG || p->n_right->n_lval != 0)
+                       comperr("bad Zg oreg");
+               printf("%s", rnames[p->n_right->n_rval]);
+               break;
+
+#if 0
+       case '1': /* double upput */
+               p = getlr(p, '1');
+               p->n_rval += 2;
+               adrput(stdout, p);
+               p->n_rval -= 2;
+               break;
+#endif
+
+       case 'i': /* Write instruction for short load from name */
+               l = getlr(p, 'L');
+               printf("        h%cr%c %s,%s+" CONFMT "\n",
+                   l->n_lval & 1 ? 'r' : 'l',
+                   ISUNSIGNED(p->n_type) ? 'z' : 'e',
+                   rnames[getlr(p, '1')->n_rval],
+                   l->n_name, l->n_lval >> 1);
+               break;
+
+       default:
+               cerror("zzzcode %c", c);
+       }
+}
+
+/* set up temporary registers */
+void
+setregs(void)
+{
+       fregs = 7;      /* 7 free regs on PDP10 (1-7) */
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       return 0;
+}
+
+int
+flshape(NODE *p)
+{
+       register int o = p->n_op;
+
+       return (o == REG || o == NAME || o == ICON ||
+               (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)));
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+int
+shtemp(NODE *p)
+{
+       return(0);
+}
+
+int
+shumul(NODE *p, int order)
+{
+       register int o;
+
+       if (x2debug) {
+               int val;
+               printf("shumul(%p)\n", p);
+               eprint(p, 0, &val, &val);
+       }
+
+       o = p->n_op;
+#if 0
+       if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON)
+               return(STARNM);
+#endif
+
+#if 0
+       if ((o == INCR) &&
+           (p->n_left->n_op == REG && p->n_right->n_op == ICON) &&
+           p->n_right->n_name[0] == '\0') {
+               switch (p->n_type) {
+                       case CHAR|PTR:
+                       case UCHAR|PTR:
+                               o = 1;
+                               break;
+
+                       case SHORT|PTR:
+                       case USHORT|PTR:
+                               o = 2;
+                               break;
+
+                       case INT|PTR:
+                       case UNSIGNED|PTR:
+                       case LONG|PTR:
+                       case ULONG|PTR:
+                       case FLOAT|PTR:
+                               o = 4;
+                               break;
+
+                       case DOUBLE|PTR:
+                       case LONGLONG|PTR:
+                       case ULONGLONG|PTR:
+                               o = 8;
+                               break;
+
+                       default:
+                               if (ISPTR(p->n_type) &&
+                                    ISPTR(DECREF(p->n_type))) {
+                                       o = 4;
+                                       break;
+                               } else
+                                       return(0);
+               }
+               return( 0);
+       }
+#endif
+       return( SRNOPE );
+}
+
+void
+adrcon(CONSZ val)
+{
+       cerror("adrcon: val %llo\n", val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_lval != 0) {
+                       acon(fp, p);
+                       if (p->n_name[0] != '\0')
+                               fputc('+', fp);
+               }
+               if (p->n_name[0] != '\0')
+                       fprintf(fp, "%s", p->n_name);
+               if (p->n_name[0] == '\0' && p->n_lval == 0)
+                       fputc('0', fp);
+               return;
+
+       case REG:
+               fprintf(fp, "%s", rnames[p->n_rval]);
+               return;
+
+       default:
+               cerror("illegal conput");
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       cerror("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZLONG;
+       switch (p->n_op) {
+       case REG:
+               printf("%s", rnames[p->n_rval + size]);
+               break;
+
+       case NAME:
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+       case ICON:
+               printf(CONFMT, p->n_lval >> (36 * size));
+               break;
+       default:
+               cerror("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *fp, NODE *p)
+{
+       int r;
+       /* output an address, with offsets, from p */
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0')
+                       fputs(p->n_name, fp);
+               if (p->n_lval != 0)
+                       fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL);
+               return;
+
+       case OREG:
+               r = p->n_rval;
+#if 0
+               if (R2TEST(r)) { /* double indexing */
+                       register int flags;
+
+                       flags = R2UPK3(r);
+                       if (flags & 1)
+                               putc('*', fp);
+                       if (flags & 4)
+                               putc('-', fp);
+                       if (p->n_lval != 0 || p->n_name[0] != '\0')
+                               acon(p);
+                       if (R2UPK1(r) != 100)
+                               printf("(%s)", rnames[R2UPK1(r)]);
+                       if (flags & 2)
+                               putchar('+');
+                       printf("[%s]", rnames[R2UPK2(r)]);
+                       return;
+               }
+#endif
+               if (R2TEST(r))
+                       cerror("adrput: unwanted double indexing: r %o", r);
+               if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) {
+                       fprintf(fp, "%s", p->n_name);
+                       acon(fp, p);
+                       fprintf(fp, "(%s)", rnames[p->n_rval]);
+                       return;
+               }
+               if (p->n_lval < 0 && p->n_rval == FPREG && offarg) {
+                       p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2;
+               } else if (p->n_lval != 0)
+                       acon(fp, p);
+               if (p->n_name[0] != '\0')
+                       fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name);
+               if (p->n_lval > 0 && p->n_rval == FPREG && offlab)
+                       fprintf(fp, "+" LABFMT, offlab);
+               if (p->n_lval < 0 && p->n_rval == FPREG && offarg)
+                       fprintf(fp, "(017)");
+               else
+                       fprintf(fp, "(%s)", rnames[p->n_rval]);
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               if (p->n_lval > 0) {
+                       acon(fp, p);
+                       if (p->n_name[0] != '\0')
+                               putc('+', fp);
+               }
+               if (p->n_name[0] != '\0')
+                       fprintf(fp, "%s", p->n_name);
+               if (p->n_lval < 0) 
+                       acon(fp, p);
+               if (p->n_name[0] == '\0' && p->n_lval == 0)
+                       putc('0', fp);
+               return;
+
+       case REG:
+               fputs(rnames[p->n_rval], fp);
+               return;
+
+       default:
+               cerror("illegal address, op %d", p->n_op);
+               return;
+
+       }
+}
+
+/*
+ * print out a constant
+ */
+void
+acon(FILE *fp, NODE *p)
+{
+       if (p->n_lval < 0 && p->n_lval > -0777777777777ULL)
+               fprintf(fp, "-" CONFMT, -p->n_lval);
+       else
+               fprintf(fp, CONFMT, p->n_lval);
+}
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o,int lab)
+{
+}
+
+/*
+ * Do some local optimizations that must be done after optim is called.
+ */
+static void
+optim2(NODE *p, void *arg)
+{
+       int op = p->n_op;
+       int m, ml;
+       NODE *l;
+
+       /* Remove redundant PCONV's */
+       if (op == PCONV) {
+               l = p->n_left;
+               m = BTYPE(p->n_type);
+               ml = BTYPE(l->n_type);
+               if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT ||
+                   m == DOUBLE || m == STRTY || m == UNIONTY ||
+                   m == UNSIGNED || m == ULONG || m == ULONGLONG) &&
+                   (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT ||
+                   ml == DOUBLE || ml == STRTY || ml == UNIONTY || 
+                   ml == UNSIGNED || ml == ULONG ||
+                   ml == ULONGLONG) && ISPTR(l->n_type)) {
+                       *p = *l;
+                       nfree(l);
+                       op = p->n_op;
+               } else
+               if (ISPTR(DECREF(p->n_type)) &&
+                   (l->n_type == INCREF(STRTY))) {
+                       *p = *l;
+                       nfree(l);
+                       op = p->n_op;
+               } else
+               if (ISPTR(DECREF(l->n_type)) &&
+                   (p->n_type == INCREF(INT) ||
+                   p->n_type == INCREF(STRTY) ||
+                   p->n_type == INCREF(UNSIGNED))) {
+                       *p = *l;
+                       nfree(l);
+                       op = p->n_op;
+               }
+
+       }
+       /* Add constands, similar to the one in optim() */
+       if (op == PLUS && p->n_right->n_op == ICON) {
+               l = p->n_left;
+               if (l->n_op == PLUS && l->n_right->n_op == ICON &&
+                   (p->n_right->n_name[0] == '\0' ||
+                    l->n_right->n_name[0] == '\0')) {
+                       l->n_right->n_lval += p->n_right->n_lval;
+                       if (l->n_right->n_name[0] == '\0')
+                               l->n_right->n_name = p->n_right->n_name;
+                       nfree(p->n_right);
+                       *p = *l;
+                       nfree(l);
+               }
+       }
+
+       /* Convert "PTR undef" (void *) to "PTR uchar" */
+       /* XXX - should be done in MI code */
+       if (BTYPE(p->n_type) == VOID)
+               p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+       if (op == ICON) {
+               if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR))
+                   && p->n_lval == 0 && p->n_name[0] != '\0')
+                       p->n_lval = 0700000000000LL;
+               if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT))
+                   && p->n_lval == 0 && p->n_name[0] != '\0')
+                       p->n_lval = 0750000000000LL;
+       }
+       if (op == MINUS) {
+               if ((p->n_left->n_type == (PTR|CHAR) ||
+                   p->n_left->n_type == (PTR|UCHAR)) &&
+                   (p->n_right->n_type == (PTR|CHAR) ||
+                   p->n_right->n_type == (PTR|UCHAR))) {
+                       l = talloc();
+                       l->n_op = SCONV;
+                       l->n_type = INT;
+                       l->n_left = p->n_right;
+                       p->n_right = l;
+                       l = talloc();
+                       l->n_op = SCONV;
+                       l->n_type = INT;
+                       l->n_left = p->n_left;
+                       p->n_left = l;
+               }
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, optim2, 0);
+       }
+
+       if (x2debug) {
+               printf("myreader final tree:\n");
+               printip(ipole);
+       }
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+/*
+ * Remove last goto.
+ */
+void
+myoptim(struct interpass *ip)
+{
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       return (szty(t) == 2 ? CLASSB : CLASSA);
+}
+
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (t == STRTY || t == UNIONTY)
+               return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR);
+       return szty(t);
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+        NODE *op = p;
+        int size = 0;
+
+        p->n_qual = 0;
+        if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+                return;
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               if (p->n_right->n_op != ASSIGN)
+                       size += argsiz(p->n_right);
+       if (p->n_op != ASSIGN)
+               size += argsiz(p);
+        op->n_qual = size; /* XXX */
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+       printf("        %smove %s,%s\n",
+           (s > 017 ? "d" : ""), rnames[d], rnames[s]);
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num;
+
+       switch (c) {
+       case CLASSA:
+               /* there are 13 classa, so min 6 classb are needed to block */
+               num = r[CLASSB] * 2;
+               num += r[CLASSA];
+               return num < 13;
+       case CLASSB:
+               /* 7 classa may block all classb */
+               num = r[CLASSB] + r[CLASSA];
+               return num < 7;
+       }
+       comperr("COLORMAP");
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/pdp10/macdefs.h b/lang/pcc/pcc/arch/pdp10/macdefs.h
new file mode 100644 (file)
index 0000000..cfaca35
--- /dev/null
@@ -0,0 +1,243 @@
+/*     $Id: macdefs.h,v 1.36 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise 
+ * treat it as an integer.
+ */
+#define makecc(val,i) {                        \
+       if (i == 0) { lastcon = val;    \
+       } else if (i == 1) { lastcon = (lastcon << 9) | val; lastcon <<= 18; \
+       } else { lastcon |= (val << (27 - (i * 9))); } }
+
+#define ARGINIT                36      /* # bits below fp where arguments start */
+#define AUTOINIT       36      /* # bits above fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         9
+#define SZBOOL         36
+#define SZINT          36
+#define SZFLOAT                36
+#define SZDOUBLE       72
+#define SZLDOUBLE      72
+#define SZLONG         36
+#define SZSHORT                18
+#define SZPOINT(x)     36
+#define SZLONGLONG     72
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         9
+#define ALBOOL         36
+#define ALINT          36
+#define ALFLOAT                36
+#define ALDOUBLE       36
+#define ALLDOUBLE      36
+#define ALLONG         36
+#define ALLONGLONG     36
+#define ALSHORT                18
+#define ALPOINT                36
+#define ALSTRUCT       36
+#define ALSTACK                36 
+
+/*
+ * Max values.
+ */
+#define        MIN_CHAR        -256
+#define        MAX_CHAR        255
+#define        MAX_UCHAR       511
+#define        MIN_SHORT       -131072
+#define        MAX_SHORT       131071
+#define        MAX_USHORT      262143
+#define        MIN_INT         (-0377777777777LL-1)
+#define        MAX_INT         0377777777777LL
+#define        MAX_UNSIGNED    0777777777777ULL
+#define        MIN_LONG        (-0377777777777LL-1)
+#define        MAX_LONG        0377777777777LL
+#define        MAX_ULONG       0777777777777ULL
+#define        MIN_LONGLONG    (000777777777777777777777LL-1)  /* XXX cross */
+#define        MAX_LONGLONG    000777777777777777777777LL      /* XXX cross */
+#define        MAX_ULONGLONG   001777777777777777777777ULL     /* XXX cross */
+
+/* Default char is unsigned */
+#define TARGET_STDARGS
+#define        CHAR_UNSIGNED
+#define        BOOL_TYPE       INT
+#define        WORD_ADDRESSED
+
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "0%llo"         /* format for printing constants */
+#define LABFMT ".L%d"          /* format for printing labels */
+#define STABLBL ".LL%d"                /* format for stab (debugging) labels */
+
+#undef BACKAUTO                /* stack grows negatively for automatics */
+#undef BACKTEMP                /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_BE
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)  gencall(a,b)
+
+#define        szty(t) (((t) == DOUBLE || (t) == FLOAT || \
+       (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+#define        shltype(o, p) \
+       ((o) == REG || (o) == NAME || (o) == ICON || \
+        (o) == OREG || ((o) == UMUL && shumul((p)->n_left, SOREG)))
+
+#undef SPECIAL_INTEGERS
+
+/*
+ * Special shapes used in code generation.
+ */
+#define        SUSHCON (SPECIAL|6)     /* unsigned short constant */
+#define        SNSHCON (SPECIAL|7)     /* negative short constant */
+#define        SILDB   (SPECIAL|8)     /* use ildb here */
+
+/*
+ * Register allocator definitions.
+ *
+ * The pdp10 has 16 general-purpose registers, but the two
+ * highest are used as sp and fp.  Register 0 has special 
+ * constraints in its possible use as index register.
+ * All regs can be used as pairs, named by the lowest number.
+ * In here we call the registers Rn and the pairs XRn, in assembler
+ * just its number prefixed with %.
+ * 
+ * R1/XR1 are return registers.
+ *
+ * R0 is currently not used.
+ */
+
+#define        MAXREGS         29 /* 16 + 13 regs */
+#define        NUMCLASS        2
+
+#define R0     00
+#define R1     01
+#define R2     02
+#define R3     03
+#define R4     04
+#define R5     05
+#define R6     06
+#define R7     07
+#define R10    010
+#define R11    011
+#define R12    012
+#define R13    013
+#define R14    014
+#define R15    015
+#define R16    016
+#define R17    017
+#define FPREG  R16             /* frame pointer */
+#define STKREG R17             /* stack pointer */
+
+
+#define XR0    020
+#define XR1    021
+#define XR2    022
+#define XR3    023
+#define XR4    024
+#define XR5    025
+#define XR6    026
+#define XR7    027
+#define XR10   030
+#define XR11   031
+#define XR12   032
+#define XR13   033
+#define XR14   034
+
+
+#define RSTATUS \
+       0, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,                 \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,     \
+       SAREG|PERMREG, SAREG|PERMREG, 0, 0,                             \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SBREG, SBREG, SBREG, SBREG, SBREG,
+
+#define ROVERLAP \
+        { XR0, -1 },                   \
+        { XR0, XR1, -1 },              \
+        { XR1, XR2, -1 },              \
+        { XR2, XR3, -1 },              \
+        { XR3, XR4, -1 },              \
+        { XR4, XR5, -1 },              \
+        { XR5, XR6, -1 },              \
+        { XR6, XR7, -1 },              \
+        { XR7, XR10, -1 },             \
+        { XR10, XR11, -1 },            \
+        { XR11, XR12, -1 },            \
+        { XR12, XR13, -1 },            \
+        { XR13, XR14, -1 },            \
+        { XR14, -1 },                  \
+        { -1 },                                \
+        { -1 },                                \
+        { R0, R1, XR1, -1 },           \
+        { R1, R2, XR0, XR2, -1 },      \
+        { R2, R3, XR1, XR3, -1 },      \
+        { R3, R4, XR2, XR4, -1 },      \
+        { R4, R5, XR3, XR5, -1 },      \
+        { R5, R6, XR4, XR6, -1 },      \
+        { R6, R7, XR5, XR7, -1 },      \
+        { R7, R10, XR6, XR10, -1 },    \
+        { R10, R11, XR7, XR11, -1 },   \
+        { R11, R12, XR10, XR12, -1 },  \
+        { R12, R13, XR11, XR13, -1 },  \
+        { R13, R14, XR12, XR14, -1 },  \
+        { R14, R15, XR13, -1 },
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (szty(p->n_type) == 2 ? SBREG : SAREG)
+#define RETREG(x) (szty(x) == 2 ? XR1 : R1)
+#define DECRA(x,y)      (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)       ((x) << 6)      /* A1 */
+#define ENCRA2(x)       ((x) << 12)     /* A2 */
+#define ENCRA(x,y)      ((x) << (6+y*6))        /* encode regs in int */
+#define GCLASS(x)      (x < 16 ? CLASSA : CLASSB)
+int COLORMAP(int c, int *r);
diff --git a/lang/pcc/pcc/arch/pdp10/order.c b/lang/pcc/pcc/arch/pdp10/order.c
new file mode 100644 (file)
index 0000000..1f695df
--- /dev/null
@@ -0,0 +1,202 @@
+/*     $Id: order.c,v 1.63 2008/01/15 21:47:06 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return(0);  /* YES */
+}
+
+int radebug = 0;
+
+void
+offstar(NODE *p, int shape)
+{
+       NODE *q;
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( p->n_right->n_op == ICON ){
+                       q = p->n_left;
+                       if (q->n_op != REG)
+                               geninsn(q, INAREG);
+                       p->n_su = -1;
+               }
+       }
+       geninsn(p, INAREG);
+}
+
+/*
+ * findops() failed, see if we can rewrite it to match.
+ */
+int
+setbin(NODE *p)
+{
+       TWORD ty;
+       NODE *r, *s;
+
+       ty = p->n_type;
+       switch (p->n_op) {
+       case MINUS:
+               switch (ty) {
+               case PTR+CHAR:
+               case PTR+UCHAR:
+               case PTR+SHORT:
+               case PTR+USHORT:
+                       /*
+                        * Must negate the right side and change op to PLUS.
+                        */
+                       r = p->n_right;
+                       if (r->n_op == ICON) {
+                               r->n_lval = -r->n_lval;
+                       } else {
+                               s = talloc();
+                               s->n_type = r->n_type;
+                               s->n_op = UMINUS;
+                               s->n_left = r;
+                               p->n_right = s;
+                       }
+                       p->n_op = PLUS;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+int
+special(NODE *p, int shape)
+{
+       switch (shape) {
+       case SUSHCON:
+               if (p->n_op == ICON && p->n_name[0] == '\0' &&
+                   (p->n_lval > 0 && p->n_lval <= 0777777))
+                       return 1;
+               break;
+
+       case SNSHCON:
+               if (p->n_op == ICON && p->n_name[0] == '\0' &&
+                   (p->n_lval < 0 && p->n_lval > -01000000))
+                       return 1;
+               break;
+       case SILDB:
+               if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
+                   p->n_right->n_op == PLUS &&
+                   p->n_right->n_left->n_op == REG &&
+                   p->n_right->n_right->n_op == ICON && 
+                   p->n_right->n_right->n_lval == 1 &&
+                   p->n_right->n_left->n_rval == p->n_left->n_rval)
+                       return 1;
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on x86 */
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *p)
+{
+       if (x2debug)
+               printf("myormake(%p)\n", p);
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[8], *s = r;
+
+       *s = -1;
+       if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL ||
+           p->n_op == FORTCALL)
+               return s;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left) {
+               if (p->n_right->n_op == ASSIGN &&
+                   p->n_right->n_left->n_op == REG)
+                       *s++ = p->n_right->n_left->n_rval;
+       }
+       if (p->n_op == ASSIGN &&
+           p->n_left->n_op == REG)
+               *s++ = p->n_left->n_rval;
+       *s = -1;
+       return r;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/pdp10/table.c b/lang/pcc/pcc/arch/pdp10/table.c
new file mode 100644 (file)
index 0000000..4e140c5
--- /dev/null
@@ -0,0 +1,1136 @@
+/*     $Id: table.c,v 1.97 2008/02/10 19:25:44 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+# define TLL TLONGLONG|TULONGLONG
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED|TULONG
+# define TSWORD TINT|TLONG
+# define TWORD TUWORD|TSWORD
+
+struct optab table[] = {
+{ -1, FORREW,SANY,TANY,SANY,TANY,REWRITE,-1,"", },
+/*
+ * A bunch of pointer conversions.
+ * First pointer to integer.
+ */
+/* Convert char pointer to int */
+{ SCONV,       INAREG,
+       SAREG|SAREG,    TPTRTO|TCHAR|TUCHAR,
+       SANY,   TWORD,
+               NAREG,  RLEFT,
+               "       lsh AL,2\n"
+               "       move A1,AL\n"
+               "       lsh A1,-040\n"
+               "       trz A1,074\n"
+               "       ior AL,A1\n"
+               "       tlz AL,0740000\n", },
+
+/* Convert short pointer to int */
+{ SCONV,       INAREG,
+       SAREG|SAREG,    TPTRTO|TSHORT|TUSHORT,
+       SANY,   TWORD,
+               NAREG,  RLEFT,
+               "       lsh AL,2\n"
+               "       move A1,AL\n"
+               "       lsh A1,-041\n"
+               "       trz A1,2\n"
+               "       ior AL,A1\n"
+               "       tlz AL,0740000\n", },
+
+/* Convert int/unsigned/long/ulong/struct/union/func ptr to int */
+{ SCONV,       INAREG,
+       SAREG|SAREG,    TPTRTO|TWORD|TSTRUCT|TPOINT,
+       SANY,           TWORD,
+               0,      RLEFT,
+               "       lsh AL,2\n", },
+
+/*
+ * Convert int/long to pointers.
+ */
+/* Convert int to char pointer */
+{ PCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TPTRTO|TCHAR|TUCHAR,
+               NAREG,  RLEFT,
+               "       move A1,AL\n"
+               "       lsh A1,036\n"
+               "       tlo A1,0700000\n"
+               "       tlz A1,0040000\n"
+               "       lsh AL,-2\n"
+               "       ior AL,A1\n", },
+
+/* Convert int/long to short pointer */
+{ PCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TPTRTO|TSHORT|TUSHORT,
+               NAREG,  RLEFT,
+               "       move A1,AL\n"
+               "       lsh AL,-2\n"
+               "       tlo AL,0750000\n"
+               "       lsh A1,035\n"
+               "       tlz A1,0760000\n"
+               "       add AL,A1\n", },
+
+/* Convert int/long to int/struct/multiple ptr */
+{ PCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TPOINT|TWORD|TSTRUCT,
+               0,      RLEFT,
+               "       lsh AL,-2\n", },
+
+/*
+ * Pointer to pointer conversions.
+ */
+/* Convert char ptr to short ptr */
+{ PCONV,       INAREG,
+       SAREG,  TPTRTO|TCHAR|TUCHAR,
+       SANY,   TPTRTO|TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       tlo AL,050000\n"
+               "       tlne AL,020000\n"
+               "       tlz AL,010000\n", },
+
+/* Convert char/short pointer to int/struct/multiple ptr */
+{ PCONV,       INAREG,
+       SAREG,  TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SANY,   TPOINT|TWORD|TSTRUCT,
+               0,      RLEFT,
+               "       tlz AL,0770000\n", },
+
+/* Convert short pointer to char ptr */
+{ PCONV,       INAREG,
+       SAREG,  TPTRTO|TSHORT|TUSHORT,
+       SANY,   TPTRTO|TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       tlz AL,050000\n", },
+
+/* Convert int/struct/foo pointer to char ptr */
+{ PCONV,       INAREG,
+       SAREG,  TPOINT|TWORD|TSTRUCT,
+       SANY,   TPTRTO|TCHAR|TUCHAR,
+               0,      RLEFT,
+               "       tlo AL,0700000\n", },
+
+/* Convert int/struct/foo pointer to short ptr */
+{ PCONV,       INAREG,
+       SAREG,  TPTRTO|TWORD|TSTRUCT,
+       SANY,   TPTRTO|TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       tlo AL,0750000\n", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ */
+
+/* convert short/char to int. This is done when register is loaded */
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD,
+       SANY,   TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert int to short/char. This is done when register is loaded */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert int/long to unsigned long long */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SANY,   TULONGLONG,
+               NAREG|NASL,     RESC1,
+               "       move U1,AL\n"
+               "       setz A1,\n"
+               "       tlze U1,0400000\n"
+               "       tro A1,01\n" , },
+
+/* convert int/long to long long */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SANY,   TLONGLONG,
+               NAREG|NASL,     RESC1,
+               "       move U1,AL\n"
+               "       move A1,U1\n"
+               "       ash A1,-043\n", },
+
+/* convert uchar/ushort to (unsigned) long long */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TUCHAR|TUSHORT,
+       SANY,                           TLL,
+               NAREG|NASL,     RESC1,
+               "       move U1,AL\n"
+               "       setz A1,\n", },
+
+/* convert long long to int/long */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+       SANY,   TWORD,
+               NAREG|NASL,     RESC1,
+               "       move A1,UL\n", },
+
+/* convert long long to unsigned char - XXX - signed char */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+       SANY,   TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       move A1,UL\n"
+               "       andi A1,0777\n", },
+
+/* convert long long to short - XXX - signed short */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+       SANY,   TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       move A1,UL\n"
+               "       hrrz A1,A1\n", },
+
+/* floating point conversions */
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TDOUBLE|TFLOAT,
+       SANY,   TWORD,
+               NAREG|NASL,     RESC1,
+               "       fix A1,AL\n", },
+
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SANY,   TFLOAT,
+               NAREG|NASL,     RESC1,
+               "       fltr A1,AL\n", },
+
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SANY,   TDOUBLE,
+               NAREG|NASL,     RESC1,
+               "       fltr A1,AL\n    setz U1,\n", },
+
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TDOUBLE,
+       SANY,   TFLOAT,
+               NAREG|NASL,     RESC1,
+               "       move A1,AL\n", },
+
+{ SCONV,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TFLOAT,
+       SANY,   TDOUBLE,
+               NAREG|NASL,     RESC1,
+               "       move A1,AL\n    setz U1,\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,      /* should be 0 */
+               "       pushj 017,AL\nZB", },
+
+{ CALL,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,      /* should be 0 */
+               "       pushj 017,AL\nZB", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SANY,   TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TPOINT,
+               NAREG,  RESC1,  /* should be 0 */
+               "       pushj 017,AL\nZB", },
+
+{ CALL,                INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       pushj 017,AL\nZB", },
+
+{ UCALL,       INAREG,
+       SAREG|SAREG,    TANY,
+       SANY,   TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       pushj 017,(AL)\nZB", },
+
+{ UCALL,       INAREG,
+       SNAME|SOREG,    TANY,
+       SANY,   TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+               NAREG,  RESC1,  /* should be 0 */
+               "       pushj 017,@AL\nZB", },
+
+#ifdef notyet
+/*
+ * INCR can be slightly optimized.
+ */
+{ INCR,                INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+       SONE,   TANY,
+               NAREG,  RESC1,
+               "       move A1,AL\n"
+               "       ibp AL\n", },
+
+/* Fix check of return value */
+{ INCR,                FOREFF,
+       SAREG|SAREG|SNAME|SOREG,        TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+       SONE,   TANY,
+               0,      0,
+               "       ibp AL\n", },
+#endif
+
+/*
+ * PLUS operators.
+ */
+/* Add a value to a char/short pointer */
+{ PLUS,        INAREG|INAREG|FOREFF,
+       SAREG|SAREG|SNAME|SOREG,        TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG,                    TWORD,
+               0,      RRIGHT,
+               "       adjbp AR,AL\n", },
+
+/* No more search for char/short pointer addition */
+{ PLUS,        INAREG|INAREG|FOREFF,
+       SANY,   TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SANY,   TANY,
+               REWRITE, 0,
+               "DIEDIEDIE!\n", },
+
+/* Add char/short/int to register */
+{ PLUS,        FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TWORD,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,      RLEFT,
+               "       add AL,AR\n", },
+
+/* Add char/short/int to memory */
+{ PLUS,        FOREFF|INAREG|INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SAREG|SAREG,                    TWORD,
+               0,      RLEFT,
+               "       addm AR,AL\n", },
+
+/* Add a small constant to a register */
+{ PLUS,        FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT,
+       SUSHCON,        TWORD,
+               0,      RLEFT,
+               "       addi AL,AR\n", },
+
+/* Add a larger constant to a register */
+{ PLUS,        FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT,
+       SCON,   TWORD,
+               0,      RLEFT,
+               "       add AL,[ .long AR ]\n", },
+
+/* Add long long to register */
+{ PLUS,        INAREG|INAREG|FOREFF,
+       SAREG|SAREG,                    TLL,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+               0,      RLEFT,
+               "       dadd AL,AR\n", },
+
+/* Add int (or int pointer) to register */
+{ PLUS,        FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TWORD|TPOINT,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,      RLEFT,
+               "       add AL,AR # foo \n", },
+
+/* char/short are allowed to be added if they are in registers */
+{ PLUS,        INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       add AL,AR\n", },
+
+/* get address of an memory position into a register */
+{ PLUS,        INAREG|INAREG,
+       SAREG|SAREG,    TWORD|TPTRTO,
+       SCON,           TANY,
+               NAREG,  RESC1,
+               "       xmovei A1,AR(AL)\n", },
+
+/* Safety belt for plus */
+{ PLUS,        FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/*
+ * MINUS operators.
+ */
+/* Rewrite subtracts from char/short pointers (to negative adds) */
+{ MINUS,       FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/* Subtract char/short/int word in memory from reg */
+{ MINUS,       FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TWORD|TPOINT,
+       SAREG|SAREG|SNAME|SOREG,        TWORD|TPOINT,
+               0,      RLEFT,
+               "       sub AL,AR\n", },
+
+/* Subtract a small constant from reg */
+{ MINUS,       FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TWORD|TPOINT,
+       SUSHCON,        TWORD|TPOINT,
+               0,      RLEFT,
+               "       subi AL,AR\n", },
+
+/* Subtract a large constant from reg */
+{ MINUS,       FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TWORD|TPOINT,
+       SCON,   TWORD|TPOINT,
+               0,      RLEFT,
+               "       sub AL,[ .long AR ]\n", },
+
+/* Subtract char/short/int word in memory from reg, save in memory */
+{ MINUS,       FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TWORD,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,      RRIGHT,
+               "       subm AL,AR\n", },
+
+/* Subtract long long from register */
+{ MINUS,       INAREG|INAREG|FOREFF,
+       SAREG|SAREG,                    TLL,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+               0,      RLEFT,
+               "       dsub AL,AR\n", },
+
+/* char/short are allowed to be subtracted if they are in registers */
+{ MINUS,       INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       sub AL,AR\n", },
+
+/* Safety belt for plus */
+{ MINUS,       FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/*
+ * AND/OR/ER operators.
+ * Simpler that the ops above in that they only work on integral types.
+ */
+/* And char/short/int with integer memory */
+{ AND, FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,      RLEFT,
+               "       and AL,AR\n", },
+
+/* And char/short/int with register */
+{ AND, FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       and AL,AR\n", },
+
+/* And char/short/int with small constant */
+{ AND, FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SUSHCON,        TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       andi AL,AR\n", },
+
+/* And char/short/int with large constant */
+{ AND, FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SCON,   TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       and AL,[ .long AR ]\n", },
+
+/* long long AND */
+{ AND, INAREG|FOREFF,
+       SAREG|SAREG,                    TLL,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+               0,      RLEFT,
+               "       and AL,AR\n"
+               "       and UL,UR\n", },
+
+/* Safety belt for AND */
+{ AND, FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+
+/* OR char/short/int with integer memory */
+{ OR,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,      RLEFT,
+               "       ior AL,AR\n", },
+
+/* OR char/short/int with register */
+{ OR,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       ior AL,AR\n", },
+
+/* OR char/short/int with small constant */
+{ OR,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SUSHCON,        TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       iori AL,AR\n", },
+
+/* OR char/short/int with large constant */
+{ OR,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SCON,   TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       ior AL,[ .long AR ]\n", },
+
+/* long long OR */
+{ OR,  INAREG|FOREFF,
+       SAREG|SAREG,                    TLL,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+               0,      RLEFT,
+               "       ior AL,AR\n"
+               "       ior UL,UR\n", },
+
+/* Safety belt for OR */
+{ OR,  FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+
+/* ER char/short/int with integer memory */
+{ ER,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,      RLEFT,
+               "       xor AL,AR\n", },
+
+/* ER char/short/int with register */
+{ ER,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SAREG|SAREG,                    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       xor AL,AR\n", },
+
+/* ER char/short/int with small constant */
+{ ER,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SUSHCON,        TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       xori AL,AR\n", },
+
+/* ER char/short/int with large constant */
+{ ER,  FOREFF|INAREG|INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+       SCON,   TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+               0,      RLEFT,
+               "       xor AL,[ .long AR ]\n", },
+
+/* long long ER */
+{ ER,  INAREG|FOREFF,
+       SAREG|SAREG,                    TLL,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+               0,      RLEFT,
+               "       xor AL,AR\n"
+               "       xor UL,UR\n", },
+
+/* Safety belt for ER */
+{ ER,  FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS,  INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       lsh AL,(AR)\n", },
+
+{ LS,  INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SNAME|SOREG,    TWORD,
+               0,      RLEFT,
+               "       lsh AL,@AR\n", },
+
+{ LS,       INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TLL,
+       SCON,           TANY,
+               0,      RLEFT,
+               "       ashc AL,ZH\n", },
+
+{ LS,  INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TLL,
+       SAREG|SAREG /* |SNAME|SOREG */, TANY,
+               0,      RLEFT,
+               "       ashc AL,(AR)\n", },
+
+{ RS,  INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TSWORD,
+       SCON,           TWORD,
+               0,      RLEFT,
+               "       ash AL,-ZH\n", },
+
+{ RS,  INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TUWORD,
+       SCON,           TWORD,
+               0,      RLEFT,
+               "       lsh AL,-ZH\n", },
+
+/* Safety belt for LS/RS */
+{ LS,  FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+{ RS,  FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+/* Match zeroed registers first */
+{ ASSIGN,      INAREG|FOREFF,
+       SAREG,  TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+       SZERO,  TANY,
+               0,      RDEST,
+               "       setz AL,\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SZERO,  TANY,
+               0,      0,
+               "       setzm AL\n", },
+
+{ ASSIGN,      INAREG|FOREFF,
+       SAREG|SAREG,    TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+       SMONE,  TANY,
+               0,      RDEST,
+               "       setom AL\n", },
+
+{ ASSIGN,      FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SMONE,  TANY,
+               0,      0,
+               "       setom AL\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SAREG,            TWORD|TPOINT,
+       SCON,           TWORD|TPOINT,
+               0,      RDEST,
+               "       ZC\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT|TFLOAT,
+       SAREG|SAREG,            TUCHAR|TUSHORT|TWORD|TPOINT|TFLOAT,
+               0,      RDEST,
+               "       movem AR,AL\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT|TFLOAT,
+       SAREG|SAREG,            TSHORT,
+               0,      RDEST,
+               "       hrrem AR,AL\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+       SAREG|SAREG|SNAME|SOREG,        TWORD|TPOINT,
+               0,      RDEST,
+               "       move AL,AR\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TUCHAR|TUSHORT|TCHAR|TSHORT,
+       SAREG|SAREG,    TUCHAR|TUSHORT|TCHAR|TSHORT,
+               0,      RDEST,
+               "       move AL,AR\n", },
+
+{ ASSIGN,      INBREG|FOREFF,
+       SBREG|SNAME|SOREG,      TLL|TDOUBLE,
+       SBREG,          TLL|TDOUBLE,
+               0,      RDEST,
+               "       dmovem AR,AL\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SOREG|SNAME,    TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG|SAREG,    TANY,
+               0,      RDEST,
+               "ZV", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TUSHORT|TUCHAR,
+       SOREG,          TANY,
+               0,      RDEST,
+               "       ldb AL,Zg\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,          TANY,
+               0,      RDEST,
+               "       movei AL,AR\n", },
+
+{ ASSIGN,      INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      RDEST,
+               "       move AL,[ .long AR]\n", },
+
+/*
+ * DIV/MOD/MUL 
+ * These can be done way more efficient.
+ */
+/* long long div. XXX - work only with unsigned */
+{ DIV, INBREG,
+       SBREG|SNAME|SOREG,      TLL,
+       SBREG|SNAME|SOREG,      TLL,
+               (2*NBREG)|NBSL, RESC1,
+               "       dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+               "       ddiv A1,AR\n", },
+
+/* long long div. with constant. XXX - work only with unsigned */
+{ DIV, INBREG,
+       SBREG|SNAME|SOREG,      TLL,
+       SCON,   TLL,
+               (2*NBREG)|NBSL, RESC1,
+               "       dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+               "       ddiv A1,ZP\n", },
+
+/* Simple divide. XXX - fix so next reg can be free */
+{ DIV, INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,      RRIGHT,
+               "       idivm AL,AR\n", },
+
+/* Safety belt for DIV */
+{ DIV, FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/* long long MOD */
+{ MOD, INBREG,
+       SBREG|SNAME|SOREG,      TLL,
+       SBREG|SNAME|SOREG,      TLL,
+               2*NBREG|NBSL,   RESC2,
+               "       dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+               "       ddiv A1,AR\n", },
+
+/* integer MOD */
+{ MOD, INAREG,
+       SAREG|SNAME|SOREG,      TWORD,
+       SAREG|SNAME|SOREG,      TWORD,
+               2*NAREG|NASL,   RESC2,
+               "       move A2,AL\n"
+               "       setz A1,\n"
+               "       idiv A1,AR\n", },
+
+/* integer MOD for char/short */
+{ MOD, INAREG,
+       SAREG,  TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG,  TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               2*NAREG|NASL,   RESC2,
+               "       move A2,AL\n"
+               "       setz A1,\n"
+               "       idiv A1,AR\n", },
+
+/* Safety belt for MOD */
+{ MOD, FOREFF,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/* long long MUL */
+{ MUL, INBREG,
+       SBREG|SNAME|SOREG,      TLL,
+       SBREG|SNAME|SOREG,      TLL,
+               2*NBREG|NBSL,   RESC2,
+               "       dmove A1,AL\n"
+               "       dmul A1,AR\n", },
+
+/* integer multiply to memory*/
+{ MUL, INAREG|INAREG|FOREFF,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SAREG|SAREG,                    TWORD,
+               0,              RLEFT,
+               "       imulm AR,AL\n", },
+
+/* integer multiply */
+{ MUL, INAREG|INAREG|FOREFF,
+       SAREG|SAREG,                    TWORD,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+               0,              RLEFT,
+               "       imul AL,AR\n", },
+
+/* integer multiply for char/short */
+{ MUL, INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG,    TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,              RLEFT,
+               "       imul AL,AR\n", },
+
+/* integer multiply with small constant */
+{ MUL, INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TWORD,
+       SUSHCON,        TWORD,
+               0,              RLEFT,
+               "       imuli AL,AR\n", },
+
+/* integer multiply with large constant */
+{ MUL, INAREG|INAREG|FOREFF,
+       SAREG|SAREG,    TWORD,
+       SCON,           TWORD,
+               0,              RLEFT,
+               "       imul AL,[ .long AR ]\n", },
+
+/* Safety belt for MUL */
+{ MUL, FORREW|FOREFF|INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "DIEDIEDIE", },
+
+/* read an indirect long long value into register */
+{ UMUL,        INAREG,
+       SAREG|SAREG,    TPTRTO|TLL|TWORD,
+       SANY,           TLL,
+               NAREG|NASL,     RESC1,
+               "       dmove A1,(AL)\n", },
+
+/* read an indirect integer value into register */
+{ UMUL,        INAREG,
+       SAREG|SAREG,    TWORD|TPOINT,
+       SANY,           TWORD|TPOINT,
+               NAREG|NASL,     RESC1,
+               "       move A1,(AL)\n", },
+
+/* read an indirect value into register */
+{ UMUL,        INAREG,
+       SOREG,  TWORD|TPOINT,
+       SANY,   TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       move A1,@AL\n", },
+
+/* read an indirect value into register */
+{ UMUL,        INAREG,
+       SAREG|SAREG|SOREG,      TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+       SANY,   TCHAR|TUCHAR|TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       ldb A1,AL\n", },
+
+#ifdef notyet
+/* Match tree shape for ildb */
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SILDB,  TUCHAR|TCHAR|TPTRTO,
+               NAREG,  RESC1,
+               "       ildb A1,ZA\n", },
+#endif
+
+/* Match char/short pointers first, requires special handling */
+{ OPLOG,       FORCC,
+       SAREG|SAREG,    TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG,    TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,      RESCC,
+               "ZZ", },
+
+/* Can check anything by just comparing if EQ/NE */
+{ OPLOG,       FORCC,
+       SAREG|SAREG,    TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SZERO,  TANY,
+               0,      RESCC,
+               "       jumpZe AL,LC # bu\n", },
+
+{ EQ,          FORCC,
+       SAREG|SAREG,    TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG|SOREG|SNAME|SCON,   TWORD|TPOINT,
+               0,      RESCC,
+               "ZR", },
+
+{ NE,          FORCC,
+       SAREG|SAREG,    TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG|SOREG|SNAME|SCON,   TWORD|TPOINT,
+               0,      RESCC,
+               "ZR", },
+
+{ OPLOG,       FORCC,
+       SAREG|SAREG,    TWORD,
+       SAREG|SAREG|SOREG|SNAME|SCON,   TSWORD,
+               0,      RESCC,
+               "ZR", },
+
+{ OPLOG,       FORCC,
+       SAREG|SAREG,    TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      RESCC,
+               "ZR", },
+
+{ OPLOG,       FORCC,
+       SAREG|SAREG,    TWORD|TPOINT|TFLOAT,
+       SAREG|SAREG|SOREG|SNAME|SCON,   TWORD|TPOINT|TFLOAT,
+               0,      RESCC,
+               "ZR", },
+
+{ OPLOG,       FORCC,
+       SAREG|SAREG,    TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SAREG|SAREG,    TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,      RESCC,
+               "ZR", },
+
+{ OPLOG,       FORCC,  
+       SAREG|SAREG,    TLL|TDOUBLE, /* XXX - does double work here? */
+       SAREG|SAREG|SOREG|SNAME,        TLL|TDOUBLE,
+               0,      RESCC,
+               "ZQ", },
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jrst LL\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SMONE,  TLL,
+               NBREG,  RESC1,
+               "       seto A1,\n      seto U1,\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SMONE,  TANY,
+               NAREG,  RESC1,
+               "       seto A1,\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SZERO,  TLL,
+               NBREG,  RESC1,
+               "       setz A1,\n      setz U1,\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SZERO,  TANY,
+               NAREG,  RESC1,
+               "       setz A1,\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SUSHCON,        TLL,
+               NBREG,  RESC1,
+               "       setz A1,\n      movei U1,AR\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SUSHCON,        ANYFIXED,
+               NAREG,  RESC1,
+               "       movei A1,AR\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   ANYFIXED,
+       SNSHCON,        ANYFIXED,
+               NAREG,  RESC1,
+               "       hrroi A1,AR\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   ANYFIXED,
+       SCON,   ANYFIXED,
+               NAREG|NASR,     RESC1,
+               "       ZD A1,ZE        # suspekt\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TWORD|TPOINT|TFLOAT,
+       SAREG|SAREG|SOREG|SNAME,        TWORD|TPOINT|TFLOAT,
+               NAREG|NASR,     RESC1,
+               "       move A1,AR\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TLL,
+       SCON,   TLL,
+               NBREG,  RESC1,
+               "       dmove A1,ZO\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TLL|TDOUBLE,
+       SANY,   TLL|TDOUBLE,
+               NBREG|NBSR,     RESC1,
+               "       dmove A1,AR\n", },
+
+{ OPLTYPE,     INAREG,
+       SOREG,          TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SOREG,          TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NASR,   RESC1,
+               "ZU", },
+
+{ OPLTYPE,     INAREG,
+       SNAME,  TUCHAR,
+       SNAME,  TUCHAR,
+               NAREG|NASR,     RESC1,
+               "       ldb A1,[ .long AL ]\n" },
+
+{ OPLTYPE,     INAREG,
+       SNAME,  TCHAR,
+       SNAME,  TCHAR,
+               NAREG|NASR,     RESC1,
+               "       ldb A1,[ .long AL ]\n"
+               "       ash A1,033\n"
+               "       ash A1,-033\n", },
+               
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SNAME,  TSHORT|TUSHORT,
+               NAREG|NASR,     RESC1,
+               "Zi", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TWORD|TPOINT,
+       SCON,   TWORD|TPOINT,
+               NAREG|NASR,     RESC1,
+               "Zc", },
+
+{ OPLTYPE,     INAREG,
+       SAREG|SAREG,    TUSHORT|TUCHAR,
+       SAREG|SAREG,    TUSHORT|TUCHAR|TWORD,
+               NAREG,  RESC1,
+               "       move A1,AL\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS,      INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SANY,   TWORD,
+               NAREG|NASL,     RESC1,
+               "       movn A1,AL\n", },
+
+{ UMINUS,      INAREG,
+       SAREG|SAREG,    TWORD,
+       SANY,   TCHAR|TUCHAR|TSHORT|TUSHORT,
+               0,      RLEFT,
+               "       movn AL,AL\n", },
+
+{ UMINUS,      INAREG,
+       SAREG|SNAME|SOREG,      TLL,
+       SANY,   TLL,
+               NAREG|NASR,     RESC1,
+               "       dmovn A1,AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TLL,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       setcm A1,AL\n"
+               "       setcm U1,UL\n", },
+
+{ COMPL,       INAREG,
+       SAREG|SAREG|SNAME|SOREG,        TWORD,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       setcm A1,AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SANY,   TCHAR|TUCHAR|TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       setcm A1,AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,      FOREFF,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT|TFLOAT,
+       SANY,   TANY,
+               0,      RNULL,
+               "       push 017,AL\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG|SAREG,    TCHAR|TUCHAR|TSHORT|TUSHORT,
+       SANY,   TANY,
+               0,      RNULL,
+               "       push 017,AL\n", },
+
+{ FUNARG,      FOREFF,
+       SCON,   TCHAR|TUCHAR|TSHORT|TUSHORT|TPOINT|TWORD,
+       SANY,   TANY,
+               0,      RNULL,
+               "       push 017,[ .long AL]\n", },
+
+{ FUNARG,      FOREFF,
+       SBREG,  TLL|TDOUBLE,
+       SANY,           TANY,
+               0,      RNULL,
+               "       push 017,AL\n   push 017,UL\n", },
+
+{ STARG,       FOREFF,
+       SAREG|SOREG|SNAME|SCON, TANY, 
+       SANY,   TSTRUCT,
+               0, 0, 
+               "ZG", },
+
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ OPLEAF, DF(NAME), },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ FREE, FREE, FREE,    FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/pdp11/code.c b/lang/pcc/pcc/arch/pdp11/code.c
new file mode 100644 (file)
index 0000000..53d3913
--- /dev/null
@@ -0,0 +1,278 @@
+/*     $Id: code.c,v 1.8 2015/09/03 19:24:51 ragge Exp $       */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+#define NODE P1ND
+#undef NIL
+#define NIL NULL
+#define        talloc p1alloc
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case UDATA: break;
+       case STRNG:
+       case RDATA: name = ".rodata"; break;
+       default:
+               cerror("setseg");
+       }
+       printf("\t%s\n", name);
+}
+
+void
+defalign(int al)
+{
+       if (al > ALCHAR)
+               printf(".even\n");
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       static char *loctbl[] = { "text", "data", "data" };
+       TWORD t;
+       char *n;
+       int s;
+
+       t = sp->stype;
+       s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+       if (s != lastloc)
+               printf("        .%s\n", loctbl[s]);
+       lastloc = s;
+       n = sp->soname ? sp->soname : exname(sp->sname);
+       if (sp->sclass == EXTDEF)
+               printf("        .globl %s\n", n);
+       if (sp->slevel == 0) {
+               printf("%s:\n", n);
+       } else {
+               printf(LABFMT ":\n", sp->soffset);
+       }
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+       NODE *p, *q;
+
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+       /* Create struct assignment */
+       q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       q->n_rval = R5;
+       q->n_lval = 8; /* return buffer offset */
+       q = buildtree(UMUL, q, NIL);
+       p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+       p = buildtree(UMUL, p, NIL);
+       p = buildtree(ASSIGN, q, p);
+       ecomp(p);
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       struct symtab *sp2;
+       NODE *n;
+       int i;
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               /* Function returns struct, adjust arg offset */
+               for (i = 0; i < cnt; i++) 
+                       sp[i]->soffset += SZPOINT(INT);
+       }
+
+       if (xtemps == 0)
+               return;
+
+       /* put arguments in temporaries */
+       for (i = 0; i < cnt; i++) {
+               if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY ||
+                   cisreg(sp[i]->stype) == 0)
+                       continue;
+               sp2 = sp[i];
+               n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap);
+               n = buildtree(ASSIGN, n, nametree(sp2));
+               sp[i]->soffset = regno(n->n_left);
+               sp[i]->sflags |= STNODE;
+               ecomp(n);
+       }
+}
+
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+}
+
+void
+bjobcode(void)
+{
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
+ */
+NODE *
+funcode(NODE *p)
+{
+       NODE *r, *l;
+
+       /* Fix function call arguments. On x86, just add funarg */
+       for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+               if (r->n_right->n_op != STARG)
+                       r->n_right = block(FUNARG, r->n_right, NIL,
+                           r->n_right->n_type, r->n_right->n_df,
+                           r->n_right->n_ap);
+       }
+       if (r->n_op != STARG) {
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_type = l->n_type;
+       }
+       return p;
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+
+NODE *
+builtin_huge_val(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_huge_valf(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_huge_vall(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_inf(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_inff(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_infl(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_nan(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_nanf(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
+NODE *
+builtin_nanl(const struct bitable *bt, NODE *a)
+{
+       uerror(__func__);
+       return bcon(0);
+}
diff --git a/lang/pcc/pcc/arch/pdp11/local.c b/lang/pcc/pcc/arch/pdp11/local.c
new file mode 100644 (file)
index 0000000..243a8cb
--- /dev/null
@@ -0,0 +1,400 @@
+/*     $Id: local.c,v 1.15 2015/09/03 19:24:51 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#define        NODE P1ND
+#undef NIL
+#define NIL NULL
+#define fwalk p1fwalk
+#define nfree p1nfree
+
+/*     this file contains code which is dependent on the target machine */
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+       register struct symtab *q;
+       register NODE *r, *l;
+       register int o;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       switch( o = p->n_op ){
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case STATIC:
+                       if (q->slevel == 0)
+                               break;
+                       p->n_lval = 0;
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+               case EXTERN:
+               case EXTDEF:
+                       break;
+               }
+               break;
+
+       case CBRANCH:
+               l = p->n_left;
+               if (coptype(l->n_op) != BITYPE)
+                       break;
+               if (l->n_left->n_op != SCONV || l->n_right->n_op != ICON)
+                       break;
+               if ((r = l->n_left->n_left)->n_type > INT)
+                       break;
+               /* compare with constant without casting */
+               nfree(l->n_left);
+               l->n_left = r;
+               l->n_right->n_type = l->n_left->n_type;
+               break;
+
+       case STASG: /* struct assignment, modify left */
+               l = p->n_left;
+               if (l->n_type == STRTY)
+                       p->n_left = buildtree(ADDROF, l, NIL);
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(CHAR) : RETREG(p->n_type);
+               break;
+
+       }
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+
+       if (p->n_op != FCON)
+               return;
+
+       sp = tmpalloc(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       locctr(DATA, sp);
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       p->n_lval = 0;
+       p->n_sp = sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);      /* all names can have & taken on them */
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE ||
+           t == LONGLONG || t == ULONGLONG)
+               return 0; /* not yet */
+       return 1;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+       char *s;
+       int val, cnt;
+
+       defloc(sp);
+
+       for (cnt = 0, s = sp->sname; *s != 0; ) {
+               if (cnt++ == 0)
+                       printf(".byte ");
+               if (*s++ == '\\')
+                       val = esccon(&s);
+               else
+                       val = s[-1];
+               printf("%o", val & 0377);
+               if (cnt > 15) {
+                       cnt = 0;
+                       printf("\n");
+               } else
+                       printf(",");
+       }
+       printf("%s0\n", cnt ? "" : ".byte ");
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+#if defined(__pdp11__) || 1
+       union { float f; double d; short s[4]; int i[2]; } u;
+#endif
+       TWORD t;
+       int i;
+
+       t = p->n_type;
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+               i = (p->n_lval >> 32);
+               p->n_lval &= 0xffffffff;
+               p->n_type = INT;
+               ninval(off, 32, p);
+               p->n_lval = i;
+               ninval(off+32, 32, p);
+               break;
+       case LONG:
+       case ULONG:
+               printf("%o ; %o\n", (int)((p->n_lval >> 16) & 0177777),
+                   (int)(p->n_lval & 0177777));
+               break;
+#if defined(__pdp11__) || 1
+       case FLOAT:
+               u.f = (float)p->n_dcon;
+               printf("%o ; %o\n", u.i[0], u.i[1]);
+               break;
+       case LDOUBLE:
+       case DOUBLE:
+               u.d = (double)p->n_dcon;
+               printf("%o ; %o ; %o ; %o\n", u.i[0], u.i[1], u.i[2], u.i[3]);
+               break;
+#else
+       /* cross-compiling */
+       case FLOAT:
+               printf("%o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2);
+               break;
+       case LDOUBLE:
+       case DOUBLE:
+               printf("%o ; %o ; %o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2,
+                   p->n_dcon.fd3, p->n_dcon.fd4);
+               break;
+#endif
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#define NCHNAM  256
+       static char text[NCHNAM+1];
+       int i;
+
+       if (p == NULL)
+               return "";
+
+       text[0] = '_';
+       for (i=1; *p && i<NCHNAM; ++i)
+               text[i] = *p++;
+
+       text[i] = '\0';
+       text[NCHNAM] = '\0';  /* truncate */
+
+       return (text);
+
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case SHORT:
+               MODTYPE(type,INT);
+               break;
+
+       case USHORT:
+               MODTYPE(type,UNSIGNED);
+               break;
+
+       case LDOUBLE:
+               MODTYPE(type,DOUBLE);
+               break;
+
+       }
+       return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       extern int lastloc;
+       char *n;
+       int off;
+
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       n = sp->soname ? sp->soname : exname(sp->sname);
+       if (sp->sclass == STATIC) {
+               printf(".bss\n");
+               if (sp->slevel == 0)
+                       printf("%s:", n);
+               else
+                       printf(LABFMT ":", sp->soffset);
+               printf("        .=.+%o\n", off);
+               lastloc = -1;
+               return;
+       }
+       printf(".comm ");
+       if (sp->slevel == 0)
+               printf("%s,0%o\n", n, off);
+       else
+               printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/pdp11/local2.c b/lang/pcc/pcc/arch/pdp11/local2.c
new file mode 100644 (file)
index 0000000..0c42ff6
--- /dev/null
@@ -0,0 +1,845 @@
+/*     $Id: local2.c,v 1.10 2015/06/29 18:49:36 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+static int spcoff;
+static int argsiz(NODE *p);
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+
+#ifdef LANG_F77
+       if (ipp->ipp_vis)
+               printf("        .globl %s\n", ipp->ipp_name);
+       printf("%s:\n", ipp->ipp_name);
+#endif
+       printf("jsr     r5,csv\n");
+       addto = p2maxautooff;
+       if (addto >= AUTOINIT/SZCHAR)
+               addto -= AUTOINIT/SZCHAR;
+       if (addto & 1)
+               addto++;
+       if (addto == 2)
+               printf("tst     -(sp)\n");
+       else if (addto == 4)
+               printf("cmp     -(sp),-(sp)\n");
+       else if (addto > 4)
+               printf("sub     $%o,sp\n", addto);
+       spcoff = 0;
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       if (spcoff)
+               comperr("spcoff == %d", spcoff);
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+       printf("jmp     cret\n");
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "add";
+               break;
+       case MINUS:
+               str = "sub";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Emit code to compare two long numbers.
+ */
+static void
+twolcomp(NODE *p)
+{
+       int o = p->n_op;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       if (o >= ULE)
+               o -= (ULE-LE);
+       switch (o) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 2, cb2 += 2;
+       expand(p, 0, "cmp       AR,AL\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+        expand(p, 0, "cmp      UR,UL\n");
+        cbgen(p->n_op, e);
+        deflab(s);
+}
+
+
+/*
+ * Generate compare code for long instructions when right node is 0.
+ */
+static void
+lcomp(NODE *p)
+{
+       switch (p->n_op) {
+       case EQ:
+               expand(p, FORCC, "tst   AL\n");
+               printf("jne     1f\n");
+               expand(p, FORCC, "tst   UL\n");
+               cbgen(EQ, p->n_label);
+               printf("1:\n");
+               break;
+       case NE:
+               expand(p, FORCC, "tst   AL\n");
+               cbgen(NE, p->n_label);
+               expand(p, FORCC, "tst   UL\n");
+               cbgen(NE, p->n_label);
+               break;
+       case GE:
+               expand(p, FORCC, "tst   AL\n");
+               cbgen(GE, p->n_label);
+               break;
+       default:
+               comperr("lcomp %p", p);
+       } 
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       switch (c) {
+       case 'A': /* print out - if not first arg */
+               if (spcoff || (p->n_type == FLOAT || p->n_type == DOUBLE))
+                       printf("-");
+               spcoff += argsiz(p);
+               break;
+
+       case 'B': /* arg is pointer to block */
+               expand(p->n_left, FOREFF, "mov  AL,ZA(sp)\n");
+               expand(p->n_left, FOREFF, "sub  CR,(sp)\n");
+               break;
+               
+       case 'C': /* subtract stack after call */
+               spcoff -= p->n_qual;
+               if (spcoff == 0 /* && !(p->n_flags & NLOCAL1) XXX FIXME */)
+                       p->n_qual -= 2;
+               if (p->n_qual == 2)
+                       printf("tst     (sp)+\n");
+               else if (p->n_qual == 4)
+                       printf("cmp     (sp)+,(sp)+\n");
+               else if (p->n_qual > 2)
+                       printf("add     $%o,sp\n", (int)p->n_qual);
+               break;
+
+       case 'D': /* long comparisions */
+               lcomp(p);
+               break;
+
+       case 'E': /* long move */
+               rmove(p->n_right->n_reg, p->n_left->n_reg, p->n_type);
+               break;
+
+       case 'F': /* long comparision */
+               twolcomp(p);
+               break;
+
+       case 'G': /* printout a subnode for post-inc */
+               adrput(stdout, p->n_left->n_left);
+               break;
+
+       case 'H': /* arg with post-inc */
+               expand(p->n_left->n_left, FOREFF, "mov  AL,ZA(sp)\n");
+               expand(p->n_left->n_left, FOREFF, "inc  AL\n");
+               break;
+
+       case 'Q': /* struct assignment, no rv */
+               printf("mov     $%o,", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/2);
+               expand(p, INAREG, "A1\n");
+               printf("1:\n");
+               expand(p, INAREG, "mov  (AR)+,(AL)+\n");
+               expand(p, INAREG, "dec  A1\n");
+               printf("jne     1b\n");
+               break;
+
+       case 'R': /* struct assignment with rv */
+               printf("mov     $%o,", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/2);
+               expand(p, INAREG, "A1\n");
+               expand(p, INAREG, "mov  AR,A2\n");
+               printf("1:\n");
+               expand(p, INAREG, "mov  (A2)+,(AL)+\n");
+               expand(p, INAREG, "dec  A1\n");
+               printf("jne     1b\n");
+               break;
+
+       case '1': /* lower part of double regs */
+               p = getlr(p, '1');
+               printf("r%c", rnames[p->n_rval][1]);
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==REG || o==ICON || o==OREG ||
+           (o==UMUL && shumul(p->n_left, STARNM|SOREG)))
+               return(1);
+       return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o == OREG || o == REG || o == NAME)
+               return SRDIR; /* Direct match */
+       if (o == UMUL && shumul(p->n_left, SOREG))
+               return SROREG; /* Convert into oreg */
+       return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(p->n_rval));
+
+       case OREG:
+               r = p->n_rval;
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+static void
+negcon(FILE *fp, int con)
+{
+       if (con < 0)
+               fprintf(fp, "-"), con = -con;
+       fprintf(fp, "%o", con & 0177777);
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = p->n_lval;
+
+       switch (p->n_op) {
+       case ICON:
+               printf("$");
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+%o", val & 0177777);
+               } else if (p->n_type == LONG || p->n_type == ULONG)
+                       negcon(fp, val >> 16);
+               else
+                       negcon(fp, val);
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+       size /= SZINT;
+       switch (p->n_op) {
+       case NAME:
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+       case REG:
+               printf("r%c", rnames[p->n_rval][2]);
+               break;
+       case ICON:
+               /* On PDP11 upper value is low 16 bits */
+               printf("$");
+               negcon(stdout, p->n_lval & 0177777);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+/*
+ * output an address, with offsets, from p
+ */
+void
+adrput(FILE *io, NODE *p)
+{
+       int r;
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       fputs(p->n_name, io);
+                       if (p->n_lval != 0)
+                               fprintf(io, "+%o", (int)(p->n_lval&0177777));
+               } else
+                       negcon(io, p->n_lval);
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               if (p->n_name[0])
+                       printf("%s%s", p->n_name, p->n_lval ? "+" : "");
+               if (R2TEST(r) && R2UPK3(r) == 0)
+                       printf("*");
+               if (p->n_lval)
+                       negcon(io, p->n_lval);
+               if (R2TEST(r)) {
+                       fprintf(io, "(%s)", rnames[R2UPK1(r)]);
+                       if (R2UPK3(r) == 1)
+                               fprintf(io, "+");
+               } else
+                       fprintf(io, "(%s)", rnames[p->n_rval]);
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               conput(io, p);
+               return;
+
+       case REG:
+               switch (p->n_type) {
+               case LONG:
+               case ULONG:
+                       fprintf(io, "r%c", rnames[p->n_rval][1]);
+                       break;
+               default:
+                       fprintf(io, "%s", rnames[p->n_rval]);
+               }
+               return;
+
+       case UMUL:
+               if (tshape(p, STARNM)) {
+                       printf("*");
+                       adrput(io, p->n_left);
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+static char *
+ccbranches[] = {
+       "jeq",          /* jumpe */
+       "jne",          /* jumpn */
+       "jle",          /* jumple */
+       "jlt",          /* jumpl */
+       "jge",          /* jumpge */
+       "jgt",          /* jumpg */
+       "jlos",         /* jumple (jlequ) */
+       "jlo",          /* jumpl (jlssu) */
+       "jhis",         /* jumpge (jgequ) */
+       "jhi",          /* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("%s      " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+#define        IS1CON(p) ((p)->n_op == ICON && (p)->n_lval == 1)
+
+/*
+ * Move postfix operators to the next statement, unless they are 
+ * within a function call or a branch.
+ */
+static void
+cvtree(NODE *p, struct interpass *ip2)
+{
+       struct interpass *ip;
+       NODE *q;
+
+       if (callop(p->n_op) || p->n_op == CBRANCH)
+               return;
+
+       if ((p->n_op == PLUS || p->n_op == MINUS) &&
+           IS1CON(p->n_right) && (q = p->n_left)->n_op == ASSIGN &&
+           treecmp(q->n_left, q->n_right->n_left) &&
+           IS1CON(q->n_right->n_right)) {
+               if ((p->n_op == PLUS && q->n_right->n_op == MINUS) ||
+                   (p->n_op == MINUS && q->n_right->n_op == PLUS)) {
+                       nfree(p->n_right);
+                       *p = *q->n_left;
+                       if (optype(p->n_op) != LTYPE)
+                               p->n_left = tcopy(p->n_left);
+                       ip = ipnode(q);
+                       DLIST_INSERT_AFTER(ip2, ip, qelem);
+                       return;
+               }
+       }
+       if (optype(p->n_op) == BITYPE)
+               cvtree(p->n_right, ip2);
+       if (optype(p->n_op) != LTYPE)
+               cvtree(p->n_left, ip2);
+}
+
+/*
+ * Convert AND to BIC.
+ */
+static void
+fixops(NODE *p, void *arg)
+{
+       static int fltwritten;
+
+       if (!fltwritten && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
+               printf(".globl  fltused\n");
+               fltwritten = 1;
+       }
+       switch (p->n_op) {
+       case AND:
+               if (p->n_right->n_op == ICON) {
+                       p->n_right->n_lval = ((~p->n_right->n_lval) & 0177777);
+               } else if (p->n_right->n_op == COMPL) {
+                       NODE *q = p->n_right->n_left;
+                       nfree(p->n_right);
+                       p->n_right = q;
+               } else
+                       p->n_right = mkunode(COMPL, p->n_right, 0, p->n_type);
+               break;
+       case RS:
+               p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type);
+               p->n_op = LS;
+               break;
+       case EQ:
+       case NE: /* Hack not to clear bits if FORCC */
+               if (p->n_left->n_op == AND)
+                       fixops(p->n_left, 0); /* Convert an extra time */
+               break;
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+#ifdef PCC_DEBUG
+       if (x2debug) {
+               printf("myreader before\n");
+               printip(ipole);
+       }
+#endif
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, fixops, 0);
+               canon(ip->ip_node); /* call it early */
+       }
+#ifdef PCC_DEBUG
+       if (x2debug) {
+               printf("myreader middle\n");
+               printip(ipole);
+       }
+#endif
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type == IP_NODE)
+                       cvtree(ip->ip_node, ip);
+       }
+#ifdef PCC_DEBUG
+       if (x2debug) {
+               printf("myreader after\n");
+               printip(ipole);
+       }
+#endif
+}
+
+/*
+ * Remove SCONVs where the left node is an OREG with a smaller type.
+ */
+static void
+delsconv(NODE *p, void *arg)
+{
+#if 0
+       NODE *l;
+
+       if (p->n_op != SCONV || (l = p->n_left)->n_op != OREG)
+               return;
+       if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == LONG) {
+               p->n_op = OREG;
+               p->n_lval = l->n_lval; /* high word */
+               p->n_rval = l->n_rval;
+               nfree(l);
+       }
+#endif
+       /* Could do this for char etc. also */
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, delsconv, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+       if (t < LONG || t > BTMASK) {
+               printf("mov%s   %s,%s\n", t < SHORT ? "b" : "",
+                   rnames[s],rnames[d]); /* XXX char should be full reg? */
+       } else if (t == LONG || t == ULONG) {
+               /* avoid trashing double regs */
+               if (d > s)
+                       printf("mov     r%c,r%c\nmov    r%c,r%c\n",
+                           rnames[s][2],rnames[d][2],
+                           rnames[s][1],rnames[d][1]);
+               else
+                       printf("mov     r%c,r%c\nmov    r%c,r%c\n",
+                           rnames[s][1],rnames[d][1],
+                           rnames[s][2],rnames[d][2]);
+       } else if (t == FLOAT || t == DOUBLE) {
+               printf("movf    %s,%s\n", rnames[s],rnames[d]);
+       } else
+               comperr("bad float rmove: %d %d %x", s, d, t);
+
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       switch (c) {
+       case CLASSA:
+               return (r[CLASSB] * 2 + r[CLASSA]) < 5;
+       case CLASSB:
+               if (r[CLASSB] > 1) return 0;
+               if (r[CLASSB] == 1 && r[CLASSA] > 0) return 0;
+               if (r[CLASSA] > 2) return 0;
+               return 1;
+       case CLASSC:
+               return r[CLASSC] < 8;
+       }
+       return 0;
+}
+
+char *rnames[] = {
+       "r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc",
+       "r01", "r12", "r23", "r34", "XXX", "XXX", "XXX", "XXX",
+       "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "XXX", "XXX",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t < LONG || t > BTMASK)
+               return CLASSA;
+       if (t == LONG || t == ULONG)
+               return CLASSB;
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+               return CLASSC;
+       comperr("gclass");
+       return CLASSD;
+}
+
+static int
+argsiz(NODE *p)  
+{
+       TWORD t = p->n_type;
+
+       if (t == LONG || t == ULONG || t == FLOAT)
+               return 4;
+       if (t == DOUBLE)
+               return 8;
+       if (t == STRTY || t == UNIONTY)
+               return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       return 2;
+}
+
+/*
+ * Argument specialties.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       /*
+        * Calculate arg sizes.
+        * Mark first arg not to have - before it.
+        */
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left) {
+               p->n_right->n_qual = 0;
+               size += argsiz(p->n_right);
+       }
+       p->n_qual = 0;
+       size += argsiz(p);
+       p = op->n_right;
+
+       if (p->n_op == CM)
+               p = p->n_right;
+#if 0 /* XXX fixme */
+       if (p->n_type == FLOAT || p->n_type == DOUBLE ||
+           p->n_type == STRTY || p->n_type == UNIONTY)
+               op->n_flags |= NLOCAL1; /* Does not use stack slot */
+       else
+               op->n_flags &= ~NLOCAL1;
+#endif
+       op->n_qual = size; /* XXX */
+}
+
+static int
+is1con(NODE *p)
+{
+       if (p->n_op == ICON && p->n_lval == 1)
+               return 1;
+       return 0;
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       CONSZ s;
+
+       switch (shape) {
+       case SANDSCON:
+               s = ~p->n_lval;
+               if (s < 65536 || s > -65537)
+                       return SRDIR;
+               break;
+       case SINCB: /* Check if subject for post-inc */
+               if (p->n_op == ASSIGN && p->n_right->n_op == PLUS &&
+                   treecmp(p->n_left, p->n_right->n_left) &&
+                   is1con(p->n_right->n_right))
+                       return SRDIR;
+               break;
+       case SARGSUB:
+               if (p->n_op == MINUS && p->n_right->n_op == ICON &&
+                   p->n_left->n_op == REG)
+                       return SRDIR;
+               break;
+       case SARGINC:
+               if (p->n_op == MINUS && is1con(p->n_right))
+                       return special(p->n_left, SINCB);
+               break;
+       }
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       return 0;
+}
+
diff --git a/lang/pcc/pcc/arch/pdp11/macdefs.h b/lang/pcc/pcc/arch/pdp11/macdefs.h
new file mode 100644 (file)
index 0000000..1c8a75c
--- /dev/null
@@ -0,0 +1,235 @@
+/*     $Id: macdefs.h,v 1.11 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = i ? (val<<8)|lastcon : val
+
+#define ARGINIT                32      /* # bits above r5 where arguments start */
+#define AUTOINIT       64      /* # bits below r5 where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         8
+#define SZINT          16
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      64
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     16
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         8
+#define ALINT          16
+#define ALFLOAT                16
+#define ALDOUBLE       16
+#define ALLDOUBLE      16
+#define ALLONG         16
+#define ALLONGLONG     16
+#define ALSHORT                16
+#define ALPOINT                16
+#define ALSTRUCT       16
+#define ALSTACK                16 
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         (-0x7fff-1)
+#define        MAX_INT         0x7fff
+#define        MAX_UNSIGNED    0xffff
+#define        MIN_LONG        (-0x7fffffff-1)
+#define        MAX_LONG        0x7fffffff
+#define        MAX_ULONG       0xffffffff
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+/* Default char is signed */
+#undef CHAR_UNSIGNED
+#define        BOOL_TYPE       CHAR    /* what used to store _Bool */
+
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#define LABFMT "L%d"           /* format for printing labels */
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define        AUTOREG EBP
+#define        ARGREG  EBP
+#define ARGOFFSET 8
+#endif
+
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_LE /* XXX TARGET_PDP */
+#define        MYINSTRING
+#define        MYALIGN
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&01)
+#define wdal(k)                (BYTEOFF(k)==0)
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+
+#define        FINDMOPS        /* pdp11 has instructions that modifies memory */
+
+#define szty(t) ((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG ? 4 : \
+       (t) == FLOAT || (t) == LONG || (t) == ULONG ? 2 : 1)
+
+/*
+ * The pdp11 has 3 register classes, 16-bit, 32-bit and floats.
+ * Class membership and overlaps are defined in the macros RSTATUS
+ * and ROVERLAP below.
+ *
+ * The classes used on pdp11 are:
+ *     A - 16-bit
+ *     B - 32-bit (concatenated 16-bit)
+ *     C - floating point
+ */
+#define        R0      000     /* Scratch and return register */
+#define        R1      001     /* Scratch and secondary return register */
+#define        R2      002     /* Scratch register */
+#define        R3      003     /* Scratch register */
+#define        R4      004     /* Scratch register */
+#define        R5      005     /* Frame pointer */
+#define        SP      006     /* Stack pointer */
+#define        PC      007     /* Program counter */
+
+#define        R01     010
+#define        R12     011
+#define        R23     012
+#define        R34     013
+
+#define        FR0     020
+#define        FR1     021
+#define        FR2     022
+#define        FR3     023
+#define        FR4     024
+#define        FR5     025
+#define        FR6     026
+#define        FR7     027
+
+#define        MAXREGS 030     /* 24 registers */
+
+#define        RSTATUS \
+       SAREG|TEMPREG, SAREG|TEMPREG, SAREG, SAREG, SAREG, 0, 0, 0, \
+       SBREG, SBREG, SBREG, SBREG, 0, 0, 0, 0,         \
+       SCREG, SCREG, SCREG, SCREG, 0, 0, 0, 0
+
+#define        ROVERLAP \
+       /* 8 basic registers */\
+       { R01, -1 },            \
+       { R01, R12, -1 },       \
+       { R12, R23, -1 },       \
+       { R23, R34, -1 },       \
+       { R34, -1 },            \
+       { -1 },                 \
+       { -1 },                 \
+       { -1 },                 \
+\
+       /* 4 long registers */\
+       { R0, R1, R12, -1 },            \
+       { R1, R2, R01, R23, -1 },               \
+       { R2, R3, R12, R34, -1 },               \
+       { R3, R4, R23, -1 },            \
+       { -1 },                 \
+       { -1 },                 \
+       { -1 },                 \
+       { -1 },                 \
+\
+       /* The fp registers do not overlap with anything */\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },\
+       { -1 },
+
+
+/* Return a register class based on the type of the node */
+
+#define PCLASS(p) (p->n_type < LONG || p->n_type > BTMASK ? SAREG : \
+                 (p->n_type == LONG || p->n_type == ULONG ? SBREG : SCREG))
+
+#define        NUMCLASS        3       /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define        GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : CLASSC)
+#define DECRA(x,y)     (((x) >> (y*5)) & 31)   /* decode encoded regs */
+#define        ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)      ((x) << 5)      /* A1 */
+#define ENCRA2(x)      ((x) << 10)     /* A2 */
+#define ENCRA(x,y)     ((x) << (5+y*5))        /* encode regs in int */
+#define        RETREG(x)       ((x) == LONG || (x) == ULONG ? R01 : \
+       (x) == FLOAT || (x) == DOUBLE ? FR0 : R0)
+
+//#define R2REGS       1       /* permit double indexing */
+
+/* XXX - to die */
+#define FPREG  R5      /* frame pointer */
+#define STKREG SP      /* stack pointer */
+
+/* A bunch of specials to make life easier for pdp11 */
+#define        SANDSCON        (MAXSPECIAL+1)
+#define        SINCB           (MAXSPECIAL+2)  /* post-increment */
+#define        SINCW           (MAXSPECIAL+3)  /* post-increment */
+#define        SARGSUB         (MAXSPECIAL+4)  /* arg pointer to array */
+#define        SARGINC         (MAXSPECIAL+5)  /* post-increment arg */
diff --git a/lang/pcc/pcc/arch/pdp11/order.c b/lang/pcc/pcc/arch/pdp11/order.c
new file mode 100644 (file)
index 0000000..15d1588
--- /dev/null
@@ -0,0 +1,249 @@
+/*     $Id: order.c,v 1.3 2008/10/04 08:43:17 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return(0);  /* YES */
+}
+
+static int
+inctree(NODE *p)
+{
+       if (p->n_op == MINUS && p->n_left->n_op == ASSIGN && 
+           p->n_left->n_right->n_op == PLUS &&
+           treecmp(p->n_left->n_left, p->n_left->n_right->n_left) &&
+           p->n_right->n_op == ICON && p->n_right->n_lval == 1 &&
+           p->n_left->n_right->n_right->n_op == ICON &&
+           p->n_left->n_right->n_right->n_lval == 1) {
+               /* post-increment by 1; (r0)+ */
+               if (isreg(p->n_left->n_left)) /* Ignore if index not in reg */
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+       if (p->n_op == UMUL)
+               p = p->n_left; /* double indexed umul */
+
+       if (inctree(p)) /* Do post-inc conversion */
+               return;
+
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if (p->n_right->n_op == ICON) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *p)
+{
+       NODE *q = p->n_left;
+
+       if (x2debug) {
+               printf("myormake(%p)\n", p);
+               fwalk(p, e2print, 0);
+       }
+       if (inctree(q)) {
+               if (q->n_left->n_left->n_op == TEMP)
+                       return;
+               p->n_op = OREG;
+               p->n_lval = 0; /* Add support for index offset */
+               p->n_rval = R2PACK(regno(q->n_left->n_left), 0, 1);
+               tfree(q);
+               return;
+       }
+       if (q->n_op != OREG)
+               return;
+       p->n_op = OREG;
+       p->n_lval = q->n_lval;
+       p->n_rval = R2PACK(q->n_rval, 0, 0);
+       nfree(q);
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       if (p->n_op == NAME && (shape & STARNM))
+               return SRDIR;
+       if (shape & SOREG)
+               return SROREG;  /* Calls offstar */
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return(0);
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case MUL:
+               if (q->visit == INAREG) {
+                       static struct rspecial s[] = { { NLEFT, R1 }, { 0 } };
+                       return s;
+               } else if (q->visit == INBREG) {
+                       static struct rspecial s[] = { { NRES, R01 }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case DIV:
+               if (q->visit == INAREG && q->ltype == TUNSIGNED) {
+                       static struct rspecial s[] = {
+                          { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } };
+                       return s;
+               } else if (q->visit == INAREG) {
+                       static struct rspecial s[] = {
+                           { NRES, R0 }, { 0 } };
+                       return s;
+               } else if (q->visit == INBREG) {
+                       static struct rspecial s[] = { { NRES, R01 }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case MOD:
+               if (q->visit == INAREG && q->ltype == TUNSIGNED) {
+                       static struct rspecial s[] = {
+                          { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } };
+                       return s;
+               } else if (q->visit == INBREG) {
+                       static struct rspecial s[] = { { NRES, R01 }, { 0 } };
+                       return s;
+               }
+               break;
+
+       case SCONV:
+               if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                           { NLEFT, R1 }, { NRES, R01 }, { 0 } };
+                       return s;
+               }
+               break;
+       } 
+       comperr("nspecial entry %d", q - table);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on x86 */
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[] = { -1 };
+
+       return r;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/pdp11/table.c b/lang/pcc/pcc/arch/pdp11/table.c
new file mode 100644 (file)
index 0000000..586b039
--- /dev/null
@@ -0,0 +1,843 @@
+/*     $Id: table.c,v 1.5 2008/10/19 15:25:25 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+# define TLL TLONGLONG|TULONGLONG
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED
+# define TSWORD TINT
+# define TWORD TUWORD|TSWORD
+# define ANYSH SCON|SAREG|SOREG|SNAME
+# define ARONS SAREG|SOREG|SNAME|STARNM
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               "", },
+
+/* convert char to int or unsigned */
+{ SCONV,       INAREG,
+       SAREG,  TCHAR,
+       SAREG,  TINT|TUNSIGNED,
+               NAREG|NASL,     RESC1,
+               "", }, /* chars are stored as ints in registers */
+
+{ SCONV,       INAREG,
+       SOREG|SCON|SNAME,       TCHAR,
+       SAREG,  TINT,
+               NAREG|NASL,     RESC1,
+               "movb   AL,A1\n", },
+
+/* convert uchar to int or unsigned */
+{ SCONV,       INAREG,
+       SAREG|SOREG|SCON|SNAME, TUCHAR,
+       SAREG,  TINT|TUNSIGNED,
+               NAREG,  RESC1,
+               "clr    A1\nbisb        AL,A1\n", },
+
+/* convert (u)int to (u)char.  Nothing to do. */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TCHAR|TUCHAR,
+               0,      RLEFT,
+               "", },
+
+/* convert (u)int to (u)int */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert pointer to (u)int */
+{ SCONV,       INAREG,
+       SAREG,  TPOINT,
+       SANY,   TWORD,
+               0,      RLEFT,
+               "", },
+
+/* convert int to long from memory */
+{ SCONV,       INBREG,
+       SNAME|SOREG,    TINT,
+       SANY,   TLONG,
+               NBREG,  RESC1,
+               "mov    AL,U1\nsxt      A1\n", },
+
+/* int -> (u)long. XXX - only in r0 and r1 */
+{ SCONV,       INBREG,
+       SAREG,  TINT,
+       SANY,   TLONG|TULONG,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "tst    AL\nsxt r0\n", },
+
+/* unsigned -> (u)long. XXX - only in r0 and r1 */
+{ SCONV,       INBREG,
+       SAREG,  TUNSIGNED,
+       SANY,   TLONG|TULONG,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "clr    r0\n", },
+
+/* uint -> double */
+{ SCONV,       INCREG,
+       SAREG|SNAME|SOREG|SCON, TUNSIGNED,
+       SANY,                   TFLOAT|TDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "mov    AL,-(sp)\nclr   -(sp)\n"
+               "setl\nmovif    (sp)+,A1\nseti\n", },
+
+/* long -> int */
+{ SCONV,       INAREG,
+       SBREG|SOREG|SNAME,      TLONG|TULONG,
+       SAREG,                  TWORD,
+               NAREG|NASL,     RESC1,
+               "mov    UL,A1\n", },
+
+
+/* (u)long -> (u)long, nothing */
+{ SCONV,       INBREG,
+       SBREG,  TLONG|TULONG,
+       SANY,   TLONG|TULONG,
+               NBREG|NBSL,     RESC1,
+               "", },
+
+/* long -> double */
+{ SCONV,       INCREG,
+       SBREG|SNAME|SOREG|SCON, TLONG,
+       SANY,           TFLOAT|TDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "mov    UL,-(sp)\nmov   AL,-(sp)\n"
+               "setl\nmovif    (sp)+,A1\nseti\n", },
+
+/*
+ * Subroutine calls.
+ */
+{ CALL,                INBREG,
+       SCON,   TANY,
+       SBREG,  TLONG|TULONG,
+               NBREG|NBSL,     RESC1,
+               "jsr    pc,*CL\nZC", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TLONG|TULONG,
+               NBREG|NBSL,     RESC1,
+               "jsr    pc,*CL\n", },
+
+{ CALL,                FOREFF,
+       SCON|SNAME|SOREG,       TANY,
+       SANY,   TANY,
+               0,      0,
+               "jsr    pc,*AL\nZC", },
+
+{ UCALL,       FOREFF,
+       SCON|SNAME|SOREG,       TANY,
+       SANY,   TANY,
+               0,      0,
+               "jsr    pc,*AL\n", },
+
+{ CALL,                INAREG,
+       SCON|SOREG|SNAME,       TANY,
+       SAREG,  TWORD|TPOINT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "jsr    pc,*AL\nZC", },
+
+{ UCALL,       INAREG,
+       SCON|SOREG|SNAME,       TANY,
+       SAREG,  TWORD|TPOINT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "jsr    pc,*AL\n", },
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "jsr    pc,(AL)\nZC", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "jsr    pc,(AL)\n", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "jsr    pc,(AL)\nZC", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "jsr    pc,(AL)\n", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Add one to anything left but use only for side effects */
+{ PLUS,                FOREFF|INAREG|FORCC,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SONE,                   TANY,
+               0,      RLEFT|RESCC,
+               "inc    AL\n", },
+
+/* add one for char to reg, special handling */
+{ PLUS,                FOREFF|INAREG|FORCC,
+       SAREG,  TCHAR|TUCHAR,
+       SONE,           TANY,
+               0,      RLEFT|RESCC,
+               "inc    AL\n", },
+
+/* add one for char to memory */
+{ PLUS,                FOREFF|FORCC,
+       SNAME|SOREG|STARNM,     TCHAR|TUCHAR,
+       SONE,                   TANY,
+               0,      RLEFT|RESCC,
+               "incb   AL\n", },
+
+{ PLUS,                INBREG|FOREFF,
+       SBREG,                  TLONG,
+       SBREG|SNAME|SOREG|SCON, TLONG,
+               0,      RLEFT,
+               "add    AR,AL\nadd      UR,UL\nadc      AL\n", },
+
+/* Add to reg left and reclaim reg */
+{ PLUS,                INAREG|FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "add    AR,AL\n", },
+
+/* Add to anything left but use only for side effects */
+{ PLUS,                FOREFF|FORCC,
+       SNAME|SOREG,    TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "add    AR,AL\n", },
+
+{ PLUS,                INAREG|FOREFF|FORCC,
+       SAREG,                  TCHAR|TUCHAR,
+       SAREG|SNAME|SOREG|SCON, TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "add    AR,AL\n", },
+
+/* Post-increment read, byte */
+{ MINUS,       INAREG,
+       SINCB,  TCHAR|TUCHAR,
+       SONE,   TANY,
+               NAREG,  RESC1,
+               "movb   ZG,A1\nincb     ZG\n", },
+
+/* Post-increment read, int */
+{ MINUS,       INAREG,
+       SINCB,  TWORD|TPOINT,
+       SONE,   TANY,
+               NAREG,  RESC1,
+               "mov    ZG,A1\ninc      ZG\n", },
+
+{ MINUS,               INBREG|FOREFF,
+       SBREG,                  TLONG|TULONG,
+       SBREG|SNAME|SOREG|SCON, TLONG|TULONG,
+               0,      RLEFT,
+               "sub    AR,AL\nsub      UR,UL\nsbc      AL\n", },
+
+/* Sub one from anything left */
+{ MINUS,       FOREFF|INAREG|FORCC,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SONE,                   TANY,
+               0,      RLEFT|RESCC,
+               "dec    AL\n", },
+
+{ MINUS,               INAREG|FOREFF,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+               0,      RLEFT,
+               "sub    AR,AL\n", },
+
+/* Sub from anything left but use only for side effects */
+{ MINUS,       FOREFF|INAREG|FORCC,
+       SAREG|SNAME|SOREG,      TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "sub    AR,AL\n", },
+
+/* Sub one left but use only for side effects */
+{ MINUS,       FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SONE,                   TANY,
+               0,      RLEFT|RESCC,
+               "decb   AL\n", },
+
+/* Sub from anything left but use only for side effects */
+{ MINUS,               FOREFF|FORCC,
+       SAREG|SNAME|SOREG,      TCHAR|TUCHAR,
+       SAREG|SNAME|SOREG|SCON, TCHAR|TUCHAR|TWORD|TPOINT,
+               0,      RLEFT|RESCC,
+               "subb   AR,AL\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS,  INBREG|FOREFF,
+       SBREG,  TLONG|TULONG,
+       SANY,   TANY,
+               0,      RLEFT,
+               "ashc   AR,AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG,  TWORD,
+       SONE,   TANY,
+               0,      RLEFT,
+               "asl    AL\n", },
+
+{ LS,  INAREG|FOREFF,
+       SAREG,  TWORD,
+       ANYSH,  TWORD,
+               0,      RLEFT,
+               "ash    AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+/* First optimizations, in lack of weight it uses first found */
+/* Start with class A registers */
+
+/* Clear word at address */
+{ ASSIGN,      FOREFF|FORCC,
+       ARONS,  TWORD|TPOINT,
+       SZERO,          TANY,
+               0,      RESCC,
+               "clr    AL\n", },
+
+/* Clear word at reg */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TWORD|TPOINT,
+       SZERO,          TANY,
+               0,      RDEST,
+               "clr    AL\n", },
+
+/* Clear byte at address.  No reg here. */
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG|STARNM,     TCHAR|TUCHAR,
+       SZERO,          TANY,
+               0,      RDEST,
+               "clrb   AL\n", },
+
+/* Clear byte in reg. must clear the whole register. */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TCHAR|TUCHAR,
+       SZERO,  TANY,
+               0,      RDEST,
+               "clr    AL\n", },
+
+/* The next is class B regs */
+
+/* Clear long at address or in reg */
+{ ASSIGN,      FOREFF|INBREG,
+       SNAME|SOREG|SBREG,      TLONG|TULONG,
+       SZERO,                  TANY,
+               0,      RDEST,
+               "clr    AL\nclr UL\n", },
+
+/* Save 2 bytes if high-order bits are zero */
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,  TLONG|TULONG,
+       SSCON,  TLONG,
+               0,      RDEST,
+               "mov    UR,UL\nsxt      AL\n", },
+
+/* Must have multiple rules for long otherwise regs may be trashed */
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,                  TLONG|TULONG,
+       SCON|SNAME|SOREG,       TLONG|TULONG,
+               0,      RDEST,
+               "mov    AR,AL\nmov      UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SNAME|SOREG,    TLONG|TULONG,
+       SBREG,                  TLONG|TULONG,
+               0,      RDEST,
+               "mov    AR,AL\nmov      UR,UL\n", },
+
+{ ASSIGN,      FOREFF,
+       SNAME|SOREG,    TLONG|TULONG,
+       SCON|SNAME|SOREG,       TLONG|TULONG,
+               0,      0,
+               "mov    AR,AL\nmov      UR,UL\n", },
+
+{ ASSIGN,      INBREG|FOREFF,
+       SBREG,  TLONG|TULONG,
+       SBREG,  TLONG|TULONG,
+               0,      RDEST,
+               "ZE\n", },
+
+{ ASSIGN,      FOREFF|INAREG|FORCC,
+       SAREG,                  TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+               0,      RDEST|RESCC,
+               "mov    AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG|FORCC,
+       ARONS,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RDEST|RESCC,
+               "mov    AR,AL\n", },
+
+{ ASSIGN,      FOREFF|FORCC,
+       SNAME|SOREG,            TWORD|TPOINT,
+       SNAME|SOREG|SCON,       TWORD|TPOINT,
+               0,      RESCC,
+               "mov    AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG|FORCC,
+       SAREG,          TCHAR|TUCHAR,
+       ARONS|SCON,     TCHAR|TUCHAR,
+               0,      RDEST|RESCC,
+               "movb   AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG|FORCC,
+       ARONS,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR,
+               0,      RDEST|RESCC,
+               "movb   AR,AL\n", },
+
+{ ASSIGN,      FOREFF|FORCC,
+       SNAME|SOREG|STARNM,             TCHAR|TUCHAR,
+       SNAME|SOREG|SCON|STARNM,        TCHAR|TUCHAR,
+               0,      RDEST|RESCC,
+               "movb   AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SCREG,          TDOUBLE,
+       SNAME|SOREG|SCON,       TDOUBLE,
+               0,      RDEST,
+               "movf   AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SCREG,          TFLOAT,
+       SNAME|SOREG|SCON,       TFLOAT,
+               0,      RDEST,
+               "movof  AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SNAME|SOREG|SCREG,      TDOUBLE,
+       SCREG,                  TDOUBLE,
+               0,      RDEST,
+               "movf   AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SNAME|SOREG|SCREG,      TFLOAT,
+       SCREG,                  TFLOAT,
+               0,      RDEST,
+               "movfo  AR,AL\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* XXX - mul may use any odd register, only r1 for now */
+{ MUL, INAREG,
+       SAREG,                          TWORD|TPOINT,
+       SAREG|SNAME|SOREG|SCON,         TWORD|TPOINT,
+               NSPECIAL,       RLEFT,
+               "mul    AR,AL\n", },
+
+{ MUL, INBREG,
+       SBREG|SNAME|SCON|SOREG,         TLONG|TULONG,
+       SBREG|SNAME|SCON|SOREG,         TLONG|TULONG,
+               NSPECIAL|NBREG|NBSL|NBSR,               RESC1,
+               "mov    UR,-(sp)\nmov   AR,-(sp)\n"
+               "mov    UL,-(sp)\nmov   AL,-(sp)\n"
+               "jsr    pc,lmul\nadd    $10,sp\n", },
+
+{ MUL, INCREG,
+       SCREG,                          TFLOAT|TDOUBLE,
+       SCREG|SNAME|SOREG,              TFLOAT|TDOUBLE,
+               0,      RLEFT,
+               "mulf   AR,AL\n", },
+
+/* need extra move to be sure N flag is correct for sxt */
+{ DIV, INAREG,
+       ANYSH,          TINT|TPOINT,
+       ANYSH,          TINT|TPOINT,
+               NSPECIAL,       RDEST,
+               "mov    AL,r1\nsxt      r0\ndiv AR,r0\n", },
+
+/* udiv uses args in registers */
+{ DIV, INAREG,
+       SAREG,          TUNSIGNED,
+       SAREG,          TUNSIGNED,
+               NSPECIAL|NAREG|NASL|NASR,               RESC1,
+               "jsr    pc,udiv\n", },
+
+{ DIV, INBREG,
+       SBREG|SNAME|SCON|SOREG,         TLONG|TULONG,
+       SBREG|SNAME|SCON|SOREG,         TLONG|TULONG,
+               NSPECIAL|NBREG|NBSL|NBSR,               RESC1,
+               "mov    UR,-(sp)\nmov   AR,-(sp)\n"
+               "mov    UL,-(sp)\nmov   AL,-(sp)\n"
+               "jsr    pc,ldiv\nadd    $10,sp\n", },
+
+{ DIV, INCREG,
+       SCREG,                  TFLOAT|TDOUBLE,
+       SCREG|SNAME|SOREG,      TFLOAT|TDOUBLE,
+               0,      RLEFT,
+               "divf   AR,AL\n", },
+
+/* XXX merge the two below to one */
+{ MOD, INBREG,
+       SBREG|SNAME|SCON|SOREG,         TLONG,
+       SBREG|SNAME|SCON|SOREG,         TLONG,
+               NSPECIAL|NBREG|NBSL|NBSR,               RESC1,
+               "mov    UR,-(sp)\nmov   AR,-(sp)\n"
+               "mov    UL,-(sp)\nmov   AL,-(sp)\n"
+               "jsr    pc,lrem\nadd    $10,sp\n", },
+
+{ MOD, INBREG,
+       SBREG|SNAME|SCON|SOREG,         TULONG,
+       SBREG|SNAME|SCON|SOREG,         TULONG,
+               NSPECIAL|NBREG|NBSL|NBSR,               RESC1,
+               "mov    UR,-(sp)\nmov   AR,-(sp)\n"
+               "mov    UL,-(sp)\nmov   AL,-(sp)\n"
+               "jsr    pc,ulrem\nadd   $10,sp\n", },
+
+/* urem uses args in registers */
+{ MOD, INAREG,
+       SAREG,          TUNSIGNED,
+       SAREG,          TUNSIGNED,
+               NSPECIAL|NAREG|NASL|NASR,               RESC1,
+               "jsr    pc,urem\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,        INBREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TLONG|TULONG,
+               NBREG,  RESC1, /* |NBSL - may overwrite index reg */
+               "mov    AR,A1\nmov      UR,U1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "mov    AR,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,   TANY,
+       SOREG,  TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "movb   AR,A1\n", },
+
+/*
+ * Logical/branching operators
+ */
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME|SCON, TWORD|TPOINT,
+       SZERO,  TANY,
+               0,      RESCC,
+               "tst    AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+       SZERO,  TANY,
+               0,      RESCC,
+               "tstb   AL\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME|SCON, TWORD|TPOINT,
+       SAREG|SOREG|SNAME|SCON, TWORD|TPOINT,
+               0,      RESCC,
+               "cmp    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+       SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+               0,      RESCC,
+               "cmpb   AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SBREG|SOREG|SNAME|SCON, TLONG|TULONG,
+       SZERO,  TANY,
+               0,      RNULL,
+               "ZD", },
+
+{ OPLOG,       FORCC,
+       SBREG|SOREG|SNAME,      TLONG|TULONG,
+       SBREG|SOREG|SNAME,      TLONG|TULONG,
+               0,      RNULL,
+               "ZF", },
+
+/* AND/OR/ER/NOT */
+/* Optimize if high order bits are zero */
+{ AND, FOREFF|INBREG|FORCC,
+       SOREG|SNAME|SBREG,      TLONG|TULONG,
+       SANDSCON,               TLONG|TULONG,
+               0,      RLEFT|RESCC,
+               "clr    AL\nbic UR,UL\n", },
+
+{ AND, INBREG|FORCC,
+       SBREG,                  TLONG|TULONG,
+       SCON|SBREG|SOREG|SNAME, TLONG|TULONG,
+               0,      RLEFT|RESCC,
+               "bic    AR,AL\nbic      UR,UL\n", },
+
+/* set status bits */
+{ AND, FORCC,
+       ARONS|SCON,     TWORD|TPOINT,
+       ARONS|SCON,     TWORD|TPOINT,
+               0,      RESCC,
+               "bit    AR,AL\n", },
+
+/* AND with int */
+{ AND, INAREG|FORCC|FOREFF,
+       SAREG|SNAME|SOREG,      TWORD,
+       SCON|SAREG|SOREG|SNAME, TWORD,
+               0,      RLEFT|RESCC,
+               "bic    AR,AL\n", },
+
+/* AND with char */
+{ AND, INAREG|FORCC,
+       SAREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       ARONS|SCON,             TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "bicb   AR,AL\n", },
+
+{ OR,  INBREG|FORCC,
+       SBREG,                  TLONG|TULONG,
+       SCON|SBREG|SOREG|SNAME, TLONG|TULONG,
+               0,      RLEFT|RESCC,
+               "bis    AR,AL\nbis      UR,UL\n", },
+
+/* OR with int */
+{ OR,  FOREFF|INAREG|FORCC,
+       ARONS,          TWORD,
+       ARONS|SCON,     TWORD,
+               0,      RLEFT|RESCC,
+               "bis    AR,AL\n", },
+
+/* OR with char */
+{ OR,  INAREG|FORCC,
+       SAREG|SOREG|SNAME,      TCHAR|TUCHAR,
+       ARONS|SCON,             TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "bisb   AR,AL\n", },
+
+/* XOR with int (extended insn)  */
+{ ER,  INAREG|FORCC,
+       ARONS,  TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT|RESCC,
+               "xor    AR,AL\n", },
+
+/* XOR with char (extended insn)  */
+{ ER,  INAREG|FORCC,
+       SAREG,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "xor    AR,AL\n", },
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "jbr    LL\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+/* Two bytes less if high half of constant is zero */
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SSCON,  TLONG|TULONG,
+               NBREG,  RESC1,
+               "mov    UL,U1\nsxt      A1\n", },
+
+/* XXX - avoid OREG index register to be overwritten */
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SCON|SBREG|SNAME|SOREG, TLONG|TULONG,
+               NBREG,  RESC1,
+               "mov    AL,A1\nmov      UL,U1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TWORD|TPOINT,
+               NAREG|NASR,     RESC1,
+               "mov    AL,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TCHAR,
+               NAREG,          RESC1,
+               "movb   AR,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG|SCON|SOREG|SNAME, TUCHAR,
+               NAREG,          RESC1,
+               "clr    A1\nbisb        AL,A1\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TANY,
+       SCREG|SCON|SOREG|SNAME, TDOUBLE,
+               NCREG,          RESC1,
+               "movf   AL,A1\n", },
+
+{ OPLTYPE,     INCREG,
+       SANY,   TANY,
+       SCREG|SCON|SOREG|SNAME, TFLOAT,
+               NCREG,          RESC1,
+               "movof  AL,A1\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS,      INAREG|FOREFF,
+       SAREG,  TWORD|TPOINT|TCHAR|TUCHAR,
+       SANY,   TANY,
+               0,      RLEFT,
+               "neg    AL\n", },
+
+{ UMINUS,      INBREG|FOREFF,
+       SBREG|SOREG|SNAME,      TLONG,
+       SANY,                   TANY,
+               0,      RLEFT,
+               "neg    AL\nneg UL\nsbc AL\n", },
+
+
+{ COMPL,       INBREG,
+       SBREG,  TLONG|TULONG,
+       SANY,   TANY,
+               0,      RLEFT,
+               "com    AL\ncom UL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TWORD,
+       SANY,   TANY,
+               0,      RLEFT,
+               "com    AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,      FOREFF,
+       SCON|SBREG|SNAME|SOREG, TLONG|TULONG,
+       SANY,   TLONG|TULONG,
+               0,      RNULL,
+               "mov    UL,ZA(sp)\nmov  AL,-(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SZERO,  TANY,
+       SANY,   TANY,
+               0,      RNULL,
+               "clr    ZA(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SARGSUB,        TWORD|TPOINT,
+       SANY,           TWORD|TPOINT,
+               0,      RNULL,
+               "ZB", },
+
+{ FUNARG,      FOREFF,
+       SARGINC,        TWORD|TPOINT,
+       SANY,           TWORD|TPOINT,
+               0,      RNULL,
+               "ZH", },
+
+{ FUNARG,      FOREFF,
+       SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+       SANY,   TWORD|TPOINT,
+               0,      RNULL,
+               "mov    AL,ZA(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SCON,   TCHAR|TUCHAR,
+       SANY,   TANY,
+               0,      RNULL,
+               "mov    AL,ZA(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SOREG,    TCHAR,
+       SANY,           TCHAR,
+               NAREG,  RNULL,
+               "movb   AL,A1\nmov      A1,ZA(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SNAME|SOREG,    TUCHAR,
+       SANY,           TUCHAR,
+               NAREG,  RNULL,
+               "clr    ZA(sp)\nbisb    AL,(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SAREG,  TUCHAR|TCHAR,
+       SANY,   TUCHAR|TCHAR,
+               0,      RNULL,
+               "mov    AL,ZA(sp)\n", },
+
+{ FUNARG,      FOREFF,
+       SCREG,  TFLOAT|TDOUBLE,
+       SANY,           TANY,
+               0,      RNULL,
+               "movf   AL,ZA(sp)\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/powerpc/README b/lang/pcc/pcc/arch/powerpc/README
new file mode 100644 (file)
index 0000000..d3c8678
--- /dev/null
@@ -0,0 +1,48 @@
+macdefs.h              ; machine-dependent definitions
+code.c                 ; machine-dependent code for prologs, switches (pass 1)
+local.c                        ; machine-dependent code for prologs, switches (pass 1)
+local2.c               ; misc routines and tables of register names (pass 2)
+order.c                        ; machine-dependent code-generation strategy (pass 2)
+table.c                        ; code templates (pass 2)
+
+On OS X, binaries are not ELF and all binaries are compiled PIC.  To use pcc
+on OS X while linking against the system libraries, use the -k option.
+
+Current issues:
+
+- no floating point (need mickey's patches to support >64 registers)
+- mod/div on longlong not supported
+- the stack frame is always 200 bytes - need to calculate size and patch
+  OREGs to temporaries and arguments [see discussion below]
+- function arguments are always saved to the stack [need to change MI code]
+- permanent registers >R13 are not saved [need to change MI code]
+- structure arguments don't work
+- return of structure doesn't work
+- function pointers don't work for PIC
+- constant structure assignment doesn't work properly for PIC
+- no built-in vararg support [shouldn't be too hard to add]
+
+The way most modern CPUs create the stack is to allocate the frame
+to contain room for the temporaries, to save the permanent registers
+and to store the arguments to functions invoked from within the function.
+To achieve this, all the information must be known when the prologue
+is generated.  Currently we only know the size of the temporaries -
+we don't know the size of the argument space for each function that
+gets invoked from this function.  Even if we did know this information,
+we create ops to save the register arguments (R3-R10), early in pass1
+and don't know the position of the stack pointer, and the size of the
+argument space required to "step over".
+
+One solution is to have two pointers to the stack.  One for the top
+of the stack and the other pointing just below the temporaries but above
+the argument space.  Then our function arguments and the permanent registers can
+be saved fixed-relative to this register.  If we don't know the size of
+argument space, we cannot "dynamically" alter the stack (like we do with mips),
+since the powerpc ABI specifies that the "lowest" address
+in the stack frame is the saved stack pointer (pointing to the previous
+stack frame).  While this is a nice feature for tracking back through the
+stack frames (which mips has always had problems with), it makes it
+next-to-impossible to increase the strack frame dynamically.
+
+I guess the best approach is to determine the size of the argument stack
+and have a second frame pointer.
diff --git a/lang/pcc/pcc/arch/powerpc/code.c b/lang/pcc/pcc/arch/powerpc/code.c
new file mode 100644 (file)
index 0000000..e306ff1
--- /dev/null
@@ -0,0 +1,1543 @@
+/*     $Id: code.c,v 1.31 2014/05/29 19:20:03 plunky Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+static void genswitch_bintree(int num, TWORD ty, struct swents **p, int n);
+
+#if 0
+static void genswitch_table(int num, struct swents **p, int n);
+static void genswitch_mrst(int num, struct swents **p, int n);
+#endif
+
+static int rvnr;
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case UDATA: break;
+#ifdef MACHOABI
+       case PICLDATA:
+       case PICDATA: name = ".section .data.rel.rw,\"aw\""; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break;
+       case STRNG: name = ".cstring"; break;
+       case RDATA: name = ".const_data"; break;
+#else
+       case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break;
+       case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
+       case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
+       case STRNG:
+#ifdef AOUTABI
+       case RDATA: name = ".data"; break;
+#else
+       case RDATA: name = ".section .rodata"; break;
+#endif
+#endif
+       case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
+       case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
+       case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
+       case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+void
+defalign(int al)
+{
+       if (ispow2(al/ALCHAR))
+               printf("\t.p2align %d\n", ispow2(al/ALCHAR));
+}
+
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       name = sp->soname ? sp->soname : exname(sp->sname);
+       if (sp->sclass == EXTDEF)
+               printf("        .globl %s\n", name);
+       if (sp->slevel == 0)
+               printf("%s:\n", name);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers
+ */
+static void
+putintemp(struct symtab *sym)
+{
+        NODE *p;
+
+        p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+        p = buildtree(ASSIGN, p, nametree(sym));
+        sym->soffset = regno(p->n_left);
+        sym->sflags |= STNODE;
+        ecomp(p);
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+        int argofs = *argofsp;
+        NODE *p, *q;
+        int navail;
+
+#if ALLONGLONG == 64
+        /* alignment */
+        ++argofs;
+        argofs &= ~1;
+#endif
+
+        navail = NARGREGS - argofs;
+
+        if (navail < 2) {
+               /* half in and half out of the registers */
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               regno(q) = R3 + argofs;
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               regno(p) = FPREG;
+               p = block(PLUS, p, bcon(sym->soffset/SZCHAR), PTR+INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+        } else {
+               q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+               regno(q) = R3R4 + argofs;
+               if (dotemps) {
+                       p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+                       sym->soffset = regno(p);
+                       sym->sflags |= STNODE;
+               } else {
+                       p = nametree(sym);
+               }
+       }
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+        *argofsp = argofs + 2;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q;
+
+        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+        regno(q) = R3 + (*argofsp)++;
+        if (dotemps) {
+                p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+                sym->soffset = regno(p);
+                sym->sflags |= STNODE;
+        } else {
+                p = nametree(sym);
+        }
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+}
+
+/* setup a double param on the stack
+ * used by bfcode() */
+static void
+param_double(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q, *t;
+        int tmpnr;
+
+        /*
+         * we have to dump the double from the general register
+         * into a temp, since the register allocator doesn't like
+         * floats to be in CLASSA.  This may not work for -xtemps.
+         */
+
+       if (xtemps) {
+               q = block(REG, NIL, NIL, ULONGLONG, 0, 0);
+               regno(q) = R3R4 + *argofsp;
+               p = block(REG, NIL, NIL, PTR+ULONGLONG, 0, 0);
+               regno(p) = SPREG;
+               p = block(PLUS, p, bcon(-8), INT, 0, 0);
+               p = block(UMUL, p, NIL, ULONGLONG, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       
+               t = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               tmpnr = regno(t);
+               p = block(REG, NIL, NIL,
+                   INCREF(sym->stype), sym->sdf, sym->sap);
+               regno(p) = SPREG;
+               p = block(PLUS, p, bcon(-8), INT, 0, 0);
+               p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap);
+               p = buildtree(ASSIGN, t, p);
+               ecomp(p);
+       } else {
+               /* bounce straight into temp */
+               p = block(REG, NIL, NIL, ULONGLONG, 0, 0);
+               regno(p) = R3R4 + *argofsp;
+               t = tempnode(0, ULONGLONG, 0, 0);
+               tmpnr = regno(t);
+               p = buildtree(ASSIGN, t, p);
+               ecomp(p);
+       }
+
+       (*argofsp) += 2;
+       
+       sym->soffset = tmpnr;
+       sym->sflags |= STNODE;
+}
+
+/* setup a float param on the stack
+ * used by bfcode() */
+static void
+param_float(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q, *t;
+        int tmpnr;
+
+        /*
+         * we have to dump the float from the general register
+         * into a temp, since the register allocator doesn't like
+         * floats to be in CLASSA.  This may not work for -xtemps.
+         */
+
+       if (xtemps) {
+               /* bounce onto TOS */
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               regno(q) = R3 + (*argofsp);
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               regno(p) = SPREG;
+               p = block(PLUS, p, bcon(-4), INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+
+               t = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               tmpnr = regno(t);
+               p = block(REG, NIL, NIL, INCREF(sym->stype),
+                   sym->sdf, sym->sap);
+               regno(p) = SPREG;
+               p = block(PLUS, p, bcon(-4), INT, 0, 0);
+               p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap);
+               p = buildtree(ASSIGN, t, p);
+               ecomp(p);
+       } else {
+               /* bounce straight into temp */
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               regno(p) = R3 + (*argofsp);
+               t = tempnode(0, INT, 0, 0);
+               tmpnr = regno(t);
+               p = buildtree(ASSIGN, t, p);
+               ecomp(p);
+       }
+
+       (*argofsp)++;
+
+       sym->soffset = tmpnr;
+       sym->sflags |= STNODE;
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retstruct(void)
+{
+       NODE *p, *q;
+
+       p = tempnode(0, INCREF(cftnsp->stype), 0, cftnsp->sap);
+       rvnr = regno(p);
+       q = block(REG, NIL, NIL, INCREF(cftnsp->stype),
+           cftnsp->sdf, cftnsp->sap);
+       regno(q) = R3;
+       p = buildtree(ASSIGN, p, q);
+       ecomp(p);
+}
+
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *argofsp)
+{
+        int argofs = *argofsp;
+        NODE *p, *q;
+        int navail;
+        int sz;
+        int off;
+        int num;
+        int i;
+
+        navail = NARGREGS - argofs;
+        sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
+        off = ARGINIT/SZINT + argofs;
+        num = sz > navail ? navail : sz;
+        for (i = 0; i < num; i++) {
+                q = block(REG, NIL, NIL, INT, 0, 0);
+                regno(q) = R3 + argofs++;
+                p = block(REG, NIL, NIL, INT, 0, 0);
+                regno(p) = SPREG;
+                p = block(PLUS, p, bcon(4*off++), INT, 0, 0);
+                p = block(UMUL, p, NIL, INT, 0, 0);
+                p = buildtree(ASSIGN, p, q);
+                ecomp(p);
+        }
+
+        *argofsp = argofs;
+}
+
+/*
+ * code for the beginning of a function
+ * sp is an array of indices in symtab for the arguments
+ * cnt is the number of arguments
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+#ifdef USE_GOTNR
+       extern int gotnr;
+#endif
+
+       struct symtab *sp2;
+       union arglist *usym;
+       int saveallargs = 0;
+       int i, argofs = 0;
+
+        /*
+         * Detect if this function has ellipses and save all
+         * argument registers onto stack.
+         */
+        usym = cftnsp->sdf->dfun;
+        while (usym && usym->type != TNULL) {
+                if (usym->type == TELLIPSIS) {
+                        saveallargs = 1;
+                        break;
+                }
+                ++usym;
+        }
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               param_retstruct();
+               ++argofs;
+       }
+
+#ifdef USE_GOTNR
+       if (kflag) {
+               /* put GOT register into temporary */
+               NODE *q, *p;
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               regno(q) = GOTREG;
+               p = tempnode(0, INT, 0, 0);
+               gotnr = regno(p);
+               ecomp(buildtree(ASSIGN, p, q));
+       }
+#endif
+
+        /* recalculate the arg offset and create TEMP moves */
+        for (i = 0; i < cnt; i++) {
+
+               if (sp[i] == NULL)
+                       continue;
+
+                if ((argofs >= NARGREGS) && !xtemps)
+                        break;
+
+                if (argofs >= NARGREGS) {
+                        putintemp(sp[i]);
+                } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
+                        param_struct(sp[i], &argofs);
+                } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
+                        param_64bit(sp[i], &argofs, xtemps && !saveallargs);
+                } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
+                       if (features(FEATURE_HARDFLOAT))
+                               param_double(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+                       else
+                               param_64bit(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+                } else if (sp[i]->stype == FLOAT) {
+                       if (features(FEATURE_HARDFLOAT))
+                               param_float(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+                       else
+                               param_32bit(sp[i], &argofs,
+                                   xtemps && !saveallargs);
+                } else {
+                        param_32bit(sp[i], &argofs, xtemps && !saveallargs);
+               }
+        }
+
+        /* if saveallargs, save the rest of the args onto the stack */
+        while (saveallargs && argofs < NARGREGS) {
+               NODE *p, *q;
+               /* int off = (ARGINIT+FIXEDSTACKSIZE*SZCHAR)/SZINT + argofs; */
+               int off = ARGINIT/SZINT + argofs;
+               q = block(REG, NIL, NIL, INT, 0, 0);
+               regno(q) = R3 + argofs++;
+               p = block(REG, NIL, NIL, INT, 0, 0);
+               regno(p) = FPREG;
+               p = block(PLUS, p, bcon(4*off), INT, 0, 0);
+               p = block(UMUL, p, NIL, INT, 0, 0);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+
+       /* profiling */
+       if (pflag) {
+               NODE *p;
+
+#if defined(ELFABI)
+
+               sp2 = lookup("_mcount", 0);
+               sp2->stype = EXTERN;
+               p = nametree(sp2);
+               p->n_sp->sclass = EXTERN;
+               p = clocal(p);
+               p = buildtree(ADDROF, p, NIL);
+               p = block(UCALL, p, NIL, INT, 0, 0);
+               ecomp(funcode(p));
+
+
+#elif defined(MACHOABI)
+
+               NODE *q;
+               int tmpnr;
+
+                q = block(REG, NIL, NIL, INT, 0, 0);
+                regno(q) = R0;
+               p = tempnode(0, INT, 0, 0);
+               tmpnr = regno(p);
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+
+               q = tempnode(tmpnr, INT, 0, 0);
+
+               sp2 = lookup("mcount", 0);
+               sp2->stype = EXTERN;
+               p = nametree(sp2);
+               p->n_sp->sclass = EXTERN;
+               p = clocal(p);
+               p = buildtree(ADDROF, p, NIL);
+               p = block(CALL, p, q, INT, 0, 0);
+               ecomp(funcode(p));
+
+#endif
+       }
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode(void)
+{
+        NODE *p, *q;
+        int tempnr;
+        int ty;
+
+#ifdef USE_GOTNR
+       extern int gotnr;
+       gotnr = 0;
+#endif
+
+        if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+                return;
+
+        ty = cftnsp->stype - FTN;
+
+        q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+        regno(q) = R3;
+        p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
+        tempnr = regno(p);
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+
+        q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
+        q = buildtree(UMUL, q, NIL);
+
+        p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+        p = buildtree(UMUL, p, NIL);
+
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+
+        q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+        p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+        regno(p) = R3;
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+}
+
+struct stub stublist;
+struct stub nlplist;
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag)
+{
+
+#if defined(MACHOABI)
+       /*
+        * iterate over the stublist and output the PIC stubs
+`       */
+       if (kflag) {
+               struct stub *p;
+
+               DLIST_FOREACH(p, &stublist, link) {
+                       printf("\t.section __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n");
+                       printf("\t.align 5\n");
+                       printf("L%s$stub:\n", p->name);
+                       if (strcmp(p->name, "mcount") == 0)
+                               printf("\t.indirect_symbol %s\n", p->name);
+                       else
+                               printf("\t.indirect_symbol %s\n", p->name);
+                       printf("\tmflr r0\n");
+                       printf("\tbcl 20,31,L%s$spb\n", p->name);
+                       printf("L%s$spb:\n", p->name);
+                       printf("\tmflr r11\n");
+                       printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$spb)\n",
+                           p->name, p->name);
+                       printf("\tmtlr r0\n");
+                       printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$spb)(r11)\n",
+                           p->name, p->name);
+                       printf("\tmtctr r12\n");
+                       printf("\tbctr\n");
+                       printf("\t.lazy_symbol_pointer\n");
+                       printf("L%s$lazy_ptr:\n", p->name);
+                       if (strcmp(p->name, "mcount") == 0)
+                               printf("\t.indirect_symbol %s\n", p->name);
+                       else
+                               printf("\t.indirect_symbol %s\n", p->name);
+                       printf("\t.long dyld_stub_binding_helper\n");
+                       printf("\t.subsections_via_symbols\n");
+               }
+
+               printf("\t.non_lazy_symbol_pointer\n");
+               DLIST_FOREACH(p, &nlplist, link) {
+                       printf("L%s$non_lazy_ptr:\n", p->name);
+                       if (strcmp(p->name, "mcount") == 0)
+                               printf("\t.indirect_symbol %s\n", p->name);
+                       else
+                               printf("\t.indirect_symbol %s\n", p->name);
+                       printf("\t.long 0\n");
+               }
+
+       }
+#endif
+
+#ifndef os_darwin
+       printf("\t.ident \"PCC: %s\"\n", VERSSTR);
+#endif
+
+}
+
+void
+bjobcode(void)
+{
+       DLIST_INIT(&stublist, link);
+       DLIST_INIT(&nlplist, link);
+}
+
+#ifdef notdef
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+       static  int     lastoctal = 0;
+
+       /* put byte i+1 in a string */
+
+       if (t < 0) {
+               if (i != 0)
+                       puts("\"");
+       } else {
+               if (i == 0)
+                       printf("\t.ascii \"");
+               if (t == '\\' || t == '"') {
+                       lastoctal = 0;
+                       putchar('\\');
+                       putchar(t);
+               } else if (t < 040 || t >= 0177) {
+                       lastoctal++;
+                       printf("\\%o",t);
+               } else if (lastoctal && '0' <= t && t <= '9') {
+                       lastoctal = 0;
+                       printf("\"\n\t.ascii \"%c", t);
+               } else {        
+                       lastoctal = 0;
+                       putchar(t);
+               }
+       }
+}
+#endif
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       if (num < 0) {
+               genswitch_bintree(num, type, p, n);
+               return 1;
+       }
+
+       return 0;
+
+#if 0
+       if (0)
+       genswitch_table(num, p, n);
+       if (0)
+       genswitch_bintree(num, p, n);
+       genswitch_mrst(num, p, n);
+#endif
+}
+
+static void bintree_rec(TWORD ty, int num,
+       struct swents **p, int n, int s, int e);
+
+static void
+genswitch_bintree(int num, TWORD ty, struct swents **p, int n)
+{
+       int lab = getlab();
+
+       if (p[0]->slab == 0)
+               p[0]->slab = lab;
+
+       bintree_rec(ty, num, p, n, 1, n);
+
+       plabel(lab);
+}
+
+static void
+bintree_rec(TWORD ty, int num, struct swents **p, int n, int s, int e)
+{
+       NODE *r;
+       int rlabel;
+       int h;
+
+       if (s == e) {
+               r = tempnode(num, ty, 0, 0);
+               r = buildtree(NE, r, bcon(p[s]->sval));
+               cbranch(buildtree(NOT, r, NIL), bcon(p[s]->slab));
+               branch(p[0]->slab);
+               return;
+       }
+
+       rlabel = getlab();
+
+       h = s + (e - s) / 2;
+
+       r = tempnode(num, ty, 0, 0);
+       r = buildtree(GT, r, bcon(p[h]->sval));
+       cbranch(r, bcon(rlabel));
+       bintree_rec(ty, num, p, n, s, h);
+       plabel(rlabel);
+       bintree_rec(ty, num, p, n, h+1, e);
+}
+
+
+#if 0
+
+static void
+genswitch_table(int num, struct swents **p, int n)
+{
+       NODE *r, *t;
+       int tval;
+       int minval, maxval, range;
+       int deflabel, tbllabel;
+       int i, j;
+
+       minval = p[1]->sval;
+       maxval = p[n]->sval;
+
+       range = maxval - minval + 1;
+
+       if (n < 10 || range > 3 * n) {
+               /* too small or too sparse for jump table */
+               genswitch_simple(num, p, n);
+               return;
+       }
+
+       r = tempnode(num, UNSIGNED, 0, 0);
+       r = buildtree(MINUS, r, bcon(minval));
+       t = tempnode(0, UNSIGNED, 0, 0);
+       tval = regno(t);
+       r = buildtree(ASSIGN, t, r);
+       ecomp(r);
+
+       deflabel = p[0]->slab;
+       if (deflabel == 0)
+               deflabel = getlab();
+
+       t = tempnode(tval, UNSIGNED, 0, 0);
+       cbranch(buildtree(GT, t, bcon(maxval-minval)), bcon(deflabel));
+
+       tbllabel = getlab();
+       struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP);
+       strtbl->soffset = tbllabel;
+       strtbl->sclass = ILABEL;
+       strtbl->stype = INCREF(UCHAR);
+
+       t = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
+       t->n_sp = strtbl;
+       t = buildtree(ADDROF, t, NIL);
+       r = tempnode(tval, UNSIGNED, 0, 0);
+       r = buildtree(PLUS, t, r);
+       t = tempnode(0, INCREF(UNSIGNED), 0, 0);
+       r = buildtree(ASSIGN, t, r);
+       ecomp(r);
+
+       r = tempnode(regno(t), INCREF(UNSIGNED), 0, 0);
+       r = buildtree(UMUL, r, NIL);
+       t = block(NAME, NIL, NIL, UCHAR, 0, 0);
+       t->n_sp = strtbl;
+       t = buildtree(ADDROF, t, NIL);
+       r = buildtree(PLUS, t, r);
+       r = block(GOTO, r, NIL, 0, 0, 0);
+       ecomp(r);
+
+       plabel(tbllabel);
+       for (i = minval, j=1; i <= maxval; i++) {
+               char *entry = tmpalloc(20);
+               int lab = deflabel;
+               //printf("; minval=%d, maxval=%d, i=%d, j=%d p[j]=%lld\n", minval, maxval, i, j, p[j]->sval);
+               if (p[j]->sval == i) {
+                       lab = p[j]->slab;
+                       j++;
+               }
+               snprintf(entry, 20, "\t.long " LABFMT "-" LABFMT "\n", lab, tbllabel);
+               send_passt(IP_ASM, entry);
+       }
+
+       if (p[0]->slab <= 0)
+               plabel(deflabel);
+}
+
+#define DPRINTF(x)     if (xdebug) printf x
+//#define DPRINTF(x)   do { } while(0)
+
+#define MIN_TABLE_SIZE 8
+
+/*
+ *  Multi-way Radix Search Tree (MRST)
+ */
+
+static void mrst_rec(int num, struct swents **p, int n, int *state, int lab);
+static unsigned long mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit);
+void mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, int tbllabel, int lab, unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit);
+
+static void
+genswitch_mrst(int num, struct swents **p, int n)
+{
+       int *state;
+       int i;
+       int putlabel = 0;
+
+       if (n < 10) {
+               /* too small for MRST */
+               genswitch_simple(num, p, n);
+               return;
+       }
+
+       state = tmpalloc((n+1)*sizeof(int));
+       for (i = 0; i <= n; i++)
+               state[i] = 0;
+
+       if (p[0]->slab == 0) {
+               p[0]->slab = getlab();
+               putlabel = 1;
+       }
+
+       mrst_rec(num, p, n, state, 0);
+
+       if (putlabel)
+               plabel(p[0]->slab);
+}
+
+
+/*
+ *  Look through the cases and generate a table or
+ *  list of simple comparisons.  If generating a table,
+ *  invoke mrst_put_entry_and_recurse() to put
+ *  an entry in the table and recurse.
+ */
+static void
+mrst_rec(int num, struct swents **p, int n, int *state, int lab)
+{
+       int len, lowbit;
+       unsigned long Wmax;
+       unsigned int tblsize;
+       NODE *t;
+       NODE *r;
+       int tval;
+       int i;
+
+       DPRINTF(("mrst_rec: num=%d, n=%d, lab=%d\n", num, n, lab));
+
+       /* find best window to cover set*/
+       Wmax = mrst_find_window(p, n, state, lab, &len, &lowbit);
+       tblsize = (1 << len);
+       assert(len > 0 && tblsize > 0);
+
+       DPRINTF(("mrst_rec: Wmax=%lu, lowbit=%d, tblsize=%u\n",
+               Wmax, lowbit, tblsize));
+
+       if (lab)
+               plabel(lab);
+
+       if (tblsize <= MIN_TABLE_SIZE) {
+               DPRINTF(("msrt_rec: break the recursion\n"));
+               for (i = 1; i <= n; i++) {
+                       if (state[i] == lab) {
+                               t = tempnode(num, UNSIGNED, 0, 0);
+                               cbranch(buildtree(EQ, t, bcon(p[i]->sval)),
+                                   bcon(p[i]->slab));
+                       }
+               }
+               branch(p[0]->slab);
+               return;
+       }
+
+       DPRINTF(("generating table with %d elements\n", tblsize));
+
+       // AND with Wmax
+       t = tempnode(num, UNSIGNED, 0, 0);
+       r = buildtree(AND, t, bcon(Wmax));
+
+       // RS lowbits
+       r = buildtree(RS, r, bcon(lowbit));
+
+       t = tempnode(0, UNSIGNED, 0, 0);
+       tval = regno(t);
+       r = buildtree(ASSIGN, t, r);
+       ecomp(r);
+
+       int tbllabel = getlab();
+       struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP);
+       strtbl->sclass = STATIC;
+       strtbl->sap = 0;
+       strtbl->slevel = 1;
+       strtbl->soffset = tbllabel;
+       strtbl->stype = INCREF(UCHAR);
+       strtbl->squal = (CON >> TSHIFT);
+
+       t = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
+       t->n_sp = strtbl;
+       t = buildtree(ADDROF, t, NIL);
+       r = tempnode(tval, UNSIGNED, 0, 0);
+       r = buildtree(PLUS, t, r);
+       t = tempnode(0, INCREF(UNSIGNED), 0, 0);
+       r = buildtree(ASSIGN, t, r);
+       ecomp(r);
+
+       r = tempnode(regno(t), INCREF(UNSIGNED), 0, 0);
+       r = buildtree(UMUL, r, NIL);
+       t = block(NAME, NIL, NIL, UCHAR, 0, 0);
+       t->n_sp = strtbl;
+       t = buildtree(ADDROF, t, NIL);
+       r = buildtree(PLUS, t, r);
+       r = block(GOTO, r, NIL, 0, 0, 0);
+       ecomp(r);
+
+       plabel(tbllabel);
+       
+       mrst_put_entry_and_recurse(num, p, n, state, tbllabel, lab,
+               0, tblsize, Wmax, lowbit);
+}
+
+
+/*
+ * Put an entry into the table and recurse to the next entry
+ * in the table.  On the way back through the recursion, invoke
+ * mrst_rec() to check to see if we should generate another
+ * table.
+ */
+void
+mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state,
+       int tbllabel, int labval,
+       unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit)
+{
+       int i;
+       int found = 0;
+       int lab = getlab();
+
+       /*
+        *  Look for labels which map to this table entry.
+        *  Mark each one in "state" that they fall inside this table.
+        */
+       for (i = 1; i <= n; i++) {
+               unsigned int val = (p[i]->sval & Wmax) >> lowbit;
+               if (val == j && state[i] == labval) {
+                       found = 1;
+                       state[i] = lab;
+               }
+       }
+
+       /* couldn't find any labels?  goto the default label */
+       if (!found)
+               lab = p[0]->slab;
+
+       /* generate the table entry */
+       char *entry = tmpalloc(20);
+       snprintf(entry, 20, "\t.long " LABFMT "-" LABFMT "\n", lab, tbllabel);
+       send_passt(IP_ASM, entry);
+
+       DPRINTF(("mrst_put_entry: table=%d, pos=%lu/%lu, label=%d\n",
+           tbllabel, j, tblsize, lab));
+
+       /* go to the next table entry */
+       if (j+1 < tblsize) {
+               mrst_put_entry_and_recurse(num, p, n, state, tbllabel, labval,
+                       j+1, tblsize, Wmax, lowbit);
+       }
+
+       /* if we are going to the default label, bail now */
+       if (!found)
+               return;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("state: ");
+               for (i = 1; i <= n; i++)
+                       printf("%d ", state[i]);
+               printf("\n");
+       }
+#endif
+
+       /* build another table */
+       mrst_rec(num, p, n, state, lab);
+}
+
+/*
+ * counts the number of entries in a table of size (1 << L) which would
+ * be used given the cases and the mask (W, lowbit).
+ */
+static unsigned int
+mrst_cardinality(struct swents **p, int n, int *state, int step, unsigned long W, int L, int lowbit)
+{
+       unsigned int count = 0;
+       int i;
+
+       if (W == 0)
+               return 0;
+
+       int *vals = (int *)calloc(1 << L, sizeof(int));
+       assert(vals);
+
+       DPRINTF(("mrst_cardinality: "));
+       for (i = 1; i <= n; i++) {
+               int idx;
+               if (state[i] != step)
+                       continue;
+               idx = (p[i]->sval & W) >> lowbit;
+               DPRINTF(("%llu->%d, ", p[i]->sval, idx));
+               if (!vals[idx]) {
+                       count++;
+               }
+               vals[idx] = 1;
+       }
+       DPRINTF((": found %d entries\n", count));
+       free(vals);
+
+       return count;
+}
+
+/*
+ *  Find the maximum window (table size) which would best cover
+ *  the set of labels.  Algorithm explained in:
+ *
+ *  Ulfar Erlingsson, Mukkai Krishnamoorthy and T.V. Raman.
+ *  Efficient Multiway Radix Search Trees.
+ *  Information Processing Letters 60:3 115-120 (November 1996)
+ */
+
+static unsigned long
+mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit)
+{
+       unsigned int tblsize;
+       unsigned long W = 0;
+       unsigned long Wmax = 0;
+       unsigned long Wleft = (1 << (SZLONG-1));
+       unsigned int C = 0;
+       unsigned int Cmax = 0;
+       int L = 0;
+       int Lmax = 0;
+       int lowmax = 0;
+       int no_b = SZLONG-1;
+       unsigned long b = (1 << (SZLONG-1));
+
+       DPRINTF(("mrst_find_window: n=%d, lab=%d\n", n, lab));
+
+       for (; b > 0; b >>= 1, no_b--) {
+
+               // select the next bit
+               W |= b;
+               L += 1;
+
+               tblsize = 1 << L;
+               assert(tblsize > 0);
+
+               DPRINTF(("no_b=%d, b=0x%lx, Wleft=0x%lx, W=0x%lx, Wmax=0x%lx, L=%d, Lmax=%d, Cmax=%u, lowmax=%d, tblsize=%u\n", no_b, b, Wleft, W, Wmax, L, Lmax, Cmax, lowmax, tblsize));
+
+               C = mrst_cardinality(p, n, state, lab, W, L, no_b);
+               DPRINTF((" -> cardinality is %d\n", C));
+
+               if (2*C >= tblsize) {
+                       DPRINTF(("(found good match, keep adding to table)\n"));
+                       Wmax = W;
+                       Lmax = L;
+                       lowmax = no_b;
+                       Cmax = C;
+               } else {
+                       DPRINTF(("(too sparse)\n"));
+                       assert((W & Wleft) != 0);
+
+                       /* flip the MSB and see if we get a better match */
+                       W ^= Wleft;
+                       Wleft >>= 1;
+                       L -= 1;
+
+                       DPRINTF((" --> trying W=0x%lx and L=%d and Cmax=%u\n", W, L, Cmax));
+                       C = mrst_cardinality(p, n, state, lab, W, L, no_b);
+                       DPRINTF((" --> C=%u\n", C));
+                       if (C > Cmax) {
+                               Wmax = W;
+                               Lmax = L;
+                               lowmax = no_b;
+                               Cmax = C;
+                               DPRINTF((" --> better!\n"));
+                       } else {
+                               DPRINTF((" --> no better\n"));
+                       }
+               }
+
+       }
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               int i;
+               int hibit = lowmax + Lmax;
+               printf("msrt_find_window: Wmax=0x%lx, lowbit=%d, result=", Wmax, lowmax);
+               for (i = 31; i >= 0; i--) {
+                       int mask = (1 << i);
+                       if (i == hibit)
+                               printf("[");
+                       if (Wmax & mask)
+                               printf("1");
+                       else
+                               printf("0");
+                       if (i == lowmax)
+                               printf("]");
+               }
+               printf("\n");
+       }
+#endif
+
+       assert(Lmax > 0);
+       *len = Lmax;
+       *lowbit = lowmax;
+
+       DPRINTF(("msrt_find_window: returning Wmax=%lu, len=%d, lowbit=%d [tblsize=%u, entries=%u]\n", Wmax, Lmax, lowmax, tblsize, C));
+
+       return Wmax;
+}
+#endif
+
+/*
+ * Straighten a chain of CM ops so that the CM nodes
+ * only appear on the left node.
+ *
+ *          CM               CM
+ *        CM  CM           CM  b
+ *       x y  a b        CM  a
+ *                      x  y
+ *
+ *           CM             CM
+ *        CM    CM        CM c
+ *      CM z  CM  c      CM b
+ *     x y    a b      CM a
+ *                   CM z
+ *                  x y
+ */
+static NODE *
+straighten(NODE *p)
+{
+        NODE *r = p->n_right;
+
+        if (p->n_op != CM || r->n_op != CM)
+                return p;
+
+        p->n_right = r->n_left;
+        r->n_left = straighten(p);
+
+        return r;
+}
+
+static NODE *
+reverse1(NODE *p, NODE *a)
+{
+       NODE *l = p->n_left;
+       NODE *r = p->n_right;
+
+       a->n_right = r;
+       p->n_left = a;
+
+       if (l->n_op == CM) {
+               return reverse1(l, p);
+       } else {
+               p->n_right = l;
+               return p;
+       }
+}
+
+/*
+ * Reverse a chain of CM ops
+ */
+static NODE *
+reverse(NODE *p)
+{
+       NODE *l = p->n_left;
+       NODE *r = p->n_right;
+
+       p->n_left = r;
+
+       if (l->n_op == CM)
+               return reverse1(l, p);
+
+       p->n_right = l;
+
+       return p;
+}
+
+/* push arg onto the stack */
+/* called by moveargs() */
+static NODE *
+pusharg(NODE *p, int *regp)
+{
+        NODE *q;
+        int sz;
+       int off;
+
+        /* convert to register size, if smaller */
+        sz = tsize(p->n_type, p->n_df, p->n_ap);
+        if (sz < SZINT)
+                p = block(SCONV, p, NIL, INT, 0, 0);
+
+        q = block(REG, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap);
+        regno(q) = SPREG;
+
+       off = ARGINIT/SZCHAR + 4 * (*regp - R3);
+       q = block(PLUS, q, bcon(off), INT, 0, 0);
+        q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap);
+       (*regp) += szty(p->n_type);
+
+        return buildtree(ASSIGN, q, p);
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+       int reg = *regp;
+       NODE *q;
+
+       q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       regno(q) = reg++;
+       q = buildtree(ASSIGN, q, p);
+
+       *regp = reg;
+       return q;
+}
+
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+        int reg = *regp;
+        NODE *q, *r;
+
+#if ALLONGLONG == 64
+        /* alignment */
+        ++reg;
+        reg &= ~1;
+#endif
+
+        if (reg > R10) {
+                *regp = reg;
+                q = pusharg(p, regp);
+       } else if (reg == R10) {
+               /* half in and half out of the registers */
+               r = tcopy(p);
+               if (!features(FEATURE_BIGENDIAN)) {
+                       q = block(SCONV, p, NIL, INT, 0, 0);
+                       q = movearg_32bit(q, regp);     /* little-endian */
+                       r = buildtree(RS, r, bcon(32));
+                       r = block(SCONV, r, NIL, INT, 0, 0);
+                       r = pusharg(r, regp); /* little-endian */
+               } else {
+                       q = buildtree(RS, p, bcon(32));
+                       q = block(SCONV, q, NIL, INT, 0, 0);
+                       q = movearg_32bit(q, regp);     /* big-endian */
+                       r = block(SCONV, r, NIL, INT, 0, 0);
+                       r = pusharg(r, regp); /* big-endian */
+               }
+               q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap));
+        } else {
+                q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+                regno(q) = R3R4 + (reg - R3);
+                q = buildtree(ASSIGN, q, p);
+                *regp = reg + 2;
+        }
+
+        return q;
+}
+
+/* setup call stack with float argument */
+/* called from moveargs() */
+static NODE *
+movearg_float(NODE *p, int *fregp, int *regp)
+{
+#if defined(MACHOABI)
+       NODE *q, *r;
+       TWORD ty = INCREF(p->n_type);
+       int tmpnr;
+#endif
+
+       p = movearg_32bit(p, fregp);
+
+       /*
+        * On OS/X, floats are passed in the floating-point registers
+        * and in the general registers for compatibily with libraries
+        * compiled to handle soft-float.
+        */
+
+#if defined(MACHOABI)
+
+       if (xtemps) {
+               /* bounce into TOS */
+               r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
+               regno(r) = SPREG;
+               r = block(PLUS, r, bcon(-4), INT, 0, 0);
+               r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
+               r = buildtree(ASSIGN, r, p);
+               ecomp(r);
+
+               /* bounce into temp */
+               r = block(REG, NIL, NIL, PTR+INT, 0, 0);
+               regno(r) = SPREG;
+               r = block(PLUS, r, bcon(-4), INT, 0, 0);
+               r = block(UMUL, r, NIL, INT, 0, 0);
+               q = tempnode(0, INT, 0, 0);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, r);
+               ecomp(r);
+       } else {
+               /* copy directly into temp */
+               q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, p);
+               ecomp(r);
+       }
+
+       /* copy from temp to register parameter */
+       r = tempnode(tmpnr, INT, 0, 0);
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       regno(q) = (*regp)++;
+       p = buildtree(ASSIGN, q, r);
+
+#endif
+       return p;
+
+}
+
+/* setup call stack with float/double argument */
+/* called from moveargs() */
+static NODE *
+movearg_double(NODE *p, int *fregp, int *regp)
+{
+#if defined(MACHOABI)
+       NODE *q, *r;
+       TWORD ty = INCREF(p->n_type);
+       int tmpnr;
+#endif
+
+       /* this does the move to a single register for us */
+       p = movearg_32bit(p, fregp);
+
+       /*
+        * On OS/X, doubles are passed in the floating-point registers
+        * and in the general registers for compatibily with libraries
+        * compiled to handle soft-float.
+        */
+
+#if defined(MACHOABI)
+
+       if (xtemps) {
+               /* bounce on TOS */
+               r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
+               regno(r) = SPREG;
+               r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap);
+               r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
+               r = buildtree(ASSIGN, r, p);
+               ecomp(r);
+
+               /* bounce into temp */
+               r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0);
+               regno(r) = SPREG;
+               r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0);
+               r = block(UMUL, r, NIL, LONGLONG, 0, 0);
+               q = tempnode(0, LONGLONG, 0, 0);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, r);
+               ecomp(r);
+       } else {
+               /* copy directly into temp */
+               q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+               tmpnr = regno(q);
+               r = buildtree(ASSIGN, q, p);
+               ecomp(r);
+       }
+
+       /* copy from temp to register parameter */
+       r = tempnode(tmpnr, LONGLONG, 0, 0);
+       q = block(REG, NIL, NIL, LONGLONG, 0, 0);
+       regno(q) = R3R4 - R3 + (*regp);
+       p = buildtree(ASSIGN, q, r);
+
+       (*regp) += 2;
+
+#endif
+       
+       return p;
+}
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, int *regp)
+{
+        int reg = *regp;
+        NODE *l, *q, *t, *r;
+        int tmpnr;
+        int navail;
+        int num;
+        int sz;
+        int ty;
+        int i;
+
+       assert(p->n_op == STARG);
+
+        navail = NARGREGS - (reg - R3);
+        navail = navail < 0 ? 0 : navail;
+        sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
+        num = sz > navail ? navail : sz;
+
+       /* remove STARG node */
+        l = p->n_left;
+        nfree(p);
+        ty = l->n_type;
+
+       /*
+        * put it into a TEMP, rather than tcopy(), since the tree
+        * in p may have side-affects
+        */
+       t = tempnode(0, ty, l->n_df, l->n_ap);
+       tmpnr = regno(t);
+       q = buildtree(ASSIGN, t, l);
+
+        /* copy structure into registers */
+        for (i = 0; i < num; i++) {
+               t = tempnode(tmpnr, ty, 0, 0);
+               t = block(SCONV, t, NIL, PTR+INT, 0, 0);
+               t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
+               t = buildtree(UMUL, t, NIL);
+
+               r = block(REG, NIL, NIL, INT, 0, 0);
+               regno(r) = reg++;
+               r = buildtree(ASSIGN, r, t);
+
+               q = block(CM, q, r, INT, 0, 0);
+        }
+
+       /* put the rest of the structure on the stack */
+        for (i = num; i < sz; i++) {
+                t = tempnode(tmpnr, ty, 0, 0);
+                t = block(SCONV, t, NIL, PTR+INT, 0, 0);
+                t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0);
+                t = buildtree(UMUL, t, NIL);
+               r = pusharg(t, &reg);
+               q = block(CM, q, r, INT, 0, 0);
+        }
+
+       q = reverse(q);
+
+        *regp = reg;
+        return q;
+}
+
+
+static NODE *
+moveargs(NODE *p, int *regp, int *fregp)
+{
+        NODE *r, **rp;
+        int reg, freg;
+
+        if (p->n_op == CM) {
+                p->n_left = moveargs(p->n_left, regp, fregp);
+                r = p->n_right;
+                rp = &p->n_right;
+        } else {
+                r = p;
+                rp = &p;
+        }
+
+        reg = *regp;
+       freg = *fregp;
+
+#define        ISFLOAT(p)      (p->n_type == FLOAT || \
+                       p->n_type == DOUBLE || \
+                       p->n_type == LDOUBLE)
+
+        if (reg > R10 && r->n_op != STARG) {
+                *rp = pusharg(r, regp);
+       } else if (r->n_op == STARG) {
+               *rp = movearg_struct(r, regp);
+        } else if (DEUNSIGN(r->n_type) == LONGLONG) {
+                *rp = movearg_64bit(r, regp);
+       } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
+               if (features(FEATURE_HARDFLOAT))
+                       *rp = movearg_double(r, fregp, regp);
+               else
+                       *rp = movearg_64bit(r, regp);
+       } else if (r->n_type == FLOAT) {
+               if (features(FEATURE_HARDFLOAT))
+                       *rp = movearg_float(r, fregp, regp);
+               else
+                       *rp = movearg_32bit(r, regp);
+        } else {
+                *rp = movearg_32bit(r, regp);
+        }
+
+       return straighten(p);
+}
+
+/*
+ * Fixup arguments to pass pointer-to-struct as first argument.
+ *
+ * called from funcode().
+ */
+static NODE *
+retstruct(NODE *p)
+{
+       struct symtab s;
+       NODE *l, *r, *t, *q;
+       TWORD ty;
+
+       l = p->n_left;
+       r = p->n_right;
+
+       ty = DECREF(l->n_type) - FTN;
+
+       s.sclass = AUTO;
+       s.stype = ty;
+       s.sdf = l->n_df;
+       s.sap = l->n_ap;
+       oalloc(&s, &autooff);
+       q = block(REG, NIL, NIL, INCREF(ty), l->n_df, l->n_ap);
+       regno(q) = FPREG;
+       q = block(MINUS, q, bcon(autooff/SZCHAR), INCREF(ty),
+           l->n_df, l->n_ap);
+
+       /* insert hidden assignment at beginning of list */
+       if (r->n_op != CM) {
+               p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap);
+       } else {
+               for (t = r; t->n_left->n_op == CM; t = t->n_left)
+                       ;
+               t->n_left = block(CM, q, t->n_left, INCREF(ty),
+                   l->n_df, l->n_ap);
+       }
+
+       return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       int regnum = R3;
+       int fregnum = F1;
+
+        if (DECREF(p->n_left->n_type) == STRTY+FTN ||
+            DECREF(p->n_left->n_type) == UNIONTY+FTN)
+               p = retstruct(p);
+
+       p->n_right = moveargs(p->n_right, &regnum, &fregnum);
+
+       if (p->n_right == NULL)
+               p->n_op += (UCALL - CALL);
+
+       return p;
+}
diff --git a/lang/pcc/pcc/arch/powerpc/local.c b/lang/pcc/pcc/arch/powerpc/local.c
new file mode 100644 (file)
index 0000000..e469235
--- /dev/null
@@ -0,0 +1,1358 @@
+/*     $Id: local.c,v 1.34 2012/09/06 13:07:29 plunky Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include "pass1.h"
+
+#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+extern int kflag;
+
+static void simmod(NODE *p);
+
+/*     this file contains code which is dependent on the target machine */
+
+#if defined(MACHOABI)
+
+/*
+ *  Keep track of PIC stubs.
+ */
+
+void
+addstub(struct stub *list, char *name)
+{
+        struct stub *s;
+
+        DLIST_FOREACH(s, list, link) {
+                if (strcmp(s->name, name) == 0)
+                        return;
+        }
+
+        s = permalloc(sizeof(struct stub));
+       s->name = newstring(name, strlen(name));
+        DLIST_INSERT_BEFORE(list, s, link);
+}
+
+#endif
+
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+       struct symtab *sp = IALLOC(sizeof(struct symtab));
+       size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+
+       sp->sname = sp->soname = IALLOC(len);
+       strlcpy(sp->soname, p, len);
+       strlcat(sp->soname, s, len);
+       strlcat(sp->soname, s2, len);
+       sp->sclass = EXTERN;
+       sp->sflags = sp->slevel = 0;
+
+       return sp;
+}
+
+int gotnr;  /* tempnum for GOT register */
+
+/*
+ * Create a reference for an extern variable.
+ */
+static NODE *
+picext(NODE *p)
+{
+       NODE *q;
+       struct symtab *sp;
+       char *name;
+
+       name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
+
+       if (strncmp(name, "__builtin", 9) == 0)
+               return p;
+
+#if defined(ELFABI)
+
+       sp = picsymtab("", name, "@got(31)");
+       q = xbcon(0, sp, PTR+VOID);
+       q = block(UMUL, q, 0, PTR+VOID, 0, 0);
+
+#elif defined(MACHOABI)
+
+       char buf2[64];
+       NODE *r;
+       char *fname;
+
+       fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname;
+
+       if (p->n_sp->sclass == EXTDEF) {
+               snprintf(buf2, 64, "-L%s$pb", fname);
+               sp = picsymtab("", name, buf2);
+       } else {
+               snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname);
+               sp = picsymtab("L", name, buf2);
+               addstub(&nlplist, name);
+       }
+#if USE_GOTNR
+       q = tempnode(gotnr, PTR+VOID, 0, 0);
+#else
+       q = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(q) = GOTREG;
+#endif
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+
+       if (p->n_sp->sclass != EXTDEF)
+               q = block(UMUL, q, 0, PTR+VOID, 0, 0);
+
+#endif
+
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp; /* for init */
+       nfree(p);
+
+       return q;
+}
+
+/*
+ * Create a reference for a static variable
+ */
+
+static NODE *
+picstatic(NODE *p)
+{
+       NODE *q;
+       struct symtab *sp;
+
+#if defined(ELFABI)
+       char *n;
+
+       if (p->n_sp->slevel > 0) {
+               char buf[64];
+               snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset);
+               sp = picsymtab("", buf, "@got(31)");
+       } else  {
+               n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
+               sp = picsymtab("", exname(n), "@got(31)");
+       }
+       sp->sclass = STATIC;
+       sp->stype = p->n_sp->stype;
+       q = xbcon(0, sp, PTR+VOID);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp;
+       nfree(p);
+
+#elif defined(MACHOABI)
+
+       char buf2[64];
+       NODE *r;
+
+       snprintf(buf2, 64, "-L%s$pb",
+           cftnsp->soname ? cftnsp->soname : cftnsp->sname);
+
+       if (p->n_sp->slevel > 0) {
+               char buf1[64];
+               snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset);
+               sp = picsymtab("", buf1, buf2);
+       } else  {
+               char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
+               sp = picsymtab("", name, buf2);
+       }
+       sp->sclass = STATIC;
+       sp->stype = p->n_sp->stype;
+#if USE_GOTNR
+       q = tempnode(gotnr, PTR+VOID, 0, 0);
+#else
+       q = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(q) = GOTREG;
+#endif
+       r = xbcon(0, sp, INT);
+       q = buildtree(PLUS, q, r);
+       q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+       q->n_sp = p->n_sp;
+       nfree(p);
+
+#endif
+
+       return q;
+}
+
+static NODE *
+convert_ulltof(NODE *p)
+{
+       NODE *q, *r, *l, *t;
+       int ty;
+       int tmpnr;
+
+       ty = p->n_type;
+       l = p->n_left;
+       nfree(p);
+
+       q = tempnode(0, ULONGLONG, 0, 0);
+       tmpnr = regno(q);
+       t = buildtree(ASSIGN, q, l);
+       ecomp(t);
+
+#if 0
+       q = tempnode(tmpnr, ULONGLONG, 0, 0);
+       q = block(SCONV, q, NIL, LONGLONG, 0, 0);
+#endif
+       q = tempnode(tmpnr, LONGLONG, 0, 0);
+       r = block(SCONV, q, NIL, ty, 0, 0);
+
+       q = tempnode(tmpnr, ULONGLONG, 0, 0);
+       q = block(RS, q, bcon(1), ULONGLONG, 0, 0);
+       q = block(SCONV, q, NIL, LONGLONG, 0, 0);
+       q = block(SCONV, q, NIL, ty, 0, 0);
+       t = block(FCON, NIL, NIL, ty, 0, 0);
+       t->n_dcon = 2;
+       l = block(MUL, q, t, ty, 0, 0);
+
+       r = buildtree(COLON, l, r);
+
+       q = tempnode(tmpnr, ULONGLONG, 0, 0);
+       q = block(SCONV, q, NIL, LONGLONG, 0, 0);
+       l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, 0);
+
+       return clocal(buildtree(QUEST, l, r));
+
+}
+
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+       struct symtab *q;
+       NODE *r, *l;
+       int o;
+       int m;
+       TWORD t;
+       int isptrvoid = 0;
+       int tmpnr;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       switch (o = p->n_op) {
+
+       case ADDROF:
+#ifdef PCC_DEBUG
+               if (xdebug) {
+                       printf("clocal(): ADDROF\n");
+                       printf("type: 0x%x\n", p->n_type);
+               }
+#endif
+               /* XXX cannot takes addresses of PARAMs */
+
+               if (kflag == 0 || blevel == 0)
+                       break;
+               /* char arrays may end up here */
+               l = p->n_left;
+               if (l->n_op != NAME ||
+                   (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
+                       break;
+               l = p;
+               p = picstatic(p->n_left);
+               nfree(l);
+               if (p->n_op != UMUL)
+                       cerror("ADDROF error");
+               l = p;
+               p = p->n_left;
+               nfree(l);
+               break;
+
+       case NAME:
+               if ((q = p->n_sp) == NULL)
+                       return p; /* Nothing to care about */
+
+               switch (q->sclass) {
+
+               case PARAM:
+               case AUTO:
+                       /* fake up a structure reference */
+                       r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       r->n_lval = 0;
+                       r->n_rval = FPREG;
+                       p = stref(block(STREF, r, p, 0, 0, 0));
+                       break;
+
+               case USTATIC:
+                       if (kflag == 0)
+                               break;
+                       /* FALLTHROUGH */
+
+               case STATIC:
+                       if (kflag == 0) {
+                               if (q->slevel == 0)
+                                       break;
+                               p->n_lval = 0;
+                       } else if (blevel > 0) {
+                               p = picstatic(p);
+                       }
+                       break;
+
+               case REGISTER:
+                       p->n_op = REG;
+                       p->n_lval = 0;
+                       p->n_rval = q->soffset;
+                       break;
+
+               case EXTERN: 
+               case EXTDEF:
+                       if (kflag == 0)
+                               break;
+                       if (blevel > 0)
+                               p = picext(p);
+                       break;
+               }
+               break;
+
+       case UCALL:
+       case CALL:
+       case USTCALL:
+       case STCALL:
+                if (p->n_type == VOID)
+                        break;
+                /*
+                 * if the function returns void*, ecode() invokes
+                 * delvoid() to convert it to uchar*.
+                 * We just let this happen on the ASSIGN to the temp,
+                 * and cast the pointer back to void* on access
+                 * from the temp.
+                 */
+                if (p->n_type == PTR+VOID)
+                        isptrvoid = 1;
+                r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+                tmpnr = regno(r);
+               r = buildtree(ASSIGN, r, p);
+
+                p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+                if (isptrvoid) {
+                        p = block(PCONV, p, NIL, PTR+VOID,
+                            p->n_df, 0);
+                }
+#if 1
+                p = buildtree(COMOP, r, p);
+#else
+               /* XXX this doesn't work if the call is already in a COMOP */
+               r = clocal(r);
+               ecomp(r);
+#endif
+                break;
+               
+       case CBRANCH:
+               l = p->n_left;
+
+               /*
+                * Remove unnecessary conversion ops.
+                */
+               if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+                       if (coptype(l->n_op) != BITYPE)
+                               break;
+                       if (l->n_right->n_op == ICON) {
+                               r = l->n_left->n_left;
+                               if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+                                       break;
+                               /* Type must be correct */
+                               t = r->n_type;
+                               nfree(l->n_left);
+                               l->n_left = r;
+                               l->n_type = t;
+                               l->n_right->n_type = t;
+                       }
+               }
+               break;
+
+       case PCONV:
+               /* Remove redundant PCONV's. Be careful */
+               l = p->n_left;
+               if (l->n_op == ICON) {
+                       l->n_lval = (unsigned)l->n_lval;
+                       goto delp;
+               }
+               if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+                       /* float etc? */
+                       p->n_left = block(SCONV, l, NIL,
+                           UNSIGNED, 0, 0);
+                       break;
+               }
+               /* if left is SCONV, cannot remove */
+               if (l->n_op == SCONV)
+                       break;
+
+               /* avoid ADDROF TEMP */
+               if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+                       break;
+
+               /* if conversion to another pointer type, just remove */
+               if (p->n_type > BTMASK && l->n_type > BTMASK)
+                       goto delp;
+               break;
+
+       delp:   l->n_type = p->n_type;
+               l->n_qual = p->n_qual;
+               l->n_df = p->n_df;
+               l->n_ap = p->n_ap;
+               nfree(p);
+               p = l;
+               break;
+               
+       case SCONV:
+               l = p->n_left;
+
+               if (p->n_type == l->n_type) {
+                       nfree(p);
+                       return l;
+               }
+
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) ==
+                   tsize(l->n_type, l->n_df, l->n_ap)) {
+                       if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                           l->n_type != FLOAT && l->n_type != DOUBLE &&
+                           l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                               if (l->n_op == NAME || l->n_op == UMUL ||
+                                   l->n_op == TEMP) {
+                                       l->n_type = p->n_type;
+                                       nfree(p);
+                                       return l;
+                               }
+                       }
+               }
+
+               if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+                   coptype(l->n_op) == BITYPE) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       return l;
+               }
+
+               /*
+                * if converting ULONGLONG to FLOAT/(L)DOUBLE,
+                * replace ___floatunsdidf() with ___floatdidf()
+                */
+               if (l->n_type == ULONGLONG && p->n_type >= FLOAT &&
+                   p->n_type <= LDOUBLE) {
+                       return convert_ulltof(p);
+               }
+
+               o = l->n_op;
+               m = p->n_type;
+
+               if (o == ICON) {
+                       CONSZ val = l->n_lval;
+
+                       if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+                           switch (m) {
+                       case BOOL:
+                               l->n_lval = l->n_lval != 0;
+                               break;
+                       case CHAR:
+                               l->n_lval = (char)val;
+                               break;
+                       case UCHAR:
+                               l->n_lval = val & 0377;
+                               break;
+                       case SHORT:
+                               l->n_lval = (short)val;
+                               break;
+                       case USHORT:
+                               l->n_lval = val & 0177777;
+                               break;
+                       case ULONG:
+                       case UNSIGNED:
+                               l->n_lval = val & 0xffffffff;
+                               break;
+                       case LONG:
+                       case INT:
+                               l->n_lval = (int)val;
+                               break;
+                       case LONGLONG:
+                               l->n_lval = (long long)val;
+                               break;
+                       case ULONGLONG:
+                               l->n_lval = val;
+                               break;
+                       case VOID:
+                               break;
+                       case LDOUBLE:
+                       case DOUBLE:
+                       case FLOAT:
+                               l->n_op = FCON;
+                               l->n_dcon = val;
+                               break;
+                       default:
+                               cerror("unknown type %d", m);
+                       }
+                       l->n_type = m;
+                       l->n_ap = 0;
+                       nfree(p);
+                       return l;
+               } else if (o == FCON) {
+                       l->n_lval = l->n_dcon;
+                       l->n_sp = NULL;
+                       l->n_op = ICON;
+                       l->n_type = m;
+                       l->n_ap = 0;
+                       nfree(p);
+                       return clocal(l);
+               }
+               if (DEUNSIGN(p->n_type) == SHORT &&
+                   DEUNSIGN(l->n_type) == SHORT) {
+                       nfree(p);
+                       p = l;
+               }
+               if ((DEUNSIGN(p->n_type) == CHAR ||
+                   DEUNSIGN(p->n_type) == SHORT) &&
+                   (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                   l->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               if ((DEUNSIGN(l->n_type) == CHAR ||
+                   DEUNSIGN(l->n_type) == SHORT) &&
+                   (p->n_type == FLOAT || p->n_type == DOUBLE ||
+                   p->n_type == LDOUBLE)) {
+                       p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+                       p->n_left->n_type = INT;
+                       return p;
+               }
+               break;
+
+       case MOD:
+               simmod(p);
+               break;
+
+       case DIV:
+               if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+                       break;
+               /* make it an int division by inserting conversions */
+               p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0);
+               p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
+               p = block(SCONV, p, NIL, p->n_type, 0, 0);
+               p->n_left->n_type = INT;
+               break;
+
+       case STNAME:
+               if ((q = p->n_sp) == NULL)
+                       return p;
+               if (q->sclass != STNAME)
+                       return p;
+               t = p->n_type;
+               p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_ap);
+               p = block(UMUL, p, NIL, t, p->n_df, p->n_ap);
+               break;
+
+       case FORCE:
+               /* put return value in return reg */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(BOOL_TYPE) : RETREG(p->n_type);
+               break;
+
+       case LS:
+       case RS:
+               if (p->n_right->n_op == ICON)
+                       break; /* do not do anything */
+               if (DEUNSIGN(p->n_right->n_type) == INT)
+                       break;
+               p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0);
+               break;
+       }
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end: %p\n", p);
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return(p);
+}
+
+/*
+ * Change CALL references to either direct (static) or PLT.
+ */
+static void
+fixnames(NODE *p, void *arg)
+{
+        struct symtab *sp;
+        struct attr *ap;
+        NODE *q;
+        char *c;
+        int isu;
+
+        if ((cdope(p->n_op) & CALLFLG) == 0)
+                return;
+
+        isu = 0;
+        q = p->n_left;
+        ap = q->n_ap;
+        if (q->n_op == UMUL)
+                q = q->n_left, isu = 1;
+
+#if defined(ELFABI)
+
+        if (q->n_op == ICON) {
+                sp = q->n_sp;
+
+#elif defined(MACHOABI)
+
+#ifdef USE_GOTNR
+       if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
+#else
+       if (q->n_op == PLUS && q->n_left->n_op == REG &&
+#endif
+           q->n_right->n_op == ICON) {
+                sp = q->n_right->n_sp;
+#endif
+
+                if (sp == NULL)
+                        return; /* nothing to do */
+                if (sp->sclass == STATIC && !ISFTN(sp->stype))
+                        return; /* function pointer */
+
+                if (sp->sclass != STATIC && sp->sclass != EXTERN &&
+                    sp->sclass != EXTDEF)
+                        cerror("fixnames");
+               c = NULL;
+#if defined(ELFABI)
+
+               if (sp->soname == NULL ||
+                    (c = strstr(sp->soname, "@got(31)")) == NULL)
+                        cerror("fixnames2");
+                if (isu) {
+                       memcpy(c, "@plt", sizeof("@plt"));
+                } else
+                        *c = 0;
+
+#elif defined(MACHOABI)
+
+               if (sp->soname == NULL ||
+                   ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL &&
+                   (c = strstr(sp->soname, "-L")) == NULL))
+                               cerror("fixnames2");
+               if (isu) {
+                       addstub(&stublist, sp->soname+1);
+                       memcpy(c, "$stub", sizeof("$stub"));
+               } else 
+                       *c = 0;
+
+               nfree(q->n_left);
+               q = q->n_right;
+               if (isu)
+                       nfree(p->n_left->n_left);
+               nfree(p->n_left);
+               p->n_left = q;
+               q->n_ap = ap;
+
+#endif
+        }
+}
+
+void
+myp2tree(NODE *p)
+{
+       int o = p->n_op;
+       struct symtab *sp;
+
+       if (kflag)
+               walkf(p, fixnames, 0);
+       if (o != FCON) 
+               return;
+
+       /* Write float constants to memory */
+       /* Should be voluntary per architecture */
+       sp = IALLOC(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       defloc(sp);
+       ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       p->n_lval = 0;  
+       p->n_sp = sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+       return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+       return 1;
+}
+
+/*
+ * Allocate bits on the stack.
+ * 'off' is the number of bits to allocate
+ * 'p' is a tree that when evaluated is the multiply count for 'off'
+ * 't' is a storeable node where to write the allocated address
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *q, *r;
+       int nbytes = off / SZCHAR;
+       int stacksize = 24+40; /* this should be p2stacksize */
+
+       /*
+        * After we subtract the requisite bytes
+        * off the stack, we need to step back over
+        * the 40 bytes for the arguments registers
+        * *and* any other parameters which will get
+        * saved to the stack.  Unfortunately, we
+        * don't have that information in pass1 and
+        * the parameters will stomp on the allocated
+        * space for alloca().
+        *
+        * No fix yet.
+        */
+       werror("parameters may stomp on alloca()");
+
+       /* compute size */
+       p = buildtree(MUL, p, bcon(nbytes));
+       p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR));
+
+       /* load the top-of-stack */
+       q = block(REG, NIL, NIL, PTR+INT, 0, 0);
+       regno(q) = SPREG;
+       q = block(UMUL, q, NIL, INT, 0, 0);
+
+       /* save old top-of-stack value to new top-of-stack position */
+       r = block(REG, NIL, NIL, PTR+INT, 0, 0);
+       regno(r) = SPREG;
+       r = block(MINUSEQ, r, p, INT, 0, 0);
+       r = block(UMUL, r, NIL, INT, 0, 0);
+       ecomp(buildtree(ASSIGN, r, q));
+
+       r = block(REG, NIL, NIL, PTR+INT, 0, 0);
+       regno(r) = SPREG;
+
+       /* skip over the arguments space and align to 16 bytes */
+       r = block(PLUS, r, bcon(stacksize + 15), INT, 0, 0);
+       r = block(RS, r, bcon(4), INT, 0, 0);
+       r = block(LS, r, bcon(4), INT, 0, 0);
+
+       t->n_type = p->n_type;
+       ecomp(buildtree(ASSIGN, t, r));
+}
+
+/*
+ * Print out a string of characters.
+ * Unfortunately, this code assumes that the assembler understands
+ * C-style escape sequences. (which it doesn't!)
+ * Location is already set.
+ */
+void
+instring(struct symtab *sp)
+{
+       char *s, *str = sp->sname;
+
+#if defined(ELFABI)
+
+       defloc(sp);
+
+#elif defined(MACHOABI)
+
+       extern int lastloc;
+       if (lastloc != STRNG)
+               printf("        .cstring\n");
+       lastloc = STRNG;
+       printf("\t.p2align 2\n");
+       printf(LABFMT ":\n", sp->soffset);
+
+#endif
+
+       /* be kind to assemblers and avoid long strings */
+       printf("\t.ascii \"");
+       for (s = str; *s != 0; ) {
+               if (*s++ == '\\') {
+                       (void)esccon(&s);
+               }
+               if (s - str > 64) {
+                       fwrite(str, 1, s - str, stdout);
+                       printf("\"\n\t.ascii \"");
+                       str = s;
+               }
+       }
+       fwrite(str, 1, s - str, stdout);
+       printf("\\0\"\n");
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+       struct symtab *q;
+       char *c;
+       TWORD t;
+       int i;
+
+       t = p->n_type;
+       if (t > BTMASK)
+               p->n_type = t = INT; /* pointer */
+
+
+       if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
+               if (p->n_op == UMUL)
+                       p = p->n_left;
+               p = p->n_right;
+               q = p->n_sp;
+
+#if defined(ELFABI)
+
+               if (q->soname && (c = strstr(q->soname, "@got(31)")) != NULL)
+                       *c = 0; /* ignore GOT ref here */
+
+#elif defined(MACHOABI)
+
+               if  ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) {
+                       q->soname++;    /* skip "L" */
+                       *c = 0; /* ignore GOT ref here */
+               }
+               else if ((c = strstr(q->soname, "-L")) != NULL)
+                       *c = 0; /* ignore GOT ref here */
+
+#endif
+
+       }
+
+       if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+               uerror("element not constant");
+
+       switch (t) {
+       case LONGLONG:
+       case ULONGLONG:
+#if 0
+               /* little-endian */
+               i = (p->n_lval >> 32);
+               p->n_lval &= 0xffffffff;
+               p->n_type = INT;
+               ninval(off, 32, p);
+               p->n_lval = i;
+               ninval(off+32, 32, p);
+#endif
+               /* big-endian */
+               i = (p->n_lval & 0xffffffff);
+               p->n_lval >>= 32;
+               p->n_type = INT;
+               ninval(off, 32, p);
+               p->n_lval = i;
+               ninval(off+32, 32, p);
+
+               break;
+       case INT:
+       case UNSIGNED:
+               printf("\t.long %d", (int)p->n_lval);
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)) {
+                               printf("+" LABFMT, q->soffset);
+                       } else {
+                               char *name = q->soname ? q->soname : exname(q->sname);
+                               printf("+%s", name);
+                       }
+               }
+               printf("\n");
+               break;
+       case LDOUBLE:
+               u.i[2] = 0;
+               u.l = (long double)p->n_dcon;
+#if 0
+               /* little-endian */
+               printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+#endif
+               /* big-endian */
+               printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+               break;
+       case DOUBLE:
+               u.d = (double)p->n_dcon;
+               printf("\t.long 0x%x\n\t.long 0x%x\n", u.i[0], u.i[1]);
+               break;
+       case FLOAT:
+               u.f = (float)p->n_dcon;
+               printf("\t.long 0x%x\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#if defined(ELFABI)
+
+       return (p == NULL ? "" : p);
+
+#elif defined(MACHOABI)
+
+#define NCHNAM 256
+        static char text[NCHNAM+1];
+       int i;
+
+       if (p == NULL)
+               return "";
+
+        text[0] = '_';
+        for (i=1; *p && i<NCHNAM; ++i)
+                text[i] = *p++;
+
+        text[i] = '\0';
+        text[NCHNAM] = '\0';  /* truncate */
+
+        return (text);
+
+#endif
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+
+       }
+       return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+#ifdef PCC_DEBUG
+       if (xdebug)
+               printf("calldec:\n");
+#endif
+}
+
+void
+extdec(struct symtab *q)
+{
+#ifdef PCC_DEBUG
+       if (xdebug)
+               printf("extdec:\n");
+#endif
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       char *n;
+       int off;
+
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       printf("\t.%scomm ", sp->sclass == STATIC ? "l" : "");
+       n = sp->soname ? sp->soname : exname(sp->sname);
+       if (sp->slevel == 0)
+               printf("%s,%d\n", n, off);
+       else
+               printf(LABFMT ",%d\n", sp->soffset, off);
+}
+
+
+#ifdef notdef
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       printf("\t.comm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off);
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+       int off;
+
+       off = tsize(q->stype, q->sdf, q->ssue);
+       off = (off+(SZCHAR-1))/SZCHAR;
+       if (q->slevel == 0)
+               printf("\t.lcomm %s,%d\n", q->soname ? q->soname : exname(q->sname), off);
+       else
+               printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+#if defined(ELFABI)
+
+static char *loctbl[] = { "text", "data", "section .rodata,",
+    "section .rodata" };
+
+#elif defined(MACHOABI)
+
+static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" };
+
+#endif
+
+void
+setloc1(int locc)
+{
+#ifdef PCC_DEBUG
+       if (xdebug)
+               printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc);
+#endif
+
+       if (locc == lastloc)
+               return;
+       lastloc = locc;
+       printf("        .%s\n", loctbl[locc]);
+}
+#endif
+
+/* simulate and optimise the MOD opcode */
+static void
+simmod(NODE *p)
+{
+       NODE *r = p->n_right;
+
+       assert(p->n_op == MOD);
+
+       if (!ISUNSIGNED(p->n_type))
+               return;
+
+#define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0))
+
+       /* if the right is a constant power of two, then replace with AND */
+       if (r->n_op == ICON && ISPOW2(r->n_lval)) {
+               p->n_op = AND;
+               r->n_lval--;
+               return;
+       }
+
+#undef ISPOW2
+
+       /* other optimizations can go here */
+}
+
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       if (strcmp(str, "tls") == 0) {
+               uerror("thread-local storage not supported for this target");
+               return 1;
+       }
+       if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+               constructor = 1;
+               return 1;
+       }
+       if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+               destructor = 1;
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+       /* may have sanity checks here */
+       if ((constructor || destructor) && (sp->sclass != PARAM)) {
+#ifdef MACHOABI
+               if (kflag) {
+                       if (constructor)
+                               printf("\t.mod_init_func\n");
+                       else
+                               printf("\t.mod_term_func\n");
+               } else {
+                       if (constructor)
+                               printf("\t.constructor\n");
+                       else
+                               printf("\t.destructor\n");
+               }
+               printf("\t.p2align 2\n");
+               printf("\t.long %s\n", exname(sp->sname));
+               printf("\t.text\n");
+               constructor = destructor = 0;
+#endif
+       }
+}
+
+/*
+ * There is very little different here to the standard builtins.
+ * It basically handles promotion of types smaller than INT.
+ */
+
+NODE *
+powerpc_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
+{
+        NODE *p, *q;
+        int sz = 1;
+
+        /* check num args and type */
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+            !ISPTR(a->n_left->n_type))
+                goto bad;
+
+        /* must first deal with argument size; use int size */
+        p = a->n_right;
+        if (p->n_type < INT) {
+                /* round up to word */
+                sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
+        }
+
+        p = buildtree(ADDROF, p, NIL);  /* address of last arg */
+        p = optim(buildtree(PLUS, p, bcon(sz)));
+        q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+        q = buildtree(CAST, q, p);
+        p = q->n_right;
+        nfree(q->n_left);
+        nfree(q);
+        p = buildtree(ASSIGN, a->n_left, p);
+        tfree(f);
+        nfree(a);
+
+        return p;
+
+bad:
+        uerror("bad argument to __builtin_stdarg_start");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_va_arg(NODE *f, NODE *a, TWORD t)
+{
+        NODE *p, *q, *r;
+        int sz, tmpnr;
+
+        /* check num args and type */
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+            !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+                goto bad;
+
+        r = a->n_right;
+
+        /* get type size */
+        sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
+        if (sz < SZINT/SZCHAR) {
+                werror("%s%s promoted to int when passed through ...",
+                        ISUNSIGNED(r->n_type) ? "unsigned " : "",
+                        DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+                sz = SZINT/SZCHAR;
+               r->n_type = INT;
+               r->n_ap = 0;
+        }
+
+        p = tcopy(a->n_left);
+
+#if defined(ELFABI)
+
+        /* alignment */
+        if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
+                p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
+                p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
+        }
+
+#endif
+
+        /* create a copy to a temp node */
+        q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+        tmpnr = regno(q);
+        p = buildtree(ASSIGN, q, p);
+
+        q = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap);
+        q = buildtree(PLUS, q, bcon(sz));
+        q = buildtree(ASSIGN, a->n_left, q);
+
+        q = buildtree(COMOP, p, q);
+
+        nfree(a->n_right);
+        nfree(a);
+        nfree(f);
+
+        p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
+        p = buildtree(UMUL, p, NIL);
+        p = buildtree(COMOP, q, p);
+
+        return p;
+
+bad:
+        uerror("bad argument to __builtin_va_arg");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_va_end(NODE *f, NODE *a, TWORD t)
+{
+        tfree(f);
+        tfree(a);
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_va_copy(NODE *f, NODE *a, TWORD t)
+{
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+                goto bad;
+        tfree(f);
+        f = buildtree(ASSIGN, a->n_left, a->n_right);
+        nfree(a);
+        return f;
+
+bad:
+        uerror("bad argument to __buildtin_va_copy");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_return_address(NODE *f, NODE *a, TWORD t)
+{
+       int nframes;
+       int i = 0;
+
+       if (a == NULL || a->n_op != ICON)
+               goto bad;
+
+       nframes = a->n_lval;
+
+       tfree(f);
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+       regno(f) = SPREG;
+
+       do {
+               f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+       } while (i++ < nframes);
+
+       f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
+       f = buildtree(UMUL, f, NIL);
+
+       return f;
+bad:
+        uerror("bad argument to __builtin_return_address");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_frame_address(NODE *f, NODE *a, TWORD t)
+{
+       int nframes;
+       int i = 0;
+
+       if (a == NULL || a->n_op != ICON)
+               goto bad;
+
+       nframes = a->n_lval;
+
+       tfree(f);
+       tfree(a);
+
+       if (nframes == 0) {
+               f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+               regno(f) = FPREG;
+       } else {
+               f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
+               regno(f) = SPREG;
+               do {
+                       f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
+               } while (i++ < nframes);
+               f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, 0);
+               f = buildtree(UMUL, f, NIL);
+       }
+
+       return f;
+bad:
+        uerror("bad argument to __builtin_frame_address");
+        return bcon(0);
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/powerpc/local2.c b/lang/pcc/pcc/arch/powerpc/local2.c
new file mode 100644 (file)
index 0000000..70db56b
--- /dev/null
@@ -0,0 +1,1517 @@
+/*     $Id: local2.c,v 1.28 2015/01/04 19:17:23 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass1.h"     /* for cftnsp */
+#include "pass2.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(MACHOABI)
+#define EXPREFIX       "_"
+#else
+#define EXPREFIX       ""
+#endif
+
+#define LOWREG         0
+#define HIREG          1
+
+char *rnames[] = {
+       REGPREFIX "r0", REGPREFIX "r1",
+       REGPREFIX "r2", REGPREFIX "r3",
+       REGPREFIX "r4", REGPREFIX "r5",
+       REGPREFIX "r6", REGPREFIX "r7",
+       REGPREFIX "r8", REGPREFIX "r9",
+       REGPREFIX "r10", REGPREFIX "r11",
+       REGPREFIX "r12", REGPREFIX "r13",
+       REGPREFIX "r14", REGPREFIX "r15",
+       REGPREFIX "r16", REGPREFIX "r17",
+       REGPREFIX "r18", REGPREFIX "r19",
+       REGPREFIX "r20", REGPREFIX "r21",
+       REGPREFIX "r22", REGPREFIX "r23",
+       REGPREFIX "r24", REGPREFIX "r25",
+       REGPREFIX "r26", REGPREFIX "r27",
+       REGPREFIX "r28", REGPREFIX "r29",
+       REGPREFIX "r30", REGPREFIX "r31",
+       "r4\0r3\0", "r5\0r4\0", "r6\0r5\0", "r7\0r6\0",
+       "r8\0r7\0", "r9\0r8\0", "r10r9\0", "r15r14", "r17r16",
+       "r19r18", "r21r20", "r23r22", "r25r24", "r27r26",
+       "r29r28", "r31r30",
+       REGPREFIX "f0", REGPREFIX "f1",
+       REGPREFIX "f2", REGPREFIX "f3",
+       REGPREFIX "f4", REGPREFIX "f5",
+       REGPREFIX "f6", REGPREFIX "f7",
+       REGPREFIX "f8", REGPREFIX "f9",
+       REGPREFIX "f10", REGPREFIX "f11",
+       REGPREFIX "f12", REGPREFIX "f13",
+       REGPREFIX "f14", REGPREFIX "f15",
+       REGPREFIX "f16", REGPREFIX "f17",
+       REGPREFIX "f18", REGPREFIX "f19",
+       REGPREFIX "f20", REGPREFIX "f21",
+       REGPREFIX "f22", REGPREFIX "f23",
+       REGPREFIX "f24", REGPREFIX "f25",
+       REGPREFIX "f26", REGPREFIX "f27",
+       REGPREFIX "f28", REGPREFIX "f29",
+       REGPREFIX "f30", REGPREFIX "f31",
+};
+
+static int argsize(NODE *p);
+
+static int p2calls;
+static int p2temps;            /* TEMPs which aren't autos yet */
+static int p2framesize;
+static int p2maxstacksize;
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ */
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int addto;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%lx, autos=%d, tmpnum=%d, lblnum=%d\n",
+                       ipp->ipp_ip.type,
+                       ipp->ipp_ip.lineno,
+                       ipp->ipp_name,
+                       ipp->ipp_vis,
+                       ipp->ipp_type,
+                       ipp->ipp_regs[0],
+                       ipp->ipp_autos,
+                       ipp->ip_tmpnum,
+                       ipp->ip_lblnum);
+#endif
+
+       ftype = ipp->ipp_type;
+
+       addto = p2framesize;
+
+       if (p2calls != 0 || kflag) {
+               /* get return address (not required for leaf function) */
+               printf("\tmflr %s\n", rnames[R0]);
+               printf("\tstw %s,8(%s)\n", rnames[R0], rnames[R1]);
+       }
+       /* save registers R30 and R31 */
+       printf("\tstmw %s,-8(%s)\n", rnames[R30], rnames[R1]);
+#ifdef FPREG
+       printf("\tmr %s,%s\n", rnames[FPREG], rnames[R1]);
+#endif
+       /* create the new stack frame */
+       if (addto > 32767) {
+               printf("\tlis %s,%d\n", rnames[R0], (-addto) >> 16);
+               printf("\tori %s,%s,%d\n", rnames[R0],
+                   rnames[R0], (-addto) & 0xffff);
+               printf("\tstwux %s,%s,%s\n", rnames[R1],
+                   rnames[R1], rnames[R0]);
+       } else {
+               printf("\tstwu %s,-%d(%s)\n", rnames[R1], addto, rnames[R1]);
+       }
+
+       if (kflag) {
+#if defined(ELFABI)
+               printf("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n");
+               printf("\tmflr %s\n", rnames[GOTREG]);
+#elif defined(MACHOABI)
+               printf("\tbcl 20,31,L%s$pb\n", ipp->ipp_name + 1);
+               printf("L%s$pb:\n", ipp->ipp_name + 1);
+               printf("\tmflr %s\n", rnames[GOTREG]);
+#endif
+       }
+
+}
+
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("eoftn:\n");
+#endif
+
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+
+       /* struct return needs special treatment */
+       if (ftype == STRTY || ftype == UNIONTY) 
+               cerror("eoftn");
+
+       /* unwind stack frame */
+       printf("\tlwz %s,0(%s)\n", rnames[R1], rnames[R1]);
+       if (p2calls != 0 || kflag) {
+               printf("\tlwz %s,8(%s)\n", rnames[R0], rnames[R1]);
+               printf("\tmtlr %s\n", rnames[R0]);
+       }
+       printf("\tlmw %s,-8(%s)\n", rnames[R30], rnames[R1]);
+       printf("\tblr\n");
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+       case PLUS:
+               str = "addw";
+               break;
+       case MINUS:
+               str = "subw";
+               break;
+       case AND:
+               str = "and";
+               break;
+       case OR:
+               str = "or";
+               break;
+       case ER:
+               str = "xor";
+               break;
+       default:
+               comperr("hopcode2: %d", o);
+               str = 0; /* XXX gcc */
+       }
+       printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return(1);
+
+               case SHORT:
+               case USHORT:
+                       return(SZSHORT/SZCHAR);
+
+               case DOUBLE:
+                       return(SZDOUBLE/SZCHAR);
+
+               case INT:
+               case UNSIGNED:
+               case LONG:
+               case ULONG:
+                       return(SZINT/SZCHAR);
+
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG/SZCHAR;
+
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type %d not pointer");
+                       return SZPOINT(p->n_type)/SZCHAR;
+               }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int o = p->n_op;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       if (o >= ULE)
+               o -= (ULE-LE);
+       switch (o) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       if (p->n_op >= ULE)
+               expand(p, 0, "\tcmplw UL,UR" COM "compare 64-bit values (upper)\n");
+       else
+               expand(p, 0, "\tcmpw UL,UR" COM "compare 64-bit values (upper)\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+       if (p->n_op >= ULE)
+               expand(p, 0, "\tcmplw AL,AR" COM "(and lower)\n");
+       else
+               expand(p, 0, "\tcmpw AL,AR" COM "(and lower)\n");
+       cbgen(p->n_op, e);
+       deflab(s);
+}
+
+static void
+shiftop(NODE *p)
+{
+       NODE *r = p->n_right;
+       TWORD ty = p->n_type;
+
+       if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
+               expand(p, INBREG, "\tsrwi A1,AL,32-AR" COM "64-bit left-shift\n");
+               expand(p, INBREG, "\tslwi U1,UL,AR\n");
+               expand(p, INBREG, "\tor U1,U1,A1\n");
+               expand(p, INBREG, "\tslwi A1,AL,AR\n");
+       } else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
+               expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n");
+               if (r->n_lval == 32)
+                       expand(p, INBREG, "\tmr U1,AL\n");
+               else
+                       expand(p, INBREG, "\tslwi U1,AL,AR-32\n");
+       } else if (p->n_op == LS && r->n_op == ICON) {
+               expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n");
+               expand(p, INBREG, "\tli U1,0\n");
+       } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
+               expand(p, INBREG, "\tslwi U1,UL,32-AR" COM "64-bit right-shift\n");
+               expand(p, INBREG, "\tsrwi A1,AL,AR\n");
+               expand(p, INBREG, "\tor A1,A1,U1\n");
+               if (ty == LONGLONG)
+                       expand(p, INBREG, "\tsrawi U1,UL,AR\n");
+               else
+                       expand(p, INBREG, "\tsrwi U1,UL,AR\n");
+       } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
+               if (ty == LONGLONG)
+                       expand(p, INBREG, "\tli U1,-1" COM "64-bit right-shift\n");
+               else
+                       expand(p, INBREG, "\tli U1,0" COM "64-bit right-shift\n");
+               if (r->n_lval == 32)
+                       expand(p, INBREG, "\tmr A1,UL\n");
+               else if (ty == LONGLONG)
+                       expand(p, INBREG, "\tsrawi A1,UL,AR-32\n");
+               else
+                       expand(p, INBREG, "\tsrwi A1,UL,AR-32\n");
+       } else if (p->n_op == RS && r->n_op == ICON) {
+               expand(p, INBREG, "\tli A1,0" COM "64-bit right-shift\n");
+               expand(p, INBREG, "\tli U1,0\n");
+       }
+}
+
+/*
+ * Structure assignment.
+ */
+static void
+stasg(NODE *p)
+{
+       NODE *l = p->n_left;
+       int val = l->n_lval;
+
+        /* R3 = dest, R4 = src, R5 = len */
+        printf("\tli %s,%d\n", rnames[R5], attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
+        if (l->n_op == OREG) {
+                printf("\taddi %s,%s,%d\n", rnames[R3], rnames[regno(l)], val);
+        } else if (l->n_op == NAME) {
+#if defined(ELFABI)
+                printf("\tli %s,", rnames[R3]);
+                adrput(stdout, l);
+               printf("@ha\n");
+                printf("\taddi %s,%s,", rnames[R3], rnames[R3]);
+                adrput(stdout, l);
+               printf("@l\n");
+#elif defined(MACHOABI)
+                printf("\tli %s,ha16(", rnames[R3]);
+                adrput(stdout, l);
+               printf(")\n");
+                printf("\taddi %s,%s,lo16(", rnames[R3], rnames[R3]);
+                adrput(stdout, l);
+               printf(")\n");
+#endif
+        }
+       if (kflag) {
+#if defined(ELFABI)
+               printf("\tbl %s@got(30)\n", EXPREFIX "memcpy");
+#elif defined(MACHOABI)
+               printf("\tbl L%s$stub\n", EXPREFIX "memcpy");
+               addstub(&stublist, EXPREFIX "memcpy");
+#endif
+       } else {
+               printf("\tbl %s\n", EXPREFIX "memcpy");
+       }
+}
+
+static void
+fpemul(NODE *p)
+{
+       NODE *l = p->n_left;
+       char *ch = NULL;
+
+       if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+       else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+       else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
+
+       else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+       else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+       else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
+
+       else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+       else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+       else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
+
+       else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+       else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+       else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
+
+       else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+       else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+       else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
+
+       else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+       else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+       else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
+
+       else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+       else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+       else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
+
+       else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+       else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+       else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
+
+       else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+       else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+       else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
+
+       else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+       else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+       else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
+
+       else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+       else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+       else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
+
+       else if (p->n_op == SCONV && p->n_type == FLOAT) {
+               if (l->n_type == DOUBLE) ch = "truncdfsf2";
+               else if (l->n_type == LDOUBLE) ch = "truncdfsf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdisf";
+               else if (l->n_type == LONGLONG) ch = "floatdisf";
+               else if (l->n_type == LONG) ch = "floatsisf";
+               else if (l->n_type == ULONG) ch = "floatunsisf";
+               else if (l->n_type == INT) ch = "floatsisf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+       } else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+               if (l->n_type == FLOAT) ch = "extendsfdf2";
+               else if (l->n_type == LDOUBLE) ch = "truncdfdf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+               else if (l->n_type == LONGLONG) ch = "floatdidf";
+               else if (l->n_type == LONG) ch = "floatsidf";
+               else if (l->n_type == ULONG) ch = "floatunssidf";
+               else if (l->n_type == INT) ch = "floatsidf";
+               else if (l->n_type == UNSIGNED) ch = "floatunssidf";
+       } else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+               if (l->n_type == FLOAT) ch = "extendsfdf2";
+               else if (l->n_type == DOUBLE) ch = "extenddfdf2";
+               else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+               else if (l->n_type == LONGLONG) ch = "floatdidf";
+               else if (l->n_type == LONG) ch = "floatsidf";
+               else if (l->n_type == ULONG) ch = "floatunssidf";
+               else if (l->n_type == INT) ch = "floatsidf";
+               else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+       } else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+               if (l->n_type == FLOAT) ch = "fixunssfdi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+       } else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+               if (l->n_type == FLOAT) ch = "fixsfdi";
+               else if (l->n_type == DOUBLE) ch = "fixdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+       } else if (p->n_op == SCONV && p->n_type == LONG) {
+               if (l->n_type == FLOAT) ch = "fixsfdi";
+               else if (l->n_type == DOUBLE) ch = "fixdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+       } else if (p->n_op == SCONV && p->n_type == ULONG) {
+               if (l->n_type == FLOAT) ch = "fixunssfdi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+       } else if (p->n_op == SCONV && p->n_type == INT) {
+               if (l->n_type == FLOAT) ch = "fixsfsi";
+               else if (l->n_type == DOUBLE) ch = "fixdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+       } else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+               if (l->n_type == FLOAT) ch = "fixunssfsi";
+               else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+               else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+       }
+
+       if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+       if (kflag) {
+#if defined(ELFABI)
+               printf("\tbl __%s%s@got(30)" COM "soft-float\n", EXPREFIX, ch);
+#elif defined(MACHOABI)
+               char buf[32];
+               printf("\tbl L__%s%s$stub" COM "soft-float\n", EXPREFIX, ch);
+               snprintf(buf, 32, "__%s%s", EXPREFIX, ch);
+               addstub(&stublist, buf);
+#endif
+       } else {
+               printf("\tbl __%s%s" COM "soft-float\n", EXPREFIX, ch);
+       }
+
+       if (p->n_op >= EQ && p->n_op <= GT)
+               printf("\tcmpwi %s,0\n", rnames[R3]);
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+
+static void
+emul(NODE *p)
+{
+       char *ch = NULL;
+
+        if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+        else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
+            DEUNSIGN(p->n_type) == INT))
+                ch = "ashlsi3";
+
+        else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+        else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
+                ch = "lshrsi3";
+
+        else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+        else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
+                ch = "ashrsi3";
+        
+        else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+        else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
+                ch = "divsi3";
+
+        else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+        else if (p->n_op == DIV && (p->n_type == ULONG ||
+            p->n_type == UNSIGNED))
+                ch = "udivsi3";
+
+        else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+        else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
+                ch = "modsi3";
+
+        else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+        else if (p->n_op == MOD && (p->n_type == ULONG ||
+            p->n_type == UNSIGNED))
+                ch = "umodsi3";
+
+        else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+        else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
+                ch = "mulsi3";
+
+        else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+        else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
+
+       else ch = 0, comperr("ZE");
+       if (kflag) {
+#if defined(ELFABI)
+               printf("\tbl __%s%s@got(30)" COM "emulated op\n", EXPREFIX, ch);
+#elif defined(MACHOABI)
+               char buf[32];
+               printf("\tbl L__%s%s$stub" COM "emulated op\n", EXPREFIX, ch);
+               snprintf(buf, 32, "__%s%s", EXPREFIX, ch);
+               addstub(&stublist, buf);
+#endif
+       } else {
+               printf("\tbl __%s%s" COM "emulated operation\n", EXPREFIX, ch);
+       }
+}
+
+/*
+ *  Floating-point conversions (int -> float/double & float/double -> int)
+ */
+
+static void
+ftoi(NODE *p)
+{
+       NODE *l = p->n_left;
+
+       printf(COM "start conversion float/(l)double to int\n");
+
+       if (l->n_op != OREG) {
+               expand(p, 0, "\tstw AL,-4");
+               printf("(%s)\n", rnames[SPREG]);
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tlfs A2,");
+               else
+                       expand(p, 0, "\tlfd A2,\n");
+               printf("-4(%s)\n", rnames[SPREG]);
+       } else {
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tlfs A2,AL\n");
+               else
+                       expand(p, 0, "\tlfd A2,AL\n");
+       }
+
+       expand(p, 0, "\tfctiwz A2,A2\n");
+       expand(p, 0, "\tstfd A2,");
+       printf("-8(%s)\n", rnames[SPREG]);
+       expand(p, 0, "\tlwz A1,");
+       printf("-4(%s)\n", rnames[SPREG]);
+
+       printf(COM "end conversion\n");
+}
+
+static void
+ftou(NODE *p)
+{
+       static int lab = 0;
+       NODE *l = p->n_left;
+       int lab1 = getlab2();
+       int lab2 = getlab2();
+
+       printf(COM "start conversion of float/(l)double to unsigned\n");
+
+       if (lab == 0) {
+               lab = getlab2();
+               expand(p, 0, "\t.data\n");
+               printf(LABFMT ":\t.long 0x41e00000\n\t.long 0\n", lab);
+               expand(p, 0, "\t.text\n");
+       }
+
+       if (l->n_op != OREG) {
+               expand(p, 0, "\tstw AL,");
+               printf("-4(%s)\n", rnames[SPREG]);
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tlfs A3,");
+               else
+                       expand(p, 0, "\tlfd A3,");
+               printf("-4(%s)\n", rnames[SPREG]);
+               
+       } else {
+               if (l->n_type == FLOAT)
+                       expand(p, 0, "\tlfs A3,AL\n");
+               else
+                       expand(p, 0, "\tlfd A3,AL\n");
+       }
+
+#if 0
+       if (kflag) {
+               expand(p, 0, "\taddis A1,");
+               printf("%s,ha16(", rnames[R31]);
+               printf(LABFMT, lab);
+               printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+                       expand(p, 0, "\tlfd A2,lo16(");
+               printf(LABFMT, lab);
+               printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+               expand(p, 0, "(A1)\n");
+       } else {
+                       expand(p, 0, "\tlfd A2,");
+               printf(LABFMT "\n", lab);
+       }
+#endif
+
+#if defined(ELFABI)
+
+       expand(p, 0, "\taddis A1,");
+       printf("%s," LABFMT "@ha\n", rnames[R31], lab);
+               expand(p, 0, "\tlfd A2,");
+       printf(LABFMT "@l", lab);
+       expand(p, 0, "(A1)\n");
+
+#elif defined(MACHOABI)
+
+       expand(p, 0, "\taddis A1,");
+       printf("%s,ha16(", rnames[R31]);
+       printf(LABFMT, lab);
+       if (kflag)
+               printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+       printf(")\n");
+               expand(p, 0, "\tlfd A2,lo16(");
+       printf(LABFMT, lab);
+       if (kflag)
+               printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+       expand(p, 0, ")(A1)\n");
+
+#endif
+
+       expand(p, 0, "\tfcmpu cr7,A3,A2\n");
+       printf("\tcror 30,29,30\n");
+       printf("\tbeq cr7,"LABFMT "\n", lab1);
+
+       expand(p, 0, "\tfctiwz A2,A3\n");
+       expand(p, 0, "\tstfd A2,");
+       printf("-8(%s)\n", rnames[SPREG]);
+       expand(p, 0, "\tlwz A1,");
+       printf("-4(%s)\n", rnames[SPREG]);
+       printf("\tba " LABFMT "\n", lab2);
+
+       deflab(lab1);
+
+        expand(p, 0, "\tfsub A2,A3,A2\n");
+        expand(p, 0, "\tfctiwz A2,A2\n");
+       expand(p, 0, "\tstfd A2,");
+       printf("-8(%s)\n", rnames[SPREG]);
+       expand(p, 0, "\tlwz A1,");
+       printf("-4(%s)\n", rnames[SPREG]);
+        expand(p, 0, "\txoris A1,A1,0x8000\n");
+
+       deflab(lab2);
+
+       printf(COM "end conversion\n");
+}
+
+static void
+itof(NODE *p)
+{
+       static int labu = 0;
+       static int labi = 0;
+       int lab;
+       NODE *l = p->n_left;
+
+       printf(COM "start conversion (u)int to float/(l)double\n");
+
+       if (labi == 0 && l->n_type == INT) {
+               labi = getlab2();
+               expand(p, 0, "\t.data\n");
+               printf(LABFMT ":\t.long 0x43300000\n\t.long 0x80000000\n", labi);
+               expand(p, 0, "\t.text\n");
+       } else if (labu == 0 && l->n_type == UNSIGNED) {
+               labu = getlab2();
+               expand(p, 0, "\t.data\n");
+               printf(LABFMT ":\t.long 0x43300000\n\t.long 0x00000000\n", labu);
+               expand(p, 0, "\t.text\n");
+       }
+
+       if (l->n_type == INT) {
+               expand(p, 0, "\txoris A1,AL,0x8000\n");
+               lab = labi;
+       } else {
+               lab = labu;
+       }
+       expand(p, 0, "\tstw A1,");
+       printf("-4(%s)\n", rnames[SPREG]);
+        expand(p, 0, "\tlis A1,0x4330\n");
+        expand(p, 0, "\tstw A1,");
+       printf("-8(%s)\n", rnames[SPREG]);
+        expand(p, 0, "\tlfd A3,");
+       printf("-8(%s)\n", rnames[SPREG]);
+
+#if 0
+       if (kflag) {
+               expand(p, 0, "\taddis A1,");
+               printf("%s,ha16(", rnames[R31]);
+               printf(LABFMT, lab);
+               printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+                       expand(p, 0, "\tlfd A2,lo16(");
+               printf(LABFMT, lab);
+               printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+               expand(p, 0, "(A1)\n");
+       } else {
+                       expand(p, 0, "\tlfd A2,");
+               printf(LABFMT "\n", lab);
+       }
+#endif
+
+#if defined(ELFABI)
+
+       expand(p, 0, "\taddis A1,");
+       printf("%s," LABFMT "@ha\n", rnames[R31], lab);
+               expand(p, 0, "\tlfd A2,");
+       printf(LABFMT "@l", lab);
+       expand(p, 0, "(A1)\n");
+
+#elif defined(MACHOABI)
+
+       expand(p, 0, "\taddis A1,");
+       printf("%s,ha16(", rnames[R31]);
+       printf(LABFMT, lab);
+       if (kflag)
+               printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+       printf(")\n");
+               expand(p, 0, "\tlfd A2,lo16(");
+       printf(LABFMT, lab);
+       if (kflag)
+               printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+       expand(p, 0, ")(A1)\n");
+
+#endif
+
+       expand(p, 0, "\tfsub A3,A3,A2\n");
+       if (p->n_type == FLOAT)
+               expand(p, 0, "\tfrsp A3,A3\n");
+
+       printf(COM "end conversion\n");
+}
+
+
+static void
+fpconv(NODE *p)
+{
+       NODE *l = p->n_left;
+
+#ifdef PCC_DEBUG
+       if (p->n_op != SCONV)
+               cerror("fpconv 1");
+#endif
+
+       if (DEUNSIGN(l->n_type) == INT)
+               itof(p);
+       else if (p->n_type == INT)
+               ftoi(p);
+       else if (p->n_type == UNSIGNED)
+               ftou(p);
+       else
+               cerror("unhandled floating-point conversion");
+
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+       switch (c) {
+
+       case 'C': /* floating-point conversions */
+               fpconv(p);
+               break;
+
+       case 'D': /* long long comparision */
+               twollcomp(p);
+               break;
+
+       case 'E': /* print out emulated ops */
+               emul(p);
+               break;
+
+       case 'F': /* print out emulate floating-point ops */
+               fpemul(p);
+               break;
+
+       case 'O': /* 64-bit left and right shift operators */
+               shiftop(p);
+               break;
+
+       case 'Q': /* emit struct assign */
+               stasg(p);
+               break;
+
+       default:
+               comperr("zzzcode %c", c);
+       }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o == NAME || o == REG || o == ICON || o == OREG ||
+           (o == UMUL && shumul(p->n_left, SOREG)))
+               return(1);
+       return 0;
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       CONSZ val;
+       int shft;
+
+       if (p->n_op == ASSIGN)
+               p = p->n_left;
+
+       if (features(FEATURE_BIGENDIAN))
+               shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
+       else
+               shft = UPKFOFF(p->n_rval);
+
+       switch (**cp) {
+       case 'S':
+               printf("%d", UPKFSZ(p->n_rval));
+               break;
+       case 'H':
+               printf("%d", shft);
+               break;
+       case 'M':
+       case 'N':
+               val = (CONSZ)1 << UPKFSZ(p->n_rval);
+               --val;
+               val <<= shft;
+               printf(CONFMT, (**cp == 'M' ? val : ~val)  & 0xffffffff);
+               break;
+       default:
+               comperr("fldexpand");
+       }
+       return 1;
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o == OREG || o == REG || o == NAME)
+               return SRDIR; /* Direct match */
+       if (o == UMUL && shumul(p->n_left, SOREG))
+               return SROREG; /* Convert into oreg */
+       return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+       printf("; shtemp\n");
+       return 0;
+#if 0
+       int r;
+
+       if (p->n_op == STARG )
+               p = p->n_left;
+
+       switch (p->n_op) {
+       case REG:
+               return (!istreg(regno(p)));
+
+       case OREG:
+               r = regno(p);
+               if (R2TEST(r)) {
+                       if (istreg(R2UPK1(r)))
+                               return(0);
+                       r = R2UPK2(r);
+               }
+               return (!istreg(r));
+
+       case UMUL:
+               p = p->n_left;
+               return (p->n_op != UMUL && shtemp(p));
+       }
+
+       if (optype(p->n_op) != LTYPE)
+               return(0);
+       return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+       printf( CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       int val = p->n_lval;
+
+       switch (p->n_op) {
+       case ICON:
+               if (p->n_name[0] != '\0') {
+                       fprintf(fp, "%s", p->n_name);
+                       if (val)
+                               fprintf(fp, "+%d", val);
+               } else {
+                       if (GCLASS(p->n_type) == CLASSB)
+                               fprintf(fp, CONFMT, p->n_lval >> 32);
+                       else
+                               fprintf(fp, "%d", val);
+               }
+               return;
+
+       default:
+               comperr("illegal conput, p %p", p);
+       }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+       comperr("insput");
+}
+
+/*
+ * Print lower or upper name of 64-bit register.
+ */
+static void
+reg64name(int reg, int hi)
+{
+       int idx;
+       int off = 0;
+
+       idx = (reg > R14R15 ? (2*(reg - R14R15) + R14) : (reg - R3R4 + R3));
+
+       if ((hi == HIREG && !features(FEATURE_BIGENDIAN)) ||
+           (hi == LOWREG && features(FEATURE_BIGENDIAN)))
+               off = 1;
+               
+       printf("%s" , rnames[idx + off]);
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               reg64name(regno(p), HIREG);
+               break;
+
+       case NAME:
+       case OREG:
+               if (features(FEATURE_BIGENDIAN))
+                       printf("%d", (int)p->n_lval);
+               else
+                       printf("%d", (int)(p->n_lval + 4));
+               printf("(%s)", rnames[regno(p)]);
+               break;
+
+       case ICON:
+               printf(CONFMT, p->n_lval >> 32);
+               break;
+
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+       /* output an address, with offsets, from p */
+
+       if (p->n_op == FLD)
+               p = p->n_left;
+
+       switch (p->n_op) {
+
+       case NAME:
+               if (p->n_name[0] != '\0') {
+                       fputs(p->n_name, io);
+                       if (p->n_lval != 0)
+                               fprintf(io, "+" CONFMT, p->n_lval);
+               } else
+                       fprintf(io, CONFMT, p->n_lval);
+               return;
+
+       case OREG:
+               if (DEUNSIGN(p->n_type) == LONGLONG &&
+                   features(FEATURE_BIGENDIAN))
+                       fprintf(io, "%d", (int)(p->n_lval + 4));
+               else
+                       fprintf(io, "%d", (int)p->n_lval);
+               fprintf(io, "(%s)", rnames[regno(p)]);
+               return;
+
+       case ICON:
+               /* addressable value of the constant */
+               conput(io, p);
+               return;
+
+       case REG:
+               if (GCLASS(regno(p)) == CLASSB)
+                       reg64name(regno(p), LOWREG);
+               else
+                       fprintf(io, "%s", rnames[regno(p)]);
+#if 0
+               switch (p->n_type) {
+               case DOUBLE:
+               case LDOUBLE:
+                       if (features(FEATURE_HARDFLOAT)) {
+                               fprintf(io, "%s", rnames[regno(p)]);
+                               break;
+                       }
+                       /* FALL-THROUGH */
+               case LONGLONG:
+               case ULONGLONG:
+                       reg64name(regno(p), LOWREG);
+                       break;
+               default:
+                       fprintf(io, "%s", rnames[regno(p)]);
+               }
+#endif
+               return;
+
+       default:
+               comperr("illegal address, op %d, node %p", p->n_op, p);
+               return;
+
+       }
+}
+
+/*
+ * these mnemonics match the order of the preprocessor decls
+ * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
+ */
+
+static char *
+ccbranches[] = {
+       "beq",          /* branch if equal */
+       "bne",          /* branch if not-equal */
+       "ble",          /* branch if less-than-or-equal */
+       "blt",          /* branch if less-than */
+       "bge",          /* branch if greater-than-or-equal */
+       "bgt",          /* branch if greater-than */
+       /* what should these be ? */
+       "ble",          /* branch if less-than-or-equal */
+       "blt",          /* branch if less-than */
+       "bge",          /* branch if greater-than-or-equal */
+       "bgt",          /* branch if greater-than */
+
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+       if (o < EQ || o > UGT)
+               comperr("bad conditional branch: %s", opst[o]);
+       printf("\t%s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static int
+argsize(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (t < LONGLONG || t == FLOAT || t > BTMASK)
+               return 4;
+       if (t == LONGLONG || t == ULONGLONG)
+               return 8;
+       if (t == DOUBLE || t == LDOUBLE)
+               return 8;
+       if (t == STRTY || t == UNIONTY)
+               return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+       comperr("argsize");
+       return 0;
+}
+
+static int
+calc_args_size(NODE *p)
+{
+       int n = 0;
+        
+        if (p->n_op == CM) {
+                n += calc_args_size(p->n_left);
+                n += calc_args_size(p->n_right);
+                return n;
+        }
+
+        n += argsize(p);
+
+        return n;
+}
+
+
+static void
+fixcalls(NODE *p, void *arg)
+{
+       int n = 0;
+
+       switch (p->n_op) {
+       case STCALL:
+       case CALL:
+               n = calc_args_size(p->n_right);
+               if (n > p2maxstacksize)
+                       p2maxstacksize = n;
+               /* FALLTHROUGH */
+       case USTCALL:
+       case UCALL:
+               ++p2calls;
+               break;
+       case TEMP:
+               p2temps += argsize(p);
+               break;
+       }
+}
+
+/*
+ * Must store floats in memory if there are two function calls involved.
+ */
+static int
+storefloat(struct interpass *ip, NODE *p)
+{
+       int l, r;
+
+       switch (optype(p->n_op)) {
+       case BITYPE:
+               l = storefloat(ip, p->n_left);
+               r = storefloat(ip, p->n_right);
+               if (p->n_op == CM)
+                       return 0; /* arguments, don't care */
+               if (callop(p->n_op))
+                       return 1; /* found one */
+#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
+       (p)->n_type == LDOUBLE)
+               if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
+                       /* must store one. store left */
+                       struct interpass *nip;
+                       TWORD t = p->n_left->n_type;
+                       NODE *ll;
+                       int off;
+
+                       off = (freetemp(szty(t)));
+                       ll = mklnode(OREG, off, SPREG, t);
+                       nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
+                       p->n_left = mklnode(OREG, off, SPREG, t);
+                       DLIST_INSERT_BEFORE(ip, nip, qelem);
+               }
+               return l|r;
+
+       case UTYPE:
+               l = storefloat(ip, p->n_left);
+               if (callop(p->n_op))
+                       l = 1;
+               return l;
+       default:
+               return 0;
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       p2calls = 0;
+       p2temps = 0;
+       p2maxstacksize = 0;
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               walkf(ip->ip_node, fixcalls, 0);
+               storefloat(ip, ip->ip_node);
+       }
+
+       if (p2maxstacksize < NARGREGS*SZINT/SZCHAR)
+               p2maxstacksize = NARGREGS*SZINT/SZCHAR;
+
+       p2framesize = ARGINIT/SZCHAR;           /* stack ptr / return addr */
+       p2framesize += 8;                       /* for R31 and R30 */
+       p2framesize += p2maxautooff;            /* autos */
+       p2framesize += p2temps;                 /* TEMPs that aren't autos */
+       if (p2calls != 0)
+               p2framesize += p2maxstacksize;  /* arguments to functions */
+       p2framesize += (ALSTACK/SZCHAR - 1);    /* round to 16-byte boundary */
+       p2framesize &= ~(ALSTACK/SZCHAR - 1);
+
+#if 0
+       printf("!!! MYREADER\n");
+       printf("!!! p2maxautooff = %d\n", p2maxautooff);
+       printf("!!! p2autooff = %d\n", p2autooff);
+       printf("!!! p2temps = %d\n", p2temps);
+       printf("!!! p2calls = %d\n", p2calls);
+       printf("!!! p2maxstacksize = %d\n", p2maxstacksize);
+#endif
+
+       if (x2debug)
+               printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+       NODE *q;
+
+       if (p->n_op == PLUS) {
+               if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+                       if (p->n_right->n_op != ICON)
+                               return;
+                       if (p->n_left->n_op != PCONV)
+                               return;
+                       if (p->n_left->n_left->n_op != OREG)
+                               return;
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       /*
+                        * This will be converted to another OREG later.
+                        */
+               }
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+       walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+#ifdef PCC_DEBUG
+       if (x2debug) {
+               printf("myoptim\n");
+       }
+#endif
+}
+
+/*
+ * Move data between registers.  While basic registers aren't a problem,
+ * we have to handle the special case of overlapping composite registers.
+ * It might just be easier to modify the register allocator so that
+ * moves between overlapping registers isn't possible.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+       switch (t) {
+       case LDOUBLE:
+       case DOUBLE:
+               if (features(FEATURE_HARDFLOAT)) {
+                       printf("\tfmr %s,%s" COM "rmove\n",
+                           rnames[d], rnames[s]);
+                       break;
+               }
+               /* FALL-THROUGH */
+       case LONGLONG:
+       case ULONGLONG:
+               if (s == d+1) {
+                       /* dh = sl, copy low word first */
+                       printf("\tmr ");
+                       reg64name(d, LOWREG);
+                       printf(",");
+                       reg64name(s, LOWREG);
+                       printf("\n");
+                       printf("\tmr ");
+                       reg64name(d, HIREG);
+                       printf(",");
+                       reg64name(s, HIREG);
+                       printf("\n");
+               } else {
+                       /* copy high word first */
+                       printf("\tmr ");
+                       reg64name(d, HIREG);
+                       printf(",");
+                       reg64name(s, HIREG);
+                       printf("\n");
+                       printf("\tmr ");
+                       reg64name(d, LOWREG);
+                       printf(",");
+                       reg64name(s, LOWREG);
+                       printf("\n");
+               }
+               break;
+       case FLOAT:
+               if (features(FEATURE_HARDFLOAT)) {
+                       printf("\tfmr %s,%s" COM "rmove\n",
+                           rnames[d], rnames[s]);
+                       break;
+               }
+               /* FALL-THROUGH */
+       default:
+               printf("\tmr %s,%s" COM "rmove\n", rnames[d], rnames[s]);
+       }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ *
+ * On PowerPC, we have:
+ *
+ * 32 32-bit registers (2 reserved)
+ * 16 64-bit pseudo registers
+ * 32 floating-point registers
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num = 0;
+
+        switch (c) {
+        case CLASSA:
+                num += r[CLASSA];
+                num += 2*r[CLASSB];
+                return num < 30;
+        case CLASSB:
+                num += 2*r[CLASSB];
+                num += r[CLASSA];
+                return num < 16;
+       case CLASSC:
+               return num < 32;
+        case CLASSD:
+                return r[CLASSD] < DREGCNT;
+        }
+        return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       if (t == LONGLONG || t == ULONGLONG)
+               return CLASSB;
+       if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
+               if (features(FEATURE_HARDFLOAT))
+                       return CLASSC;
+               if (t == FLOAT)
+                       return CLASSA;
+               else
+                       return CLASSB;
+       }
+       return CLASSA;
+}
+
+int
+retreg(int t)
+{
+       int c = gclass(t);
+       if (c == CLASSB)
+               return R3R4;
+       else if (c == CLASSC)
+               return F1;
+       return R3;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+#ifdef PCC_DEBUG
+       if (x2debug)
+               printf("lastcall:\n");
+#endif
+
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               size += argsize(p->n_right);
+       size += argsize(p);
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       int o = p->n_op;
+
+       switch (shape) {
+       case SFUNCALL:
+               if (o == STCALL || o == USTCALL)
+                       return SRREG;
+               break;
+       case SPCON:
+               if (o == ICON && p->n_name[0] == 0 && (p->n_lval & ~0x7fff) == 0)
+                       return SRDIR;
+               break;
+       }
+       return SRNOPE;
+}
+
+static int fset = FEATURE_BIGENDIAN | FEATURE_HARDFLOAT;
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+       if (strcasecmp(str, "big-endian") == 0) {
+               fset |= FEATURE_BIGENDIAN;
+       } else if (strcasecmp(str, "little-endian") == 0) {
+               fset &= ~FEATURE_BIGENDIAN;
+       } else if (strcasecmp(str, "soft-float") == 0) {
+               fset &= ~FEATURE_HARDFLOAT;
+       } else if (strcasecmp(str, "hard-float") == 0) {
+               fset |= FEATURE_HARDFLOAT;
+       } else {
+               fprintf(stderr, "unknown m option '%s'\n", str);
+               exit(1);
+       }
+}
+
+int
+features(int mask)
+{
+       return ((fset & mask) == mask);
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/powerpc/macdefs.h b/lang/pcc/pcc/arch/powerpc/macdefs.h
new file mode 100644 (file)
index 0000000..72cc2b6
--- /dev/null
@@ -0,0 +1,407 @@
+/*     $Id: macdefs.h,v 1.18 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR         8
+#define SZBOOL         32
+#define SZINT          32
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#ifdef ELFABI
+#define SZLDOUBLE      96
+#else
+#define SZLDOUBLE      128
+#endif
+#define SZLONG         32
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR         8
+#define ALBOOL         32
+#define ALINT          32
+#define ALFLOAT                32
+#define ALDOUBLE       32
+#ifdef ELFABI
+#define ALLDOUBLE      32
+#else
+#define ALLDOUBLE      128
+#endif
+#define ALLONG         32
+#ifdef ELFABI
+#define ALLONGLONG     64
+#else
+#define ALLONGLONG     32
+#endif
+#define ALSHORT                16
+#define ALPOINT                32
+#define ALSTRUCT       32
+#define ALSTACK                (16*SZCHAR)
+
+/*
+ * Min/max values.
+ */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         -1
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffff
+#define        MIN_LONG        MIN_INT
+#define        MAX_LONG        MAX_INT
+#define        MAX_ULONG       MAX_UNSIGNED
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+
+#define CHAR_UNSIGNED
+#define        BOOL_TYPE       INT     /* what used to store _Bool */
+
+/*
+ * Use large-enough types.
+ */
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"          /* format for printing constants */
+#if defined(ELFABI)
+#define LABFMT ".L%d"          /* format for printing labels */
+#define REGPREFIX      "%"     /* format for printing registers */
+#elif defined(MACHOABI)
+#define LABFMT "L%d"           /* format for printing labels */
+#define REGPREFIX
+#else
+#error undefined ABI
+#endif
+#define        STABLBL "LL%d"          /* format for stab (debugging) labels */
+
+#ifdef MACHOABI
+#define STAB_LINE_ABSOLUTE     /* S_LINE fields use absolute addresses */
+#endif
+
+#undef FIELDOPS                /* no bit-field instructions */
+#define TARGET_ENDIAN TARGET_BE
+#define MYINSTRING
+#define MYALIGN
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)     ((x)&03)
+
+#define        szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \
+       DEUNSIGN(t) == LONGLONG) ? 2 : 1)
+
+/*
+ * The PPC register definition are taken from apple docs.
+ *
+ * The classes used are:
+ *     A - general registers
+ *     B - 64-bit register pairs
+ *     C - floating-point registers
+ */
+
+#define R0     0       /* scratch register */
+#define R1     1       /* stack base pointer */
+#define R2     2
+#define R3     3       /* return register / argument 0 */
+#define R4     4       /* return register (for longlong) / argument 1 */
+#define R5     5       /* scratch register / argument 2 */
+#define R6     6       /* scratch register / argument 3 */
+#define R7     7       /* scratch register / argument 4 */
+#define R8     8       /* scratch register / argument 5 */
+#define R9     9       /* scratch register / argument 6 */
+#define R10    10      /* scratch register / argument 7 */
+#define R11    11      /* scratch register */
+#define R12    12      /* scratch register */
+#define R13    13
+#define R14    14
+#define R15    15
+#define R16    16
+#define R17    17
+#define R18    18
+#define R19    19
+#define R20    20
+#define R21    21
+#define R22    22
+#define R23    23
+#define R24    24
+#define R25    25
+#define R26    26
+#define R27    27
+#define R28    28
+#define R29    29
+#define R30    30
+#define R31    31
+
+#define R3R4   32
+#define R4R5   33
+#define R5R6   34
+#define R6R7   35
+#define R7R8   36
+#define R8R9   37
+#define R9R10  38
+#define R14R15 39
+#define R16R17 40
+#define R18R19 41
+#define R20R21 42
+#define R22R23 43
+#define R24R25 44
+#define R26R27 45
+#define R28R29 46
+#define R30R31 47
+
+#define F0     48      /* scratch register */
+#define F1     49      /* return value 0 / argument 0 */
+#define F2     50      /* return value 1 / argument 1 */
+#define F3     51      /* return value 2 / argument 2 */
+#define F4     52      /* return value 3 / argument 3 */
+#define F5     53      /* argument 4 */
+#define F6     54      /* argument 5 */
+#define F7     55      /* argument 6 */
+#define F8     56      /* argument 7 */
+#define F9     57      /* argument 8 */
+#define F10    58      /* argument 9 */
+#define F11    59      /* argument 10 */
+#define F12    60      /* argument 11 */
+#define F13    61      /* argument 12 */
+#define F14    62
+#define F15    63
+#define F16    64
+#define F17    65
+#define F18    66
+#define F19    67
+#define F20    68
+#define F21    69
+#define F22    70
+#define F23    71
+#define F24    72
+#define F25    73
+#define F26    74
+#define F27    75
+#define F28    76
+#define F29    77
+#define F30    78
+#define F31    79
+
+#define NUMCLASS 3
+#define        MAXREGS 64              /* XXX cannot have more than 64 */
+
+#define RSTATUS                                \
+       0,                      /* R0 */        \
+       0,                      /* R1 */        \
+       SAREG|TEMPREG,          /* R2 */        \
+       SAREG|TEMPREG,          /* R3 */        \
+       SAREG|TEMPREG,          /* R4 */        \
+       SAREG|TEMPREG,          /* R5 */        \
+       SAREG|TEMPREG,          /* R6 */        \
+       SAREG|TEMPREG,          /* R7 */        \
+       SAREG|TEMPREG,          /* R8 */        \
+       SAREG|TEMPREG,          /* R9 */        \
+       SAREG|TEMPREG,          /* R10 */       \
+       SAREG|TEMPREG,          /* R11 */       \
+       SAREG|TEMPREG,          /* R12 */       \
+       SAREG,                  /* R13 */       \
+       SAREG,                  /* R14 */       \
+       SAREG,                  /* R15 */       \
+       SAREG,                  /* R16 */       \
+       SAREG,                  /* R17 */       \
+       SAREG,                  /* R18 */       \
+       SAREG,                  /* R19 */       \
+       SAREG,                  /* R20 */       \
+       SAREG,                  /* R21 */       \
+       SAREG,                  /* R22 */       \
+       SAREG,                  /* R23 */       \
+       SAREG,                  /* R24 */       \
+       SAREG,                  /* R25 */       \
+       SAREG,                  /* R26 */       \
+       SAREG,                  /* R27 */       \
+       SAREG,                  /* R28 */       \
+       SAREG,                  /* R29 */       \
+       SAREG,                  /* R30 */       \
+       SAREG,                  /* R31 */       \
+       \
+        SBREG|TEMPREG,         /* R3R4 */      \
+       SBREG|TEMPREG,          /* R4R5 */      \
+       SBREG|TEMPREG,          /* R5R6 */      \
+       SBREG|TEMPREG,          /* R6R7 */      \
+        SBREG|TEMPREG,         /* R7R8 */      \
+       SBREG|TEMPREG,          /* R8R9 */      \
+       SBREG|TEMPREG,          /* R9R10 */     \
+       \
+       SBREG,                  /* R14R15 */    \
+       SBREG,                  /* R16R17 */    \
+       SBREG,                  /* R18R19 */    \
+       SBREG,                  /* R20R21 */    \
+       SBREG,                  /* R22R23 */    \
+       SBREG,                  /* R24R25 */    \
+       SBREG,                  /* R26R2k */    \
+       SBREG,                  /* R28R29 */    \
+       SBREG,                  /* R30R31 */    \
+       \
+       SCREG|TEMPREG,          /* F0 */        \
+       SCREG|TEMPREG,          /* F1 */        \
+       SCREG|TEMPREG,          /* F2 */        \
+       SCREG|TEMPREG,          /* F3 */        \
+       SCREG|TEMPREG,          /* F4 */        \
+       SCREG|TEMPREG,          /* F5 */        \
+       SCREG|TEMPREG,          /* F6 */        \
+       SCREG|TEMPREG,          /* F7 */        \
+       SCREG|TEMPREG,          /* F8 */        \
+       SCREG|TEMPREG,          /* F9 */        \
+       SCREG|TEMPREG,          /* F10 */       \
+       SCREG|TEMPREG,          /* F11 */       \
+       SCREG|TEMPREG,          /* F12 */       \
+       SCREG|TEMPREG,          /* F13 */       \
+       SCREG,                  /* F14 */       \
+       SCREG,                  /* F15 */       \
+
+#define ROVERLAP \
+       { -1 }, { -1 }, { -1 },                 \
+       { R3R4,       -1 }, { R3R4, R4R5, -1 }, \
+       { R4R5, R5R6, -1 }, { R5R6, R6R7, -1 }, \
+       { R6R7, R7R8, -1 }, { R7R8, R8R9, -1 }, \
+       { R8R9, R9R10, -1 }, { R9R10, -1 },     \
+       { -1 }, { -1 }, { -1 },                 \
+       { R14R15, -1 }, { R14R15, -1 },         \
+       { R16R17, -1 }, { R16R17, -1 },         \
+       { R18R19, -1 }, { R18R19, -1 },         \
+       { R20R21, -1 }, { R20R21, -1 },         \
+       { R22R23, -1 }, { R22R23, -1 },         \
+       { R24R25, -1 }, { R24R25, -1 },         \
+       { R26R27, -1 }, { R26R27, -1 },         \
+       { R28R29, -1 }, { R28R29, -1 },         \
+       { R30R31, -1 }, { R30R31, -1 },         \
+       \
+       { R3, R4,       R4R5, -1 }, { R4, R5, R3R4, R5R6, -1 }, \
+       { R5, R6, R4R5, R6R7, -1 }, { R6, R7, R5R6, R7R8, -1 }, \
+       { R7, R8, R6R7, R8R9, -1 }, { R8, R9, R7R8, R8R9, -1 }, \
+       { R9, R10, R8R9,      -1 },     \
+       { R14, R15, -1 }, { R16, R17, -1 },     \
+       { R18, R19, -1 }, { R20, R21, -1 },     \
+       { R22, R23, -1 }, { R24, R25, -1 },     \
+       { R26, R27, -1 }, { R28, R29, -1 },     \
+       { R30, R31, -1 },               \
+       \
+       { -1 }, { -1 }, { -1 }, { -1 },         \
+       { -1 }, { -1 }, { -1 }, { -1 },         \
+       { -1 }, { -1 }, { -1 }, { -1 },         \
+       { -1 }, { -1 }, { -1 }, { -1 },         \
+
+/*
+ * According to the ABI documents, there isn't really a frame pointer;
+ * all references to data on the stack (autos and parameters) are
+ * indexed relative to the stack pointer.  However, pcc isn't really
+ * capable of running in this manner, and expects a frame pointer.
+ */
+#define SPREG   R1     /* stack pointer */
+#define FPREG   R30    /* frame pointer */
+#define GOTREG R31     /* global offset table (PIC) */
+
+#ifdef FPREG
+#define ARGINIT                (24*8)  /* # bits above fp where arguments start */
+#define AUTOINIT       (8*8)   /* # bits above fp where automatics start */
+#define BACKAUTO               /* stack grows negatively for automatics */
+#define BACKTEMP               /* stack grows negatively for temporaries */
+#else
+#define ARGINIT                (24*8)  /* # bits above fp where arguments start */
+#define AUTOINIT       (56*8)  /* # bits above fp where automatics start */
+#endif
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p)      (1 << gclass((p)->n_type))
+
+#define GCLASS(x)      ((x) < 32 ? CLASSA : ((x) < 48 ? CLASSB : CLASSC))
+#define DECRA(x,y)     (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRA(x,y)     ((x) << (6+y*6))        /* encode regs in int */
+#define ENCRD(x)       (x)             /* Encode dest reg in n_reg */
+#define RETREG(x)      retreg(x)
+
+int COLORMAP(int c, int *r);
+int retreg(int ty);
+
+#define        SHSTR           (MAXSPECIAL+1)  /* short struct */
+#define        SFUNCALL        (MAXSPECIAL+2)  /* struct assign after function call */
+#define SPCON          (MAXSPECIAL+3)  /* positive constant */
+
+int features(int f);
+#define FEATURE_BIGENDIAN      0x00010000
+#define FEATURE_PIC            0x00020000
+#define FEATURE_HARDFLOAT      0x00040000
+
+struct stub {
+       struct { struct stub *q_forw, *q_back; } link;
+       char *name;
+};
+extern struct stub stublist;
+extern struct stub nlplist;
+void addstub(struct stub *list, char *name);
+
+#define TARGET_STDARGS
+#define TARGET_BUILTINS                                                        \
+       { "__builtin_stdarg_start", powerpc_builtin_stdarg_start },     \
+       { "__builtin_va_arg", powerpc_builtin_va_arg },                 \
+       { "__builtin_va_end", powerpc_builtin_va_end },                 \
+       { "__builtin_va_copy", powerpc_builtin_va_copy },               \
+       { "__builtin_frame_address", powerpc_builtin_frame_address },   \
+       { "__builtin_return_address", powerpc_builtin_return_address },
+
+#define NODE struct node
+struct node;
+NODE *powerpc_builtin_stdarg_start(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_va_arg(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_va_end(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_va_copy(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_frame_address(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_return_address(NODE *f, NODE *a, unsigned int);
+#undef NODE
+
+#define NARGREGS       8
+
+#ifdef ELFABI
+#define COM     "       # "
+#else
+#define COM     "       ; "
+#endif
diff --git a/lang/pcc/pcc/arch/powerpc/order.c b/lang/pcc/pcc/arch/powerpc/order.c
new file mode 100644 (file)
index 0000000..61782cd
--- /dev/null
@@ -0,0 +1,408 @@
+/*     $Id: order.c,v 1.8 2009/01/07 11:44:03 gmcgarry Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/*
+ * Check size of offset in OREG.  Called by oregok() to see if an
+ * OREG can be generated.
+ *
+ * returns 0 if it can, 1 otherwise.
+ */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+#if 0
+       if (off >= 32767 || off <= -32768)
+               printf("; notoff %lld TOO BIG!\n", off);
+#endif
+       if (cp && cp[0]) return 1;
+       return (off >= 32768 || off <= -32769);
+}
+
+/*
+ * Generate instructions for an OREG.
+ * Called by swmatch().
+ */
+void
+offstar(NODE *p, int shape)
+{
+       NODE *r;
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+       r = p->n_right;
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( r->n_op == ICON ){
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+/*
+ * Unable to convert to OREG (notoff() returned failure).  Output
+ * suitable instructions to replace OREG.
+ */
+void
+myormake(NODE *q)
+{
+       NODE *p;
+
+       if (x2debug)
+               printf("myormake(%p)\n", q);
+
+        p = q->n_left;
+
+       /*
+        * This handles failed OREGs conversions, due to the offset
+        * being too large for an OREG.
+        */
+       if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) {
+               if (isreg(p->n_left) == 0)
+                       (void)geninsn(p->n_left, INAREG);
+               if (isreg(p->n_right) == 0)
+                       (void)geninsn(p->n_right, INAREG);
+               (void)geninsn(p, INAREG);
+       } else if (p->n_op == REG) {
+               q->n_op = OREG;
+               q->n_lval = p->n_lval;
+               q->n_rval = p->n_rval;
+               tfree(p);
+       }
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on x86 */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+       if (x2debug)
+               printf("setbin(%p)\n", p);
+       return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+       if (x2debug)
+               printf("setasg(%p)\n", p);
+       return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       if (x2debug)
+               printf("nspecial: op=%d, visit=0x%x: %s", q->op, q->visit, q->cstring);
+
+       switch (q->op) {
+
+       /* soft-float stuff */
+        case RS:
+        case LS:
+                if (q->lshape == SBREG) {
+                        static struct rspecial s[] = {
+                                { NLEFT, R3R4 },
+                                { NRIGHT, R5 },
+                                { NRES, R3R4 },
+                                { 0 },
+                        };
+                        return s;
+                } else if (q->lshape == SAREG) {
+                        static struct rspecial s[] = {
+                                { NLEFT, R3 },
+                                { NRIGHT, R4 },
+                                { NRES, R3 },
+                                { 0 },
+                        };
+                        return s;
+                }
+
+               cerror("nspecial LS/RS");
+               break;
+
+       case UMINUS:
+       case SCONV:
+               if (q->lshape == SBREG && q->rshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3R4 },
+                               { NRES, R3 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG && q->rshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3 },
+                               { NRES, R3R4 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG && q->rshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3 },
+                               { NRES, R3 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SBREG && q->rshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3R4 },
+                               { NRES, R3R4 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SCREG && q->rshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, F1 },
+                               { NEVER, F0 }, /* stomped on */
+                               { NRES, R3R4 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SBREG && q->rshape == SCREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3R4 },
+                               { NEVER, F0 }, /* stomped on */
+                               { NRES, F1 },
+                               { 0 }
+                       };
+                       return s;
+               } else {
+                       static struct rspecial s[] = {
+                               { NOLEFT, R0 },
+                               { 0 } };
+                       return s;
+               }
+
+               break;
+
+       case OPLOG:
+               if (q->lshape == SBREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3R4 },
+                               { NRIGHT, R5R6 },
+                               { NRES, R3 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3 },
+                               { NRIGHT, R4 },
+                               { NRES, R3 },
+                               { 0 }
+                       };
+                       return s;
+               }
+
+               cerror("nspecial oplog");
+               break;
+
+       case PLUS:
+       case MINUS:
+       case MUL:
+       case DIV:
+       case MOD:
+               if (q->lshape == SBREG && 
+                   (q->ltype & (TDOUBLE|TLDOUBLE|TLONGLONG|TULONGLONG))) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3R4 },
+                               { NRIGHT, R5R6 },
+                               { NRES, R3R4 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG && q->ltype & TFLOAT) {
+                       static struct rspecial s[] = {
+                               { NLEFT, R3 },
+                               { NRIGHT, R4 },
+                               { NRES, R3 },
+                               { 0 }
+                       };
+                       return s;
+               } else if (q->lshape == SAREG) {
+                       static struct rspecial s[] = {
+                               { NOLEFT, R0 },
+                               { 0 } };
+                       return s;
+               }
+
+               cerror("nspecial mul");
+               break;
+
+       case STASG:
+               {
+                       static struct rspecial s[] = {
+                               { NEVER, R3 },
+                               { NRIGHT, R4 },
+                               { NEVER, R5 },
+                               { 0 } };
+                       return s;
+               }
+               break;
+
+       case OPLTYPE:
+               {
+                       if (q->visit & SAREG) {
+                               static struct rspecial s[] = {
+                                       { NEVER, R0 },
+                                       { 0 } };
+                               return s;
+                       }
+               }
+               break;
+
+       case ASSIGN:
+               if (q->lshape & SNAME) {
+                       static struct rspecial s[] = {
+                               { NEVER, R0 },
+                               { 0 } };
+                       return s;
+               } else if (q->rshape & SNAME) {
+                       static struct rspecial s[] = {
+                               { NOLEFT, R0 },
+                               { 0 } };
+                       return s;
+               } else if (q->lshape & SOREG) {
+                       static struct rspecial s[] = {
+                               { NOLEFT, R0 },
+                               { 0 } };
+                       return s;
+               } else if (q->rshape & SOREG) {
+                       static struct rspecial s[] = {
+                               { NORIGHT, R0 },
+                               { 0 } };
+                       return s;
+               }
+               /* fallthough */
+
+       case UMUL:
+       case AND:
+       case OR:
+       case ER:
+               {
+                       static struct rspecial s[] = {
+                               { NOLEFT, R0 },
+                               { 0 } };
+                       return s;
+               }
+
+       default:
+               break;
+       }
+
+       comperr("nspecial entry %d: %s", q - table, q->cstring);
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on x86 */
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[] = { R10, R9, R8, R7, R6, R5, R4, R3, R30, R31, -1 };
+       int num = 1;
+
+        if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+                return &r[8-0];
+
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+                num += szty(p->n_right->n_type);
+        num += szty(p->n_right->n_type);
+
+        num = (num > 8 ? 8 : num);
+
+        return &r[8 - num];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       if ((op->visit & FEATURE_PIC) != 0)
+               return (kflag != 0);
+       return features(op->visit & 0xffff0000);
+}
diff --git a/lang/pcc/pcc/arch/powerpc/table.c b/lang/pcc/pcc/arch/powerpc/table.c
new file mode 100644 (file)
index 0000000..5f81d77
--- /dev/null
@@ -0,0 +1,1806 @@
+/*     $Id: table.c,v 1.18 2010/11/26 17:06:31 ragge Exp $     */
+/*-
+ * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * A template has five logical sections:
+ *
+ *     1) subtree (operator); goal to achieve (cookie)
+ *     2) left node descendent of operator (node class; type)
+ *     3) right node descendent of operator (node class; type)
+ *     4) resource requirements (number of scratch registers);
+ *        subtree rewriting rule
+ *     5) emitted instructions
+ */
+
+#include "pass2.h"
+
+#define TUWORD TUNSIGNED|TULONG
+#define TSWORD TINT|TLONG
+#define TWORD  TUWORD|TSWORD
+
+#if defined(ELFABI)
+#define HA16(x)        # x "@ha"
+#define LO16(x)        # x "@l"
+#elif defined(MACHOABI)
+#define HA16(x)        "ha16(" # x ")"
+#define LO16(x)        "lo16(" # x ")"
+#else
+#error undefined ABI
+#endif
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD|TPOINT,
+       SAREG,  TWORD|TPOINT,
+               0,      RLEFT,
+               COM "pointer conversion\n", },
+
+/*
+ * Conversions of integral types
+ */
+
+{ SCONV,       INAREG,
+       SAREG,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR,
+               0,      RLEFT,
+               COM "convert between (u)char and (u)char\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               0,      RLEFT,
+               COM "convert between (u)short and (u)short\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TPOINT|TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               COM "convert a pointer/word to an int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TPOINT,
+       SAREG,  TPOINT,
+               0,      RLEFT,
+               COM "convert pointers\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               0,      RLEFT,
+               COM "convert (u)longlong to (u)longlong\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TCHAR,
+       SAREG,  TSHORT|TSWORD,
+               NASL|NAREG,     RESC1,
+               "       extsb A1,AL" COM "convert char to short/int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUCHAR,
+       SAREG,  TSHORT|TSWORD,
+               0,      RLEFT,
+               COM "convert uchar to short/int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUCHAR,
+       SAREG,  TUSHORT|TUWORD,
+               0,      RLEFT,
+               COM "convert uchar to ushort/unsigned\n", },
+
+/* XXX is this necessary? */
+{ SCONV,       INAREG,
+       SAREG,  TCHAR,
+       SAREG,  TUSHORT|TUWORD,
+               NSPECIAL|NAREG|NASL,    RESC1,
+               "       extsb A1,AL" COM "convert char to ushort/unsigned\n", },
+
+{ SCONV,       INBREG | FEATURE_BIGENDIAN,
+       SAREG,  TUCHAR|TUSHORT|TUNSIGNED,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG,          RESC1,
+               "       mr U1,AL" COM "convert uchar/ushort/uint to (u)longlong\n"
+               "       li A1,0\n", },
+
+{ SCONV,       INBREG,
+       SAREG,  TUCHAR|TUSHORT|TUNSIGNED,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG,          RESC1,
+               "       mr A1,AL" COM "convert uchar/ushort/uint to (u)longlong\n"
+               "       li U1,0\n", },
+
+{ SCONV,       INBREG | FEATURE_BIGENDIAN,
+       SAREG,  TCHAR|TSHORT|TSWORD,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NBREG,          RESC1,
+               "       mr U1,AL" COM "convert char/short/int to ulonglong\n"
+               "       srawi A1,AL,31\n", },
+
+{ SCONV,       INBREG,
+       SAREG,  TCHAR|TSHORT|TSWORD,
+       SBREG,  TULONGLONG|TLONGLONG,
+               NBREG,          RESC1,
+               "       mr A1,AL" COM "convert char/short/int to ulonglong\n"
+               "       srawi U1,AL,31\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT,
+       SAREG,  TCHAR|TUCHAR,
+               NSPECIAL|NAREG|NASL,    RESC1,
+               "       andi. A1,AL,255" COM "convert (u)short to (u)char\n", },
+
+/* XXX is this really necessary? */
+{ SCONV,       INAREG,
+       SAREG,  TSHORT,
+       SAREG,  TWORD,
+               NAREG|NASL,     RESC1,
+               "       extsh A1,AL" COM "convert short to int\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUSHORT,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG|NASL,    RESC1,
+               COM "convert ushort to word\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       andi. A1,AL,255" COM "convert (u)int to (u)char\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       andi. A1,AL,65535" COM "convert (u)int to (u)short\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TCHAR|TUCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       andi. A1,AL,255" COM "(u)longlong to (u)char\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       andi. A1,AL,65535" COM "(u)longlong to (u)short\n", },
+
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TWORD,
+               NAREG,          RESC1,
+               "       mr A1,AL" COM "convert (u)longlong to (u)int/long\n", },
+
+/* conversions on load from memory */
+
+{ SCONV,       INAREG,
+       SOREG,  TCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG|NSPECIAL,    RESC1,
+               "       lbz A1,AL" COM "convert char to int/long\n"
+               "       extsb A1,A1\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TUCHAR,
+       SAREG,  TWORD,
+               NASL|NAREG|NSPECIAL,    RESC1,
+               "       lbz A1,AL" COM "convert uchar to int/long\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG|NSPECIAL,    RESC1,
+               "       lha A1,AL" COM "convert short to int/long\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TUSHORT,
+       SAREG,  TWORD,
+               NASL|NAREG|NSPECIAL,    RESC1,
+               "       lhz A1,AL" COM "convert ushort to int/long\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TCHAR|TUCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       lwz A1,AL" COM "(u)longlong to (u)char\n"
+               "       andi. A1,A1,255\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       lwz A1,AL" COM "(u)longlong to (u)short\n"
+               "       andi. A1,A1,65535\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TWORD,
+               NAREG|NSPECIAL, RESC1,
+               "       lwz A1,AL" COM "(u)longlong to (u)int\n", },
+
+/*
+ * floating-point conversions
+ *
+ * There doesn't appear to be an instruction to move values between
+ * the floating-point registers and the general-purpose registers.
+ * So values are bounced into memory...
+ */
+
+{ SCONV,       INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               COM "convert float to (l)double\n", },
+
+/* soft-float */
+{ SCONV,       INBREG,
+       SAREG,  TFLOAT,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       frsp A1,AL" COM "convert (l)double to float\n", },
+
+/* soft-float */
+{ SCONV,       INAREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ SCONV,       INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               COM "convert (l)double to (l)double\n", },
+
+/* soft-float */
+{ SCONV,       INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               0,      RLEFT,
+               COM "convert (l)double to (l)double (soft-float)\n", },
+
+{ SCONV,       INCREG | FEATURE_HARDFLOAT,
+       SAREG,  TWORD,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               2*NCREG|NAREG,  RESC3,
+               "ZC", },
+
+/* soft-float */
+{ SCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+/* soft-float */
+{ SCONV,       INBREG,
+       SAREG,  TWORD,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ SCONV,       INAREG | FEATURE_HARDFLOAT,
+       SOREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+       SAREG,  TWORD,
+               2*NCREG|NAREG,  RESC1,
+               "ZC", },
+
+/* soft-float */
+{ SCONV,       INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+/* soft-float */
+{ SCONV,       INAREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SAREG,  TWORD,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+       
+{ SCONV,       INCREG | FEATURE_HARDFLOAT,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               NSPECIAL|NCREG, RESC1,
+               "ZF", },
+
+/* soft-float */
+{ SCONV,       INAREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+/* soft-float */
+{ SCONV,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ SCONV,       INBREG | FEATURE_HARDFLOAT,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+/* soft-float */
+{ SCONV,       INBREG,
+       SAREG,  TFLOAT,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+/* soft-float */
+{ SCONV,       INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       bl CL" COM "call (args, no result) to scon\n", },
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       bl CL" COM "call (no args, no result) to scon\n", },
+
+{ CALL,                INAREG,
+       SCON,   TANY,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,                INBREG,
+       SCON,   TANY,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,                INCREG | FEATURE_HARDFLOAT,
+       SCON,   TANY,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,       INCREG | FEATURE_HARDFLOAT,
+       SCON,   TANY,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,                INAREG,
+       SCON,   TANY,
+       SAREG,  TFLOAT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SAREG,  TFLOAT,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,                INBREG,
+       SCON,   TANY,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       bl CL" COM "call (no args, result) to scon\n", },
+
+
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       mtctr AL" COM "call (args, no result) to reg\n"
+               "       bctrl\n", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,
+               "       mtctr AL" COM "call (no args, no result) to reg\n"
+               "       bctrl\n", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG,  RESC1,
+               "       mtctr AL" COM "call (args, result) to reg\n"
+               "       bctrl\n", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG,  RESC1,
+               "       mtctr AL" COM "call (no args, result) to reg\n"
+               "       bctrl\n", },
+
+/* struct return */
+{ USTCALL,     FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       bl CL\n", },
+
+{ USTCALL,     INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL\n", },
+
+{ USTCALL,     INAREG,
+       SAREG,  TANY,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG,  RESC1,
+               "       mtctr AL"
+               "       bctrl\n", },
+
+{ STCALL,      FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       bl CL\n", },
+
+{ STCALL,      INAREG,
+       SCON,   TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       bl CL\n", },
+
+{ STCALL,      INAREG,
+       SAREG,  TANY,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       mtctr AL"
+               "       bctrl\n", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+
+/* XXX AL cannot be R0 */
+{ PLUS,                INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,  TANY,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       addi A1,AL,AR" COM "addition of constant\n", },
+
+/* XXX AL cannot be R0 */
+{ PLUS,                INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,  TANY,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       addic. A1,AL,AR" COM "addition of constant\n", },
+
+{ PLUS,                INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SSCON,  TANY,
+               NBREG|NBSL,     RESC1,
+               "       addic A1,AL,AR" COM "64-bit addition of constant\n"
+               "       addze U1,UL\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       add A1,AL,AR\n", },
+
+{ PLUS,                INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       add. A1,AL,AR\n", },
+
+{ PLUS,                INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       addc A1,AL,AR" COM "64-bit add\n"
+               "       adde U1,UL,UR\n", },
+
+{ PLUS,                INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,          RESC1,
+               "       fadds A1,AL,AR" COM "float add\n", },
+
+{ PLUS,                INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ PLUS,                INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       fadd A1,AL,AR" COM "(l)double add\n", },
+
+/* soft-float */
+{ PLUS,                INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZF", },
+
+{ MINUS,       INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,  TANY,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       addi A1,AL,-AR\n", },
+
+{ MINUS,       INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,  TANY,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       addic. A1,AL,-AR\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SSCON,  TANY,
+               NBREG|NBSL,     RESC1,
+               "       addic A1,AL,-AR\n"
+               "       addme U1,UL\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       subf A1,AR,AL\n", },
+
+{ MINUS,       INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       subf. A1,AR,AL\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       subfc A1,AR,AL" COM "64-bit subtraction\n"
+               "       subfe U1,UR,UL\n", },
+
+{ MINUS,       INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TFLOAT,
+       SCREG,  TFLOAT,
+               NCREG,  RESC1,
+               "       fsubs A1,AL,AR\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ MINUS,               INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TDOUBLE|TLDOUBLE,
+       SCREG,  TDOUBLE|TLDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       fsub A1,AL,AR" COM "(l)double sub\n", },
+
+/* soft-float */
+{ MINUS,               INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG|NBSL,    RESC1,
+               "ZF", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+
+{ LS,  INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       slw A1,AL,AR" COM "left shift\n", },
+
+{ LS,  INAREG|FORCC,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       slw. A1,AL,AR" COM "left shift\n", },
+
+{ LS,  INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       slwi A1,AL,AR" COM "left shift by constant\n", },
+
+{ LS,  INAREG|FORCC,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       slwi. A1,AL,AR" COM "left shift by constant\n", },
+
+{ LS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "ZO", },
+
+{ LS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TANY,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ RS,  INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srw A1,AL,AR" COM "right shift\n", },
+
+{ RS,  INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sraw A1,AL,AR" COM "arithmetic right shift\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srw. A1,AL,AR" COM "right shift\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sraw. A1,AL,AR" COM "arithmetic right shift\n", },
+
+{ RS,  INAREG,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       srwi A1,AL,AR" COM "right shift by constant\n", },
+
+{ RS,  INAREG,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       srawi A1,AL,AR" COM "arithmetic right shift by constant\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,  TUWORD|TUSHORT|TUCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       srwi. A1,AL,AR" COM "right shift by constant\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       srawi. A1,AL,AR" COM "right shift by constant\n", },
+
+{ RS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "ZO" },
+
+{ RS,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SAREG,  TANY,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,          TANY,
+               0,      RDEST,
+               "       li AL,AR\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SSCON,          TANY,
+               0,      RDEST,
+               "       li AL,AR\n"
+               "       li UL,UR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SCON,           TANY,
+               0,      RDEST,
+               "       lis AL," HA16(AR) "\n"
+               "       addi AL,AL," LO16(AR) "\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SCON,           TANY,
+               0,      RDEST,
+               "       lis AL," HA16(AR) "\n"
+               "       addi AL,AL," LO16(AR) "\n"
+               "       lis UL," HA16(UR) "\n"
+               "       addi UL,UL," LO16(UR) "\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT,
+       SOREG,          TWORD|TPOINT,
+               NSPECIAL,       RDEST,
+               "       lwz AL,AR" COM "assign oreg to reg\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT,
+       SNAME,          TWORD|TPOINT,
+               NSPECIAL,       RDEST,
+               "       lis AL," HA16(AR) COM "assign sname to reg\n"
+               "       lwz AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SOREG,          TLONGLONG|TULONGLONG,
+               NSPECIAL,       RDEST,
+               "       lwz AL,AR" COM "assign llong to reg\n"
+               "       lwz UL,UR\n" },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SNAME,          TLONGLONG|TULONGLONG,
+               NSPECIAL,       RDEST,
+               "       lis AL," HA16(AR) COM "assign 64-bit sname to reg\n"
+               "       lwz AL," LO16(AR) "(AL)\n"
+               "       lis UL," HA16(UR) "\n"
+               "       lwz UL," LO16(UR) "(UL)\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SOREG,          TSWORD,
+               NSPECIAL,       RDEST,
+               "       lwz AL,AR" COM "load int/pointer into llong\n"
+               "       srawi UL,AR,31\n" },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SOREG,          TUNSIGNED|TPOINT,
+               NSPECIAL,       RDEST,
+               "       lwz AL,AR" COM "load uint/pointer into (u)llong\n"
+               "       li UL,0\n" },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TUCHAR,
+       SOREG,          TUCHAR,
+               NSPECIAL,       RDEST,
+               "       lbz AL,AR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TUCHAR,
+       SNAME,          TUCHAR,
+               NSPECIAL,       RDEST,
+               "       lis AL," HA16(AR) COM "assign uchar sname to reg\n"
+               "       lbz AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TCHAR,
+       SOREG,          TCHAR,
+               NSPECIAL,       RDEST,
+               "       lbz AL,AR\n"
+               "       extsb AL,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TCHAR,
+       SNAME,          TCHAR,
+               NSPECIAL,       RDEST,
+               "       lis AL," HA16(AR) COM "assign char sname to reg\n"
+               "       lbz AL," LO16(AR) "(AL)\n"
+               "       extsb AL,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT,
+       SOREG,          TSHORT,
+               NSPECIAL,       RDEST,
+               "       lha AL,AR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT,
+       SOREG,          TUSHORT,
+               NSPECIAL,       RDEST,
+               "       lhz AL,AR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD,
+       SNAME,          TSHORT,
+               NSPECIAL,       RDEST,
+               "       lis AL," HA16(AR) "\n"
+               "       lha AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD,
+       SNAME,          TUSHORT,
+               NSPECIAL,       RDEST,
+               "       lis AL," HA16(AR) "\n"
+               "       lhz AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,          TWORD|TPOINT,
+       SAREG,          TWORD|TPOINT,
+               NSPECIAL,       RDEST,
+               "       stw AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,          TWORD|TPOINT,
+       SAREG,          TWORD|TPOINT,
+               NAREG|NSPECIAL, RDEST,
+               "       lis A1," HA16(AL) COM "assign reg to sname\n"
+               "       stw AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NSPECIAL,       RDEST,
+               "       stw AR,AL" COM "store 64-bit value\n"
+               "       stw UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SNAME,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NBREG|NSPECIAL, RDEST,
+               "       lis A1," HA16(AL) COM "assign reg to 64-bit sname\n"
+               "       stw AR," LO16(AL) "(A1)\n"
+               "       lis U1," HA16(UL) "\n"
+               "       stw UR," LO16(UL) "(U1)\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,          TCHAR|TUCHAR,
+       SAREG,          TCHAR|TUCHAR,
+               NSPECIAL,       RDEST,
+               "       stb AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,          TCHAR|TUCHAR,
+       SAREG,          TCHAR|TUCHAR,
+               NAREG|NSPECIAL, RDEST,
+               "       lis A1," HA16(AL) "\n"
+               "       stb AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,          TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               NSPECIAL,       RDEST,
+               "       sth AR,AL\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,          TSHORT|TUSHORT,
+       SAREG,          TSHORT|TUSHORT,
+               NAREG|NSPECIAL, RDEST,
+               "       lis A1," HA16(AL) "\n"
+               "       sth AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               0,      RDEST,
+               "       mr AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+        SBREG, TLONGLONG|TULONGLONG,
+        SBREG, TLONGLONG|TULONGLONG,
+                0,  RDEST,
+               "       mr AL,AR" COM "assign UR:AR to UL:AL\n"
+                "      mr UL,UR\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SFLD,           TANY,
+       SAREG,          TANY,
+               3*NAREG,        RDEST,
+               "       lis A3," HA16(M) COM "bit-field assignment\n"
+               "       addi A3,A3," LO16(M) "\n"
+               "       lwz A2,AL\n"
+               "       slwi A1,AR,H\n"
+               "       and A1,A1,A3\n"
+               "       not A3,A3\n"
+               "       and A2,A2,A3\n"
+               "       or A2,A2,A1\n"
+               "       stw A2,AL\n"
+               "F      mr AD,AR\n"
+               "F      slwi AD,AD,32-S\n"
+               "F      srwi AD,AD,32-S\n", },
+
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SAREG,          TPTRTO|TANY,
+               NSPECIAL,       RDEST,
+               "ZQ", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SOREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               0,      RDEST,
+               "       stfs AR,AL" COM "store float\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,          TFLOAT,
+       SAREG,          TFLOAT,
+               0,      RDEST,
+               "       stw AR,AL" COM "store float (soft-float)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SNAME,          TFLOAT,
+       SCREG,          TFLOAT,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AL) "\n"
+               "       stfs AR," LO16(AL) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,          TFLOAT,
+       SAREG,          TFLOAT,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AL) "\n"
+               "       stw AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TFLOAT,
+       SOREG,          TFLOAT,
+               0,      RDEST,
+               "       lfs AL,AR" COM "load float\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TFLOAT,
+       SOREG,          TFLOAT,
+               0,      RDEST,
+               "       lwz AL,AR" COM "load float (soft-float)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TFLOAT,
+       SNAME,          TFLOAT,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AR) "\n"
+               "       lfs AL," LO16(AR) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TFLOAT,
+       SNAME,          TFLOAT,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AR) "\n"
+               "       lwz AL," LO16(AR) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               0,      RDEST,
+               "       fmr AL,AR" COM "assign AR to AL\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,          TFLOAT,
+       SAREG,          TFLOAT,
+               0,      RDEST,
+               "       mr AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SOREG,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       stfd AR,AL" COM "store (l)double\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG,          TDOUBLE|TLDOUBLE,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       stw AR,AL" COM "store (l)double (soft-float)\n"
+               "       stw UR,UL\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SNAME,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AL) "\n"
+               "       stfd AR," LO16(AL) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INBREG,
+       SNAME,          TDOUBLE|TLDOUBLE,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AL) "\n"
+               "       stw AR," LO16(AL) "(A1)\n"
+               "       lis A1," HA16(UL) "\n"
+               "       stw UR," LO16(UL) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SOREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       lfd AL,AR" COM "load (l)double\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TDOUBLE|TLDOUBLE,
+       SOREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       lwz AL,AR" COM "load (l)double (soft-float)\n"
+               "       lwz UL,UR\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SNAME,          TDOUBLE|TLDOUBLE,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AR) "\n"
+               "       lfd AL," LO16(AR) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TDOUBLE|TLDOUBLE,
+       SNAME,          TDOUBLE|TLDOUBLE,
+               NAREG,  RDEST,
+               "       lis A1," HA16(AR) "\n"
+               "       lwz AL," LO16(AR) "(A1)\n"
+               "       lis A1," HA16(UR) "\n"
+               "       lwz UL," LO16(UR) "(A1)\n", },
+
+{ ASSIGN,      FOREFF|INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       fmr AL,AR" COM "assign AR to AL\n", },
+
+/* soft-float */
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,          TDOUBLE|TLDOUBLE,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               0,      RDEST,
+               "       mr AL,AR" COM "assign AR to AL\n"
+               "       mr UL,UR\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+
+{ DIV, INAREG,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       divwu A1,AL,AR\n", },
+
+{ DIV, INAREG|FORCC,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+               NAREG|NASL,     RESC1|RESCC,
+               "       divwu. A1,AL,AR\n", },
+
+{ DIV, INAREG,
+       SAREG,  TWORD|TSHORT|TCHAR,
+       SAREG,  TWORD|TSHORT|TCHAR,
+               NAREG|NASL,     RESC1,
+               "       divw A1,AL,AR\n", },
+
+{ DIV, INAREG|FORCC,
+       SAREG,  TWORD|TSHORT|TCHAR,
+       SAREG,  TWORD|TSHORT|TCHAR,
+               NAREG|NASL,     RESC1|RESCC,
+               "       divw. A1,AL,AR\n", },
+
+{ DIV, INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ DIV, INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               NCREG|NCSR,     RESC1,
+               "       fdivs A1,AL,AR" COM "float divide\n", },
+
+/* soft-float */
+{ DIV, INAREG,
+       SAREG,          TFLOAT,
+       SAREG,          TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ DIV, INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NCREG|NCSR,     RESC1,
+               "       fdiv A1,AL,AR" COM "(l)double divide\n", },
+
+/* soft-float */
+{ DIV, INBREG,
+       SBREG,          TDOUBLE|TLDOUBLE,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+{ MOD, INAREG,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+               NAREG,  RESC1,
+               "       divwu A1,AL,AR" COM "unsigned modulo\n"
+               "       mullw A1,A1,AR\n"
+               "       subf A1,A1,AL\n", },
+
+{ MOD, INAREG,
+       SAREG,  TWORD|TSHORT|TCHAR,
+       SAREG,  TWORD|TSHORT|TCHAR,
+               NAREG,  RESC1,
+               "       divw A1,AL,AR" COM "signed modulo\n"
+               "       mullw A1,A1,AR\n"
+               "       subf A1,A1,AL\n", },
+
+{ MOD, INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NSPECIAL|NBREG, RESC1,
+               "ZE", },
+
+{ MUL, INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,          TANY,
+               NAREG|NASL,     RESC1,
+               "       mulli A1,AL,AR\n", },
+
+{ MUL, INAREG|FORCC,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SSCON,          TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       mulli. A1,AL,AR\n", },
+
+{ MUL, INAREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       mullw A1,AL,AR\n", },
+
+{ MUL, INAREG|FORCC,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1|RESCC,
+               "       mullw. A1,AL,AR\n", },
+
+{ MUL, INBREG,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,          TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NBREG,  RESC1,
+               "       mullw A1,AL,AR\n"
+               "       mulhw U1,AL,AR\n", },
+
+{ MUL, INBREG,
+       SBREG,          TLONGLONG|TULONGLONG,
+       SBREG,          TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       mullw A1,AL,AR\n"
+               "       mulhw U1,AL,AR\n", },
+
+{ MUL, INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TFLOAT,
+       SCREG,          TFLOAT,
+               NCREG|NCSR,     RESC1,
+               "       fmuls A1,AL,AR" COM "float multiply\n", },
+
+/* soft-float */
+{ MUL, INAREG,
+       SAREG,          TFLOAT,
+       SAREG,          TFLOAT,
+               NSPECIAL|NAREG, RESC1,
+               "ZF", },
+
+{ MUL, INCREG | FEATURE_HARDFLOAT,
+       SCREG,          TDOUBLE|TLDOUBLE,
+       SCREG,          TDOUBLE|TLDOUBLE,
+               NCREG|NCSR,     RESC1,
+               "       fmul A1,AL,AR" COM "(l)double multiply\n", },
+
+/* soft-float */
+{ MUL, INBREG,
+       SBREG,          TDOUBLE|TLDOUBLE,
+       SBREG,          TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "ZF", },
+
+/*
+ * Indirection operators.
+ */
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TWORD|TPOINT,
+               NAREG|NSPECIAL, RESC1,
+               "       lwz A1,AL" COM "word load\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       lbz A1,AL" COM "char load\n"
+               "       extsb A1,A1\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TUCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       lbz A1,AL" COM "uchar load\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       lha A1,AL" COM "short load\n", },
+
+{ UMUL,        INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       lhz A1,AL" COM "ushort load\n", },
+
+{ UMUL, INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       lwz A1,AL" COM "64-bit load\n"
+               "       lwz U1,UL\n", },
+
+{ UMUL, INCREG | FEATURE_HARDFLOAT,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NCREG,  RESC1,
+               "       lfs A1,AL" COM "float load\n", },
+
+{ UMUL, INAREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TFLOAT,
+               NAREG,  RESC1,
+               "       lwz A1,AL" COM "float load (soft-float)\n", },
+
+{ UMUL, INCREG | FEATURE_HARDFLOAT,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       lfd A1,AL" COM "(l)double load\n", },
+
+{ UMUL, INBREG,
+       SANY,           TANY,
+       SOREG|SNAME,    TDOUBLE|TLDOUBLE,
+               NSPECIAL|NBREG, RESC1,
+               "       lwz A1,AL" COM "(l)double load (soft-float)\n"
+               "       lwz U1,UL\n", },
+
+#if 0
+{ UMUL, INAREG,
+       SANY,           TANY,
+       SAREG,          TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       lwz A1,(AL)" COM "word load\n", },
+#endif
+
+/*
+ * Logical/branching operators
+ */
+
+/* compare with constant */
+{ OPLOG,       FORCC,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SSCON,  TANY,
+               0,      RESCC,
+               "       cmpwi AL,AR\n", },
+
+/* compare with constant */
+{ OPLOG,       FORCC,
+       SAREG,  TUWORD|TPOINT|TUSHORT|TUCHAR,
+       SSCON,  TANY,
+               0,      RESCC,
+               "       cmplwi AL,AR\n", },
+
+/* compare with register */
+{ OPLOG,       FORCC,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+       SAREG,  TSWORD|TSHORT|TCHAR,
+               0,      RESCC,
+               "       cmpw AL,AR\n", },
+
+/* compare with register */
+{ OPLOG,       FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               0,      RESCC,
+               "       cmplw AL,AR\n", },
+
+/* compare with register */
+{ OPLOG,       FORCC,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               0,      RESCC,
+               "ZD", },
+
+/* compare with register */
+{ OPLOG,       FORCC | FEATURE_HARDFLOAT,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+               0,      RESCC,
+               "       fcmpu 0,AL,AR\n", },
+
+/* soft-float */
+{ OPLOG,       FORCC,
+       SAREG,  TFLOAT,
+       SAREG,  TFLOAT,
+               NSPECIAL,       RESCC,
+               "ZF\n", },
+
+/* soft-float */
+{ OPLOG,       FORCC,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SBREG,  TDOUBLE|TLDOUBLE,
+               NSPECIAL,       RESCC,
+               "ZF", },
+
+{ OPLOG,       FORCC,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        0,
+               "diediedie!", },
+
+/* AND/OR/ER */
+{ AND, INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       and A1,AL,AR\n", },
+
+{ AND, INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       and. A1,AL,AR\n", },
+
+/* AR must be positive */
+{ AND, INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SPCON,  TANY,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       andi. A1,AL,AR\n", },
+
+{ AND, INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       and A1,AL,AR" COM "64-bit and\n"
+               "       and U1,UL,UR\n" },
+
+{ AND, INBREG|FORCC,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SPCON,  TANY,
+               NBREG|NBSL,     RESC1|RESCC,
+               "       andi. A1,AL,AR" COM "64-bit and with constant\n"
+               "       li U1,0\n" },
+
+{ OR,  INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       or A1,AL,AR\n", },
+
+{ OR,  INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       or. A1,AL,AR\n", },
+
+{ OR,  INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1,
+               "       ori A1,AL,AR\n", },
+
+{ OR,  INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SPCON,  TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       ori. A1,AL,AR\n", },
+
+{ OR,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       or A1,AL,AR" COM "64-bit or\n"
+               "       or U1,UL,UR\n" },
+
+{ OR,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SPCON,  TANY,
+               NBREG|NBSL,     RESC1,
+               "       ori A1,AL,AR" COM "64-bit or with constant\n" },
+
+{ OR,  INBREG|FORCC,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SPCON,  TANY,
+               NBREG|NBSL,     RESC1|RESCC,
+               "       ori. A1,AL,AR" COM "64-bit or with constant\n" },
+
+{ ER,  INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       xor A1,AL,AR\n", },
+
+{ ER,  INAREG|FORCC,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL|NSPECIAL,    RESC1|RESCC,
+               "       xor. A1,AL,AR\n", },
+
+{ ER,  INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SPCON,  TANY,
+               NAREG|NASL|NSPECIAL,    RESC1,
+               "       xori A1,AL,AR\n", },
+
+{ ER,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SBREG,  TLONGLONG|TULONGLONG,
+               NBREG|NBSL,     RESC1,
+               "       xor A1,AL,AR" COM "64-bit xor\n"
+               "       xor U1,UL,UR\n" },
+
+{ ER,  INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SPCON,  TANY,
+               NBREG|NBSL,     RESC1,
+               "       xori A1,AL,AR" COM "64-bit xor with constant\n" },
+
+/*
+ * Jumps.
+ */
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       b LL\n", },
+
+{ GOTO,        FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       mtctr AL\n"
+               "       bctr\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+#if defined(ELFABI)
+{ OPLTYPE,     INAREG | FEATURE_PIC,
+       SANY,           TANY,
+       SNAME,          TANY,
+               NAREG,  RESC1,
+               "       lwz A1,AL" COM "elfabi pic load\n", },
+#endif
+
+{ OPLTYPE,      INBREG,
+        SANY,          TANY,
+        SOREG,         TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+                "      lwz A1,AL" COM "load llong from memory\n"
+               "       lwz U1,UL\n", },
+
+{ OPLTYPE,      INBREG,
+        SANY,          TANY,
+        SNAME,         TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+               "       lis A1," HA16(AL) COM "load llong from sname\n"
+               "       lwz A1," LO16(AL) "(A1)\n"
+               "       lis U1," HA16(UL) "\n"
+               "       lwz U1," LO16(UL) "(U1)\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG,          TWORD|TPOINT,
+               NAREG,  RESC1,
+               "       lwz A1,AL" COM "load word from memory\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME,          TWORD|TPOINT,
+               NAREG|NSPECIAL, RESC1,
+               "       lis A1," HA16(AL) COM "load word from sname\n"
+               "       lwz A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG,          TCHAR,
+               NAREG,  RESC1,
+               "       lbz A1,AL" COM "load char from memory\n"
+               "       extsb A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME,          TCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       lis A1," HA16(AL) COM "load char from sname\n"
+               "       lbz A1," LO16(AL) "(A1)\n"
+               "       extsb A1,A1\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG,          TUCHAR,
+               NAREG,  RESC1,
+               "       lbz A1,AL" COM "load uchar from memory\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME,          TUCHAR,
+               NAREG|NSPECIAL, RESC1,
+               "       lis A1," HA16(AL) COM "load uchar from sname\n"
+               "       lbz A1," LO16(AL) "(A1)\n", },
+
+/* load short from memory */
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG,          TSHORT,
+               NAREG,  RESC1,
+               "       lha A1,AL" COM "load short from memory\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG,          TUSHORT,
+               NAREG,  RESC1,
+               "       lhz A1,AL" COM "load ushort from memory\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME,          TSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       lis A1," HA16(AL) COM "load short from sname\n"
+               "       lha A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME,          TUSHORT,
+               NAREG|NSPECIAL, RESC1,
+               "       lis A1," HA16(AL) COM "load ushort from sname\n"
+               "       lhz A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SSCON,          TANY,
+               NAREG,  RESC1,
+               "       li A1,AL" COM "load 16-bit constant\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SSCON,  TANY,
+               NBREG,  RESC1,
+               "       li A1,AL" COM "load 16-bit constant\n"
+               "       li U1,UL\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1,
+               "       lis A1," HA16(AL) COM "load constant into register\n"
+               "       addi A1,A1," LO16(AL) "\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SCON,   TANY,
+               NBREG,  RESC1,
+               "       lis A1," HA16(AL) COM "load constant into register\n"
+               "       addi A1,A1," LO16(AL) "\n"
+               "       lis U1," HA16(UL) "\n"
+               "       addi U1,U1," LO16(UL) "\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SAREG,  TANY,
+               NAREG,  RESC1,
+               "       mr A1,AL" COM "load AL into A1\n" },
+
+{ OPLTYPE,      INBREG,
+        SANY,   TANY,
+        SBREG, TANY,
+                NBREG,  RESC1,
+               "       mr A1,AL" COM "load UL:AL into U1:A1\n"
+                "       mr U1,UL\n", },
+
+{ OPLTYPE,      INCREG,
+        SANY,   TANY,
+        SCREG, TFLOAT|TDOUBLE|TLDOUBLE,
+                NCREG,  RESC1,
+               "       fmr A1,AL" COM "load AL into A1\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_HARDFLOAT,
+       SANY,           TANY,
+       SOREG,          TFLOAT,
+               NCREG,  RESC1,
+               "       lfs A1,AL" COM "load float\n", },
+
+/* soft-float */
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SOREG,          TFLOAT,
+               NAREG,  RESC1,
+               "       lwz A1,AL" COM "load float (soft-float)\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_HARDFLOAT,
+       SANY,           TANY,
+       SNAME,          TFLOAT,
+               NCREG|NAREG,    RESC2,
+               "       lis A1," HA16(AL) COM "load sname\n"
+               "       lfs A2," LO16(AL) "(A1)\n", },
+
+/* soft-float */
+{ OPLTYPE,     INAREG,
+       SANY,           TANY,
+       SNAME,          TFLOAT,
+               NAREG,  RESC1,
+               "       lis A1," HA16(AL) COM "load sname (soft-float)\n"
+               "       lwz A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_HARDFLOAT,
+       SANY,           TANY,
+       SOREG,          TDOUBLE|TLDOUBLE,
+               NCREG,  RESC1,
+               "       lfd A1,AL" COM "load (l)double\n", },
+
+/* soft-float */
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SOREG,          TDOUBLE|TLDOUBLE,
+               NBREG,  RESC1,
+               "       lwz A1,AL" COM "load (l)double (soft-float)\n"
+               "       lwz U1,UL\n", },
+
+{ OPLTYPE,     INCREG | FEATURE_HARDFLOAT,
+       SANY,           TANY,
+       SNAME,          TDOUBLE|TLDOUBLE,
+               NCREG|NAREG,    RESC2,
+               "       lis A1," HA16(AL) COM "load sname\n"
+               "       lfd A2," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,           TANY,
+       SNAME,          TDOUBLE|TLDOUBLE,
+               NBREG,  RESC1,
+               "       lis A1," HA16(AL) COM "load sname (soft-float)\n"
+               "       lwz A1," LO16(AL) "(A1)\n"
+               "       lis U1," HA16(UL) "\n"
+               "       lwz U1," LO16(UL) "(U1)\n", },
+
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,      INAREG,
+       SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       neg A1,AL\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,
+               "       subfic A1,AL,0\n"
+               "       subfze U1,UL\n", },
+
+{ UMINUS,      INCREG | FEATURE_HARDFLOAT,
+       SCREG,  TFLOAT|TDOUBLE|TLDOUBLE,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,
+               "       fneg A1,AL\n", },
+
+{ UMINUS,      INAREG,
+       SAREG,  TFLOAT,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       xoris A1,AL,0x8000" COM "(soft-float)\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TDOUBLE|TLDOUBLE,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,
+               "       xoris U1,UL,0x8000" COM "(soft-float)\n"
+               "       mr A1,AL\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       not A1,AL\n", },
+
+{ COMPL,       INBREG,
+       SBREG,  TLONGLONG|TULONGLONG,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,
+               "       not A1,AL\n"
+               "       not U1,UL\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+#if 0
+{ STARG,       FOREFF,
+       SAREG|SOREG|SNAME|SCON, TANY,
+       SANY,   TSTRUCT,
+               NSPECIAL|NAREG, 0,
+               "ZF", },
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/sparc64/code.c b/lang/pcc/pcc/arch/sparc64/code.c
new file mode 100644 (file)
index 0000000..b2b7b53
--- /dev/null
@@ -0,0 +1,272 @@
+/*     $Id: code.c,v 1.23 2015/07/24 07:57:01 ragge Exp $      */
+
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+       case DATA:
+       case LDATA: name = ".data"; break;
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+       case UDATA: break;
+       case PICLDATA:
+       case PICDATA:
+       case PICRDATA:
+       case TLSDATA:
+       case TLSUDATA:
+       case CTORS:
+       case DTORS:
+               uerror("FIXME: unknown section");
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+
+void
+defloc(struct symtab *sp)
+{
+       TWORD t;
+       char *name;
+
+       t = sp->stype;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+
+       if (!ISFTN(t)) {
+               printf("\t.type %s,#object\n", name);
+               printf("\t.size %s," CONFMT "\n", name,
+                       tsize(sp->stype, sp->sdf, sp->sap) / SZCHAR);
+       }
+       if (sp->sclass == EXTDEF)
+               printf("\t.global %s\n", name);
+       if (sp->slevel == 0) {
+               printf("%s:\n", name);
+       } else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+void
+efcode(void)
+{
+       /* XXX */
+}
+
+void
+bfcode(struct symtab **sp, int cnt)
+{
+       int i, off;
+       NODE *p, *q;
+       struct symtab *sym;
+
+       /* Process the first six arguments. */
+       for (i=0; i < cnt && i < 6; i++) {
+               sym = sp[i];
+               q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+               q->n_rval = RETREG_PRE(sym->stype) + i;
+               p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               sym->soffset = regno(p);
+               sym->sflags |= STNODE;
+               p = buildtree(ASSIGN, p, q);
+               ecomp(p);
+       }
+
+       /* Process the remaining arguments. */
+       for (off = V9RESERVE; i < cnt; i++) {
+               sym = sp[i];
+               p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+               off = ALIGN(off, (tlen(p) - 1));
+               sym->soffset = off * SZCHAR;
+               off += tlen(p);
+               p = buildtree(ASSIGN, p, nametree(sym));
+               sym->soffset = regno(p->n_left);
+               sym->sflags |= STNODE;
+               ecomp(p);
+       }
+}
+
+void
+ejobcode(int flag)
+{
+}
+
+void
+bjobcode(void)
+{
+       astypnames[USHORT] = astypnames[SHORT] = "\t.half";
+       astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
+       astypnames[LONG] = astypnames[ULONG] = 
+           astypnames[LONGLONG] = astypnames[ULONGLONG] = "\t.xword";
+}
+
+/*
+ * The first six 64-bit arguments are saved in the registers O0 to O5,
+ * which become I0 to I5 after the "save" instruction moves the register
+ * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176.
+ *
+ * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4.
+ */
+static NODE *
+moveargs(NODE *p, int *regp, int *stacksize)
+{
+       NODE *r, *q;
+
+       if (p->n_op == CM) {
+               p->n_left = moveargs(p->n_left, regp, stacksize);
+               r = p->n_right;
+       } else {
+               r = p;
+       }
+
+       /* XXX more than six FP args can and should be passed in registers. */
+       if (*regp > 5 && r->n_op != STARG) {
+               /* We are storing the stack offset in n_rval. */
+               r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
+               /* Make sure we are appropriately aligned. */
+               *stacksize = ALIGN(*stacksize, (tlen(r) - 1));
+               r->n_rval = *stacksize;
+               *stacksize += tlen(r);
+       } else if (r->n_op == STARG)
+               cerror("op STARG in moveargs");
+       else {
+               q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);
+
+               /*
+                * The first six non-FP arguments go in the registers O0 - O5.
+                * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31.
+                * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30.
+                * A non-fp argument still increments register, eg.
+                *     test(int a, int b, float b)
+                * takes %o0, %o1, %fp5.
+                */
+               if (q->n_type == FLOAT)
+                       q->n_rval = F0 + (*regp++ * 2) + 1;
+               else if (q->n_type == DOUBLE)
+                       q->n_rval = D0 + *regp++;
+               else if (q->n_type == LDOUBLE)
+                       cerror("long double support incomplete");
+               else
+                       q->n_rval = O0 + (*regp)++;
+
+               r = buildtree(ASSIGN, q, r);
+       }
+
+       if (p->n_op == CM) {
+               p->n_right = r;
+               return p;
+       }
+
+       return r;
+}
+
+NODE *
+funcode(NODE *p)
+{
+       NODE *r, *l;
+       int reg = 0, stacksize = 0;
+
+       r = l = 0;
+
+       p->n_right = moveargs(p->n_right, &reg, &stacksize);
+
+       /*
+        * This is a particularly gross and inefficient way to handle
+        * argument overflows. First, we calculate how much stack space
+        * we need in moveargs(). Then we assign it by moving %sp, make
+        * the function call, and then move %sp back.
+        *
+        * What we should be doing is getting the maximum of all the needed
+        * stacksize values to the prologue and doing it all in the "save"
+        * instruction.
+        */
+       if (stacksize != 0) {
+               stacksize = V9STEP(stacksize); /* 16-bit alignment. */
+
+               r = block(REG, NIL, NIL, INT, 0, 0);
+               r->n_lval = 0;
+               r->n_rval = SP;
+               r = block(MINUS, r, bcon(stacksize), INT, 0, 0);
+
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               l->n_lval = 0;
+               l->n_rval = SP;
+               r = buildtree(ASSIGN, l, r);
+
+               p = buildtree(COMOP, r, p);
+
+               r = block(REG, NIL, NIL, INT, 0, 0);
+               r->n_lval = 0;
+               r->n_rval = SP;
+               r = block(PLUS, r, bcon(stacksize), INT, 0, 0);
+
+               l = block(REG, NIL, NIL, INT, 0, 0);
+               l->n_lval = 0;
+               l->n_rval = SP;
+               r = buildtree(ASSIGN, l, r);
+
+               p = buildtree(COMOP, p, r);
+
+       }
+       return p;
+}
+
+void
+fldty(struct symtab *p)
+{
+}
+
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       uerror("missing %s", __func__);
+       return bcon(0);
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       uerror("missing %s", __func__);
+       return bcon(0);
+}
+
+NODE *  
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       uerror("missing %s", __func__);
+       return bcon(0);
+}
diff --git a/lang/pcc/pcc/arch/sparc64/local.c b/lang/pcc/pcc/arch/sparc64/local.c
new file mode 100644 (file)
index 0000000..507dc5e
--- /dev/null
@@ -0,0 +1,281 @@
+/*     $Id: local.c,v 1.34 2011/06/23 13:41:25 ragge Exp $     */
+
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+
+NODE *
+clocal(NODE *p)
+{
+       struct symtab *sp;
+       int op;
+       NODE *r, *l;
+
+       op = p->n_op;
+       sp = p->n_sp;
+       l  = p->n_left;
+       r  = p->n_right;
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal in: %p, %s\n", p, copst(op));
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       switch (op) {
+
+       case NAME:
+               if (sp->sclass == PARAM || sp->sclass == AUTO) {
+                       /*
+                        * Use a fake structure reference to
+                        * write out frame pointer offsets.
+                        */
+                       l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+                       l->n_lval = 0;
+                       l->n_rval = FP;
+                       r = p;
+                       p = stref(block(STREF, l, r, 0, 0, 0));
+               }
+               break;
+       case PCONV: /* Remove what PCONVs we can. */
+               if (l->n_op == SCONV)
+                       break;
+
+               if (l->n_op == ICON || (ISPTR(p->n_type) && ISPTR(l->n_type))) {
+                       l->n_type = p->n_type;
+                       l->n_qual = p->n_qual;
+                       l->n_df = p->n_df;
+                       l->n_ap = p->n_ap;
+                       nfree(p);
+                       p = l;
+               }
+               break;
+
+       case SCONV:
+        /* Remove redundant conversions. */
+               if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                   tsize(p->n_type, p->n_df, p->n_ap) ==
+                   tsize(l->n_type, l->n_df, l->n_ap) &&
+                   p->n_type != FLOAT && p->n_type != DOUBLE &&
+                   l->n_type != FLOAT && l->n_type != DOUBLE &&
+                   l->n_type != DOUBLE && p->n_type != LDOUBLE) {
+                       if (l->n_op == NAME || l->n_op == UMUL ||
+                           l->n_op == TEMP) {
+                               l->n_type = p->n_type;
+                               nfree(p);
+                               p = l;
+                               break;
+                       }
+               }
+
+        /* Convert floating point to int before to char or short. */
+        if ((l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)
+            && (DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT)) {
+            p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+            p->n_left->n_type = INT;
+            break;
+        }
+
+        /* Transform constants now. */
+               if (l->n_op != ICON)
+                       break;
+
+               if (ISPTR(p->n_type)) {
+                       l->n_type = p->n_type;
+                       nfree(p);
+                       p = l;
+                       break;
+               }
+
+               switch (p->n_type) {
+               case BOOL:      l->n_lval = (l->n_lval != 0); break;
+               case CHAR:      l->n_lval = (char)l->n_lval; break;
+               case UCHAR:     l->n_lval = l->n_lval & 0377; break;
+               case SHORT:     l->n_lval = (short)l->n_lval; break;
+               case USHORT:    l->n_lval = l->n_lval & 0177777; break;
+               case UNSIGNED:  l->n_lval = l->n_lval & 0xffffffff; break;
+               case INT:       l->n_lval = (int)l->n_lval; break;
+               case ULONG:
+               case ULONGLONG: l->n_lval = l->n_lval; break;
+               case LONG:
+               case LONGLONG:  l->n_lval = (long long)l->n_lval; break;
+               case FLOAT:
+               case DOUBLE:
+               case LDOUBLE:
+                       l->n_op = FCON;
+                       l->n_dcon = l->n_lval;
+                       break;
+               case VOID:
+                       break;
+               default:
+                       cerror("sconv type unknown %d", p->n_type);
+               }
+
+               l->n_type = p->n_type;
+               nfree(p);
+               p = l;
+               break;
+
+       case FORCE:
+               /* Put attached value into the return register. */
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = RETREG_PRE(p->n_type);
+               break;
+       }
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal out: %p, %s\n", p, copst(op));
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       return p;
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+
+       if (p->n_op != FCON)
+               return;
+
+       sp = tmpalloc(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->slevel = 1;
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       defloc(sp);
+       ninval(0, tsize(p->n_type, p->n_df, p->n_ap), p);
+
+       p->n_op = NAME;
+       p->n_lval = 0;
+       p->n_sp = sp;
+}
+
+int
+andable(NODE *p)
+{
+       return 1;
+}
+
+int
+cisreg(TWORD t)
+{
+       /* SPARCv9 registers are all 64-bits wide. */
+       return 1;
+}
+
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       cerror("spalloc");
+}
+
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; int i; long long l; } u;
+
+       switch (p->n_type) {
+       case FLOAT:
+               u.f = (float)p->n_dcon;
+               printf("\t.long %d\n", u.i);
+               break;
+       case DOUBLE:
+               u.d = (double)p->n_dcon;
+               printf("\t.xword %lld\n", u.l);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+char *
+exname(char *p)
+{
+       return p ? p : "";
+}
+
+TWORD
+ctype(TWORD type)
+{
+       switch (BTYPE(type)) {
+       case LONGLONG:
+               MODTYPE(type,LONG);
+               break;
+       case ULONGLONG:
+               MODTYPE(type,ULONG);
+
+       }
+       return type;
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+void
+defzero(struct symtab *sp)
+{
+       int off;
+       char *name;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+
+       if (sp->sclass == STATIC)
+               printf("\t.local %s\n", name);
+       if (sp->slevel == 0)
+               printf("\t.comm %s,%d\n", name, off);
+       else
+               printf("\t.comm " LABFMT ",%d\n", sp->soffset, off);
+}
+
+int
+mypragma(char *str)
+{
+       return 0;
+}
+
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+
diff --git a/lang/pcc/pcc/arch/sparc64/local2.c b/lang/pcc/pcc/arch/sparc64/local2.c
new file mode 100644 (file)
index 0000000..6cd0a44
--- /dev/null
@@ -0,0 +1,425 @@
+/*     $Id: local2.c,v 1.27 2015/01/04 19:17:23 ragge Exp $    */
+
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+#include "pass2.h"
+
+
+char *
+rnames[] = {
+       /* "\%g0", always zero, removed due to 31-element class limit */
+               "\%g1", "\%g2", "\%g3", "\%g4", "\%g5", "\%g6", "\%g7",
+       "\%o0", "\%o1", "\%o2", "\%o3", "\%o4", "\%o5", "\%o6", "\%o7",
+       "\%l0", "\%l1", "\%l2", "\%l3", "\%l4", "\%l5", "\%l6", "\%l7",
+       "\%i0", "\%i1", "\%i2", "\%i3", "\%i4", "\%i5", "\%i6", "\%i7",
+
+       "\%f0",  "\%f1",  "\%f2",  "\%f3",  "\%f4",  "\%f5",  "\%f6",  "\%f7",
+       "\%f8",  "\%f9",  "\%f10", "\%f11", "\%f12", "\%f13", "\%f14", "\%f15",
+       "\%f16", "\%f17", "\%f18", "\%f19", "\%f20", "\%f21", "\%f22", "\%f23",
+       "\%f24", "\%f25", "\%f26", "\%f27", "\%f28", "\%f29", "\%f30",
+       /*, "\%f31" XXX removed due to 31-element class limit */
+
+       "\%f0",  "\%f2",  "\%f4",  "\%f6",  "\%f8",  "\%f10", "\%f12", "\%f14",
+       "\%f16", "\%f18", "\%f20", "\%f22", "\%f24", "\%f26", "\%f28", "\%f30",
+
+       "\%sp", "\%fp",
+};
+
+void
+deflab(int label)
+{
+       printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+       int i, stack;
+
+       stack = V9RESERVE + V9STEP(p2maxautooff);
+
+       for (i = ipp->ipp_regs[0]; i; i >>= 1)
+               if (i & 1)
+                       stack += 16;
+
+       /* TODO printf("\t.proc %d\n"); */
+       if (SIMM13(stack))
+               printf("\tsave %%sp,-%d,%%sp\n", stack);
+       else {
+               printf("\tsetx -%d,%%g4,%%g1\n", stack);
+               printf("\tsave %%sp,%%g1,%%sp\n");
+       }
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       printf("\tret\n");
+       printf("\trestore\n");
+       printf("\t.type %s,#function\n", ipp->ipp_name);
+       printf("\t.size %s,(.-%s)\n", ipp->ipp_name, ipp->ipp_name);
+}
+
+void
+hopcode(int f, int o)
+{
+       char *str;
+
+       switch (o) {
+               case EQ:        str = "brz"; break;
+               case NE:        str = "brnz"; break;
+               case ULE:
+               case LE:        str = "brlez"; break;
+               case ULT:
+               case LT:        str = "brlz";  break;
+               case UGE:
+               case GE:        str = "brgez"; break;
+               case UGT:
+               case GT:        str = "brgz";  break;
+               case PLUS:      str = "add"; break;
+               case MINUS:     str = "sub"; break;
+               case AND:       str = "and"; break;
+               case OR:        str = "or";  break;
+               case ER:        str = "xor"; break;
+               default:
+                       comperr("unknown hopcode: %d (with %c)", o, f);
+                       return;
+       }
+
+       printf("%s%c", str, f);
+}
+
+int
+tlen(NODE *p)
+{
+       switch (p->n_type) {
+               case CHAR:
+               case UCHAR:
+                       return 1;
+               case SHORT:
+               case USHORT:
+                       return (SZSHORT / SZCHAR);
+               case FLOAT:
+                       return (SZFLOAT / SZCHAR);
+               case DOUBLE:
+                       return (SZDOUBLE / SZCHAR);
+               case INT:
+               case UNSIGNED:
+                       return (SZINT / SZCHAR);
+               case LONG:
+               case ULONG:
+               case LONGLONG:
+               case ULONGLONG:
+                       return SZLONGLONG / SZCHAR;
+               default:
+                       if (!ISPTR(p->n_type))
+                               comperr("tlen type unknown: %d");
+                       return SZPOINT(p->n_type) / SZCHAR;
+       }
+}
+
+void
+zzzcode(NODE * p, int c)
+{
+       char *str;
+       NODE *l, *r;
+       int sz;
+       l = p->n_left;
+       r = p->n_right;
+
+       switch (c) {
+
+       case 'A':       /* Add const. */
+               if (ISPTR(l->n_type) && l->n_rval == FP)
+                       r->n_lval += V9BIAS;
+
+               if (SIMM13(r->n_lval))
+                       expand(p, 0, "\tadd AL,AR,A1\t\t! add const\n");
+               else
+                       expand(p, 0, "\tsetx AR,A3,A2\t\t! add const\n"
+                                    "\tadd AL,A2,A1\n");
+               break;
+       case 'B':       /* Subtract const. */
+               if (ISPTR(l->n_type) && l->n_rval == FP)
+                       r->n_lval -= V9BIAS;
+
+               if (SIMM13(r->n_lval))
+                       expand(p, 0, "\tsub AL,AR,A1\t\t! subtract const\n");
+               else
+                       expand(p, 0, "\tsetx AR,A3,A2\t\t! subtract const\n"
+                                    "\tsub AL,A2,A1\n");
+               break;
+       case 'C':       /* Load constant to register. */
+               if (ISPTR(p->n_type))
+                       expand(p, 0,
+                               "\tsethi %h44(AL),A1\t\t! load label\n"
+                               "\tor A1,%m44(AL),A1\n"
+                               "\tsllx A1,12,A1\n"
+                               "\tor A1,%l44(AL),A1\n");
+               else if (SIMM13(p->n_lval))
+                       expand(p, 0, "\tor %g0,AL,A1\t\t\t! load const\n");
+               else
+                       expand(p, 0, "\tsetx AL,A2,A1\t\t! load const\n");
+               break;
+       case 'F':       /* Floating-point comparison, cf. hopcode(). */
+               switch (p->n_op) {
+                       case EQ:        str = "fbe"; break;
+                       case NE:        str = "fbne"; break;
+                       case ULE:
+                       case LE:        str = "fbule"; break;
+                       case ULT:
+                       case LT:        str = "fbul";  break;
+                       case UGE:
+                       case GE:        str = "fbuge"; break;
+                       case UGT:
+                       case GT:        str = "fbug";  break;
+                       /* XXX
+                       case PLUS:      str = "add"; break;
+                       case MINUS:     str = "sub"; break;
+                       case AND:       str = "and"; break;
+                       case OR:        str = "or";  break;
+                       case ER:        str = "xor"; break;*/
+                       default:
+                               comperr("unknown float code: %d", p->n_op);
+                               return;
+               }
+               printf(str);
+               break;
+
+       case 'Q':       /* Structure assignment. */
+               /* TODO Check if p->n_stsize is small and use a few ldx's
+                       to move the struct instead of memcpy. The equiv.
+                       could be done on all the architectures. */
+               sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+               if (l->n_rval != O0)
+                       printf("\tmov %s,%s\n", rnames[l->n_rval], rnames[O0]);
+               if (SIMM13(sz))
+                       printf("\tor %%g0,%d,%%o2\n", sz);
+               else
+                       printf("\tsetx %d,%%g1,%%o2\n", sz);
+               printf("\tcall memcpy\t\t\t! struct assign (dest, src, len)\n");
+               printf("\tnop\n");
+               break;
+       default:
+               cerror("unknown zzzcode call: %c", c);
+       }
+}
+
+int
+rewfld(NODE * p)
+{
+       return (1);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       printf("XXX fldexpand called\n"); /* XXX */
+       return 1;
+}
+
+int
+flshape(NODE * p)
+{
+       return SRREG;
+}
+
+int
+shtemp(NODE * p)
+{
+       return 0;
+}
+
+
+void
+adrcon(CONSZ val)
+{
+}
+
+void
+conput(FILE * fp, NODE * p)
+{
+       if (p->n_op != ICON) {
+               comperr("conput got bad op: %s", copst(p->n_op));
+               return;
+       }
+
+       if (p->n_name[0] != '\0') {
+               fprintf(fp, "%s", p->n_name);
+               if (p->n_lval > 0)
+                       fprintf(fp, "+");
+               if (p->n_lval)
+                       fprintf(fp, CONFMT, p->n_lval);
+       } else
+               fprintf(fp, CONFMT, p->n_lval);
+}
+
+void
+insput(NODE * p)
+{
+       comperr("insput");
+}
+
+void
+upput(NODE *p, int size)
+{
+       comperr("upput");
+}
+
+void
+adrput(FILE * io, NODE * p)
+{
+       int64_t off;
+
+       if (p->n_op == FLD) {
+               printf("adrput a FLD\n");
+               p = p->n_left;
+       }
+
+       if (p->n_op == UMUL && p->n_right == 0)
+               p = p->n_left;
+
+       off = p->n_lval;
+
+       switch (p->n_op) {
+       case NAME:
+               if (p->n_name[0] != '\0')
+                       fputs(p->n_name, io);
+               if (off > 0)
+                       fprintf(io, "+");
+               if (off != 0)
+                       fprintf(io, CONFMT, (long long int)off);
+               return;
+       case OREG:
+               fprintf(io, "%s", rnames[p->n_rval]);
+               if (p->n_rval == FP)
+                       off += V9BIAS;
+               if (p->n_rval == SP)
+                       off += V9BIAS + V9RESERVE;
+               if (off > 0)
+                       fprintf(io, "+");
+               if (off)
+                       fprintf(io, CONFMT, (CONSZ)off);
+               return;
+       case ICON:
+               /* addressable value of the constant */
+               conput(io, p);
+               return;
+       case REG:
+               fputs(rnames[p->n_rval], io);
+               return;
+       case FUNARG:
+               /* We do something odd and store the stack offset in n_rval. */
+               fprintf(io, "%d", V9BIAS + V9RESERVE + p->n_rval);
+               return;
+       default:
+               comperr("bad address, %s, node %p", copst(p->n_op), p);
+               return;
+       }
+}
+
+void
+cbgen(int o, int lab)
+{
+}
+
+void
+myreader(struct interpass * ipole)
+{
+}
+
+void
+mycanon(NODE * p)
+{
+}
+
+void
+myoptim(struct interpass * ipole)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+       printf("\t");
+
+       if (t == FLOAT)       printf("fmovs");
+       else if (t == DOUBLE) printf("fmovd");
+       else                  printf("mov");
+
+       printf(" %s,%s\t\t\t! rmove()\n", rnames[s], rnames[d]);
+}
+
+int
+gclass(TWORD t)
+{
+       if (t == FLOAT)
+               return CLASSB;
+       if (t == DOUBLE)
+               return CLASSC;
+       return CLASSA;
+}
+
+void
+lastcall(NODE *p)
+{
+}
+
+int
+special(NODE *p, int shape)
+{
+       return SRNOPE;
+}
+
+void mflags(char *str)
+{
+}
+
+int
+COLORMAP(int c, int *r)
+{
+       int num=0;
+
+       switch (c) {
+               case CLASSA:
+                       num += r[CLASSA];
+                       return num < 32;
+               case CLASSB:
+                       num += r[CLASSB];
+                       num += 2*r[CLASSC];
+                       return num < 32;;
+               case CLASSC:
+                       num += r[CLASSC];
+                       num += 2*r[CLASSB];
+                       return num < 17;
+               case CLASSD:
+                       return 0;
+               default:
+                       comperr("COLORMAP: unknown class: %d", c);
+                       return 0;
+       }
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       return 0;
+}
diff --git a/lang/pcc/pcc/arch/sparc64/macdefs.h b/lang/pcc/pcc/arch/sparc64/macdefs.h
new file mode 100644 (file)
index 0000000..7bc8946
--- /dev/null
@@ -0,0 +1,266 @@
+/*     $Id: macdefs.h,v 1.18 2016/03/05 15:53:04 ragge Exp $   */
+
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*
+ * Many arithmetic instructions take 'reg_or_imm' in SPARCv9, where imm
+ * means we can use a signed 13-bit constant (simm13). This gives us a
+ * shortcut for small constants, instead of loading them into a register.
+ * Special handling is required because 13 bits lies between SSCON and SCON.
+ */
+#define SIMM13(val) (val < 4096 && val > -4097)
+
+/*
+ * The SPARCv9 ABI specifies a stack bias of 2047 bits. This means that the
+ * end of our call space is %fp+V9BIAS, working back towards %sp+V9BIAS+176.
+ */
+#define V9BIAS 2047
+
+/*
+ * The ABI requires that every frame reserve 176 bits for saving registers
+ * in the case of a spill. The stack size must be 16-bit aligned.
+ */
+#define V9RESERVE 176
+#define V9STEP(x) ALIGN(x, 0xf)
+#define ALIGN(x, y) ((x & y) ? (x + y) & ~y : x)
+
+
+#define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT                (7*8) /* XXX */
+#define AUTOINIT       (0)
+
+/* Type sizes */
+#define SZCHAR         8
+#define SZBOOL         32
+#define SZINT          32
+#define SZFLOAT                32
+#define SZDOUBLE       64
+#define SZLDOUBLE      64
+#define SZLONG         64
+#define SZSHORT                16
+#define SZLONGLONG     64
+#define SZPOINT(t)     64
+
+/* Type alignments */
+#define ALCHAR         8
+#define ALBOOL         32
+#define ALINT          32
+#define ALFLOAT                32
+#define ALDOUBLE       64
+#define ALLDOUBLE      64
+#define ALLONG         64
+#define ALLONGLONG     64
+#define ALSHORT                16
+#define ALPOINT                64
+#define ALSTRUCT       32
+#define ALSTACK                64
+
+/* Min/max values. */
+#define        MIN_CHAR        -128
+#define        MAX_CHAR        127
+#define        MAX_UCHAR       255
+#define        MIN_SHORT       -32768
+#define        MAX_SHORT       32767
+#define        MAX_USHORT      65535
+#define        MIN_INT         -1
+#define        MAX_INT         0x7fffffff
+#define        MAX_UNSIGNED    0xffffffff
+#define        MIN_LONGLONG    0x8000000000000000LL
+#define        MAX_LONGLONG    0x7fffffffffffffffLL
+#define        MAX_ULONGLONG   0xffffffffffffffffULL
+#define        MIN_LONG        MIN_LONGLONG
+#define        MAX_LONG        MAX_LONGLONG
+#define        MAX_ULONG       MAX_ULONGLONG
+
+#define BOOL_TYPE      INT
+
+typedef        long long CONSZ;
+typedef        unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld"
+#define LABFMT  "L%d"
+#define STABLBL "LL%d"
+
+#define BACKAUTO               /* Stack grows negatively for automatics. */
+#define BACKTEMP               /* Stack grows negatively for temporaries. */
+
+#undef FIELDOPS
+#define TARGET_ENDIAN TARGET_BE
+
+#define BYTEOFF(x)     ((x)&03)
+
+#define        szty(t) ((ISPTR(t) || (t) == DOUBLE || \
+                (t) == LONG || (t) == ULONG || \
+                (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+
+/* Register names. */
+
+#define MAXREGS (31 + 31 + 16 + 2)
+#define NUMCLASS 4
+
+//define G0    -1
+#define G1     0
+#define G2     1
+#define G3     2
+#define G4     3
+#define G5     4
+#define G6     5
+#define G7     6
+#define O0     7
+#define O1     8
+#define O2     9
+#define O3     10
+#define O4     11
+#define O5     12
+#define O6     13
+#define O7     14
+#define L0     15
+#define L1     16
+#define L2     17
+#define L3     18
+#define L4     19
+#define L5     20
+#define L6     21
+#define L7     22
+#define I0     23
+#define I1     24
+#define I2     25
+#define I3     26
+#define I4     27
+#define I5     28
+#define I6     29
+#define I7     30
+
+#define F0     31
+#define F1     32
+#define F2     33
+#define F3     34
+#define F4     35
+#define F5     36
+#define F6     37
+#define F7     38
+#define F8     39
+#define F9     40
+#define F10    41
+#define F11    42
+#define F12    43
+#define F13    44
+#define F14    45
+#define F15    46
+#define F16    47
+#define F17    48
+#define F18    49
+#define F19    50
+#define F20    51
+#define F21    52
+#define F22    53
+#define F23    54
+#define F24    55
+#define F25    56
+#define F26    57
+#define F27    58
+#define F28    59
+#define F29    60
+#define F30    61
+//define F31    XXX
+#define D0     62
+#define D1     63
+#define D2     64
+#define D3     65
+#define D4     66
+#define D5     67
+#define D6     68
+#define D7     69
+#define D8     70
+#define D9     71
+#define D10    72
+#define D11    73
+#define D12    74
+#define D13    75
+#define D14    76
+#define D15    77
+
+#define SP     78
+#define FP     79
+
+#define FPREG  FP
+
+#define RETREG(x)      ((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : O0)
+#define RETREG_PRE(x)  ((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : I0)
+
+#define RSTATUS \
+       /* global */ \
+                              SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+               SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+       /* out */ \
+               SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+               SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+       /* local */ \
+               SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+               SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+       /* in */ \
+               SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+               SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+       /* 32-bit floating point */ \
+               SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+               SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+               SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+               SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, /*, SBREG */ \
+       /* 64-bit floating point */ \
+               SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+               SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+       /* sp */ SDREG, \
+       /* fp */ SDREG
+
+#define ROVERLAP \
+               { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+       { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+/* 32-bit floating point */ \
+       {  D0, -1 }, {  D0, -1 }, {  D1, -1 }, {  D1, -1 }, \
+       {  D2, -1 }, {  D2, -1 }, {  D3, -1 }, {  D3, -1 }, \
+       {  D4, -1 }, {  D4, -1 }, {  D5, -1 }, {  D5, -1 }, \
+       {  D6, -1 }, {  D6, -1 }, {  D7, -1 }, {  D7, -1 }, \
+       {  D8, -1 }, {  D8, -1 }, {  D9, -1 }, {  D9, -1 }, \
+       { D10, -1 }, { D10, -1 }, { D11, -1 }, { D11, -1 }, \
+       { D12, -1 }, { D12, -1 }, { D13, -1 }, { D13, -1 }, \
+       { D14, -1 }, { D14, -1 }, { D15, -1 }, /* { D15, -1 }, */ \
+/* 64-bit floating point */ \
+       {  F0,  F1, -1 }, {  F2,  F3, -1 }, {  F4,  F5, -1 }, \
+       {  F6,  F7, -1 }, {  F8,  F9, -1 }, { F10, F11, -1 }, \
+       { F12, F13, -1 }, { F14, F15, -1 }, { F16, F17, -1 }, \
+       { F18, F19, -1 }, { F20, F21, -1 }, { F22, F23, -1 }, \
+       { F24, F25, -1 }, { F26, F27, -1 }, { F28, F29, -1 }, \
+       { F30, /* F31, */ -1 }, \
+       { -1 }, \
+       { -1 }
+
+#define GCLASS(x)      (x <= I7                ? CLASSA : \
+                       (x <= F30               ? CLASSB : \
+                       (x <= D15               ? CLASSC : \
+                       (x == SP || x == FP     ? CLASSD : 0))))
+#define PCLASS(p)      (1 << gclass((p)->n_type))
+#define DECRA(x,y)     (((x) >> (y*7)) & 127)
+#define ENCRA(x,y)     ((x) << (7+y*7))
+#define ENCRD(x)       (x)
+
+int COLORMAP(int c, int *r);
diff --git a/lang/pcc/pcc/arch/sparc64/order.c b/lang/pcc/pcc/arch/sparc64/order.c
new file mode 100644 (file)
index 0000000..8a6916a
--- /dev/null
@@ -0,0 +1,117 @@
+/*     $Id: order.c,v 1.7 2011/06/05 08:54:42 plunky Exp $     */
+
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass2.h"
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       return !SIMM13(off);
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+void
+offstar(NODE *p, int shape)
+{
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (p->n_op == PLUS || p->n_op == MINUS) {
+               if (p->n_right->n_op == ICON && SIMM13(p->n_right->n_lval)) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+       }
+       (void)geninsn(p, INAREG);
+}
+
+void
+myormake(NODE *q)
+{
+}
+
+int
+shumul(NODE *p, int shape)
+{
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+int
+setbin(NODE *p)
+{
+       return 0;
+}
+
+int
+setasg(NODE *p, int cookie)
+{
+       return 0;
+}
+
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case STASG: {
+               static struct rspecial s[] = {
+                       { NEVER, O0 },
+                       { NRIGHT, O1 },
+                       { NEVER, O2 },
+                       { 0 }
+               };
+               return s;
+       }
+       }
+
+       comperr("unknown nspecial %d: %s", q - table, q->cstring);
+       return 0; /* XXX */
+}
+
+int
+setorder(NODE *p)
+{
+       return 0;
+}
+
+int *
+livecall(NODE *p)
+{
+       static int ret[] = { O0, O1, O2, O3, O4, O5, O6, O7, -1 };
+       return ret;
+}
+
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/sparc64/table.c b/lang/pcc/pcc/arch/sparc64/table.c
new file mode 100644 (file)
index 0000000..d6eb524
--- /dev/null
@@ -0,0 +1,965 @@
+/*     $Id: table.c,v 1.29 2011/06/05 08:54:42 plunky Exp $    */
+
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass2.h"
+
+#define TS64   TLONG|TLONGLONG
+#define TU64   TULONG|TULONGLONG|TPOINT
+#define T64    TS64|TU64
+
+struct optab table[] = {
+
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },      /* empty */
+
+{ PCONV,       INAREG,
+       SAREG,  T64|TINT,
+       SAREG,  T64,
+               0,      RLEFT,
+               "       ! convert between word and pointer\n", },
+
+/* Conversions. */
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TUNSIGNED,
+       SAREG,  TINT,
+               NAREG|NASL,     RESC1,
+               "       sra AL,0,A1     \t\t! (u)int64/32 -> (u)int32\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TINT|TUNSIGNED,
+       SAREG,  TSHORT,
+               NAREG|NASL,     RESC1,
+               "       sll AL,16,A1    \t\t! (u)int64/32 -> int16\n"
+               "       sra AL,16,A1\n"
+               "       sra AL, 0,A1\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TINT|TUNSIGNED,
+       SAREG,  TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       sll AL,16,A1    \t\t! (u)int64/32 -> uint16\n"
+               "       srl AL,16,A1\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+       SAREG,  TCHAR,
+               NAREG|NASL,     RESC1,
+               "       sll AL,24,A1    \t\t! (u)int64/32/16 -> int8\n"
+               "       sra AL,24,A1\n"
+               "       sra AL, 0,A1\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+       SAREG,  TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       and AL,0xff,A1  \t\t! (u)int64/32/16 -> uint8\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, /* TCHAR|TUCHAR added to handle char -> long (among others) */
+       SAREG,  T64,
+               0,      RLEFT,
+               "                       \t\t! (u)int64...8 -> (u)int64\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG,  TINT,
+               0,      RLEFT,
+               "                       \t\t! (u)int16/8 -> int32\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  T64|TINT|TSHORT|TCHAR,
+       SAREG,  TUNSIGNED,
+               0,      RLEFT,
+               "       srl AL, 0,A1    \t\t! int32/16/8 -> uint32\n", },
+
+{ SCONV,       INAREG,
+       SAREG,  TUSHORT|TUCHAR,
+       SAREG,  TUNSIGNED,
+               0,      RLEFT,
+               "                       \t\t! uint16/8 -> uint32\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  TINT|TUNSIGNED,
+       SBREG,  TFLOAT,
+               NBREG|NASL,     RESC1,
+               "       fitos AL,A1         \t\t! (u)int32 -> float\n", },
+
+{ SCONV,       INBREG,
+       SBREG,  T64,
+       SBREG,  TFLOAT,
+               NBREG|NASL,     RESC1,
+               "       fxtos AL,A1         \t\t! (u)int64 -> float\n", },
+
+{ SCONV,       INCREG,
+       SCREG,  TINT|TUNSIGNED,
+       SCREG,  TDOUBLE,
+               NCREG|NASL,     RESC1,
+               "       fitod AL,A1         \t\t! (u)int32 -> double\n", },
+
+{ SCONV,       INCREG,
+       SCREG,  T64,
+       SCREG,  TDOUBLE,
+               NCREG|NASL,     RESC1,
+               "       fxtod AL,A1         \t\t! (u)int64 -> double\n", },
+
+
+/* Floating-point conversions must be stored and loaded. */
+
+{ SCONV,       INAREG,
+       SOREG,  TFLOAT,
+       SAREG,  TINT,
+               NAREG|(2*NBREG),        RESC1,
+               "       ld [AL],A2    \t\t! float -> int32\n"
+               "       nop\n"
+               "       fmovs A2,A3\n"
+               "       fstoi A2,A2\n"
+               "       st A2,[AL]\n"
+               "       nop\n"
+               "       ld [AL],A1\n"
+               "       nop\n"
+               "       st A3,[AL]\n"
+               "       nop\n", },
+
+{ SCONV,       INAREG,
+       SOREG,  TDOUBLE,
+       SAREG,  TINT,
+               NAREG|(2*NCREG),        RESC1,
+               "       ld [AL],A2    \t\t! double -> int32\n"
+               "       nop\n"
+               "       fmovd A2,A3\n"
+               "       fdtoi A2,A2\n"
+               "       std A2,[AL]\n"
+               "       nop\n"
+               "       ldd [AL],A1\n"
+               "       nop\n"
+               "       std A3,[AL]\n"
+               "       nop\n", },
+
+{ SCONV,       INBREG,
+       SOREG,  T64|TUNSIGNED,
+       SBREG,  TFLOAT,
+               NBREG,  RESC1,
+               "       ld [AL],A1      \t\t! int64 -> float\n"
+               "       fxtos A1,A1\n", },
+
+{ SCONV,       INBREG,
+       SOREG,  TINT|TSHORT|TCHAR,
+       SBREG,  TFLOAT,
+               NBREG,  RESC1,
+               "       ld [AL],A1      \t\t! int32/16/8 -> float\n"
+               "       fitos A1,A1\n", }, // XXX need 'lds', 'ldh', etc
+
+{ SCONV,       INCREG,
+       SOREG,  T64|TUNSIGNED,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       ldd [AL],A1     \t\t! (u)int64 -> double\n"
+               "       fxtod A1,A1\n", },
+
+{ SCONV,       INCREG,
+       SOREG,  TINT|TSHORT|TCHAR,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       ld [AL],A1      \t\t! int32/16/8 -> double\n"
+               "       fitod A1,A1\n", }, // XXX need 'lds' 'ldh' 'ld', etc.
+
+{ SCONV,       INBREG,
+       SCREG,  TDOUBLE,
+       SBREG,  TFLOAT,
+               NBREG,  RESC1,
+               "       fdtos AL,A1     \t\t! double -> float\n",},
+
+{ SCONV,       INCREG,
+       SBREG,  TFLOAT,
+       SCREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       fstod AL,A1     \t\t! float -> double\n",},
+
+{ SCONV,    INAREG,
+       SBREG,  TFLOAT,
+       SAREG,  TINT,
+               NAREG|NBREG,    RESC1,
+               "       fstoi AL,A2     \t\t! float -> int\n"
+               "       st A2,[%fp+2047]\n"
+               "       nop\n"
+               "       ld [%fp+2047],A1\n"
+               "       nop\n",},
+
+{ SCONV,    INAREG,
+       SCREG,  TDOUBLE,
+       SAREG,  TINT,
+               NAREG|NCREG,    RESC1,
+               "       fdtoi AL,A2     \t\t! double -> int\n"
+               "       st A2,[%fp+2047]\n"
+               "       nop\n"
+               "       ld [%fp+2047],A1\n"
+        "      nop\n",},
+
+
+/* Multiplication and division */
+
+{ MUL, INAREG,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               NAREG|NASR|NASL,        RESC1,
+               "       mulx AL,AR,A1           ! multiply\n", },
+
+{ MUL, INBREG,
+       SBREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               NBREG|NBSR|NBSL,        RESC1,
+               "       fmuls AL,AR,A1          ! multiply float\n", },
+
+{ MUL, INCREG,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG|NCSR|NCSL,        RESC1,
+               "       fmuld AL,AR,A1          ! multiply double\n", },
+
+{ DIV, INAREG,
+       SAREG,  TUNSIGNED|TUSHORT|TUCHAR|TU64,
+       SAREG,  TUNSIGNED|TUSHORT|TUCHAR|TU64,
+               NAREG|NASR|NASL,        RESC1,
+               "       udivx AL,AR,A1          ! unsigned division\n", },
+
+{ DIV, INAREG,
+       SAREG,  TINT|TSHORT|TCHAR|TS64,
+       SAREG,  TINT|TSHORT|TCHAR|TS64,
+               NAREG|NASR|NASL,        RESC1,
+               "       sdivx AL,AR,A1          ! signed division\n", },
+
+{ DIV, INBREG,
+       SBREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               NBREG|NBSR|NBSL,        RESC1,
+               "       fdivs AL,AR,A1          ! divide float\n", },
+
+{ DIV, INCREG,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG|NCSR|NCSL,        RESC1,
+               "       fdivd AL,AR,A1          ! divide double\n", },
+
+{ MOD, INAREG,
+       SAREG,  TUNSIGNED|TUSHORT|TUCHAR|TU64,
+       SAREG,  TUNSIGNED|TUSHORT|TUCHAR|TU64,
+               NAREG, RESC1,
+               "       udivx AL,AR,A1          ! unsigned modulo\n"
+               "       mulx A1,AR,A1\n"
+               "       sub AL,A1,A1\n", },
+
+{ MOD, INAREG,
+       SAREG,  TINT|TSHORT|TCHAR|TS64,
+       SAREG,  TINT|TSHORT|TCHAR|TS64,
+               NAREG, RESC1,
+               "       sdivx AL,AR,A1          ! signed modulo\n"
+               "       mulx A1,AR,A1\n"
+               "       sub AL,A1,A1\n", },
+
+{ PLUS,        INAREG,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               NAREG|NASL,     RESC1,
+               "       add AL,AR,A1\n", },
+
+{ PLUS,        INBREG,
+       SBREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               NBREG|NBSL,     RESC1,
+               "       fadds AL,AR,A1\n", },
+
+{ PLUS,        INCREG,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG|NCSL,     RESC1,
+               "       faddd AL,AR,A1\n", },
+
+{ PLUS,        INAREG,
+       SAREG,  TANY,
+       SCON,   TANY,
+               (3*NAREG),      RESC1,
+               "ZA", },
+
+{ MINUS,       INAREG,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               NAREG|NASL,     RESC1,
+               "       sub AL,AR,A1\n", },
+
+{ MINUS,       INBREG,
+       SBREG,  TANY,
+       SBREG,  TANY,
+               NBREG|NBSL|NBSR,        RESC1,
+               "       fsubs AL,AR,A1\n", },
+
+{ MINUS,       INCREG,
+       SCREG,  TANY,
+       SCREG,  TANY,
+               NCREG|NCSL|NBSR,        RESC1,
+               "       fsubd AL,AR,A1\n", },
+
+{ MINUS,       INAREG,
+       SAREG,  TANY,
+       SCON,   TANY,
+               (3*NAREG),      RESC1,
+               "ZB", },
+
+{ UMINUS,      INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       sub %g0,AL,A1\n", },
+
+{ UMINUS,      INBREG,
+       SBREG,  TANY,
+       SANY,   TANY,
+               NBREG|NBSL,     RESC1,
+               "       fsubs %g0,AL,A1\n", },
+
+{ UMINUS,      INCREG,
+       SCREG,  TANY,
+       SANY,   TANY,
+               NCREG|NCSL,     RESC1,
+               "       fsubd %g0,AL,A1\n", },
+
+/* Shifts */
+
+{ RS,  INAREG,
+       SAREG,  TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG|SCON,     TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srl AL,AR,A1                    ! shift right\n", },
+
+{ RS,  INAREG,
+       SAREG,  T64,
+       SAREG|SCON,     T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       srlx AL,AR,A1                   ! shift right\n", },
+
+{ LS,  INAREG,
+       SAREG,  TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+       SAREG|SCON,     TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sll AL,AR,A1                    ! shift left\n", },
+
+{ LS,  INAREG,
+       SAREG,  T64,
+       SAREG|SCON,     TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       sllx AL,AR,A1                   ! shift left\n", },
+
+{ COMPL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1,
+               "       not AL,A1                       ! complement\n", },
+
+/* Assignments */
+
+{ ASSIGN,      FOREFF|INAREG,                  /* FIXME: Remove [,] here and add them in adrput instead. */
+       SAREG|SOREG,    TINT|TUNSIGNED,
+       SAREG,  TINT|TUNSIGNED,
+               0,      RDEST,
+               "       stw AR,[AL]             ! store (u)int32\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               0,      RDEST,
+               "       sth AR,[AL]             ! store (u)int16\n"
+               "       nop\n", },      
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR,
+               0,      RDEST,
+               "       stb AR,[AL]             ! store (u)int8\n"
+               "       nop\n", },      
+
+{ ASSIGN,      FOREFF|INAREG,
+       SOREG,  T64,
+       SAREG,  T64,
+               0,      RDEST,
+               "       stx AR,[AL]             ! store (u)int64\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               0,      RDEST,
+               "       st AR,[AL]              ! store float\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SOREG,  TINT,
+       SBREG,  TINT,
+               0,      RDEST,
+               "       st AR,[AL]              ! store int from fp address\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SOREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               0,      RDEST,
+               "       std AR,[AL]             ! store double\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SOREG,  TINT,
+       SCREG,  TINT,
+               0,      RDEST,
+               "       st AR,[AL]              ! store int from fp address\n"
+               "       nop\n", },
+
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,  TINT|TUNSIGNED,
+       SAREG,  TINT|TUNSIGNED,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store (u)int32 into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       stw AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,  TSHORT|TUSHORT,
+       SAREG,  TSHORT|TUSHORT,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store (u)int16 into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       sth AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,  TCHAR|TUCHAR,
+       SAREG,  TCHAR|TUCHAR,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store (u)int8 into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       stb AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SNAME,  T64,
+       SAREG,  T64,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store (u)int64 into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       stx AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SNAME,  TFLOAT|TINT,
+       SBREG,  TFLOAT|TINT,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store float into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       st AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SNAME,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store double into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       std AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SNAME,  TINT,
+       SCREG,  TINT,
+               NAREG,  RDEST,
+               "       sethi %h44(AL),A1       \t! store int into sname\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       st AR,[A1+%l44(AL)]\n"
+               "       nop\n", },
+
+{ ASSIGN,      FOREFF|INAREG,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               0,      RDEST,
+               "       mov AR,AL                       ! register move\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+       SBREG,  TANY,
+       SBREG,  TANY,
+               0,      RDEST,
+               "       fmovs AR,AL                     ! move float\n", },
+
+{ ASSIGN,      FOREFF|INCREG,
+       SCREG,  TANY,
+       SCREG,  TANY,
+               0,      RDEST,
+               "       fmovd AR,AL                     ! move double\n", },
+
+/* Structure assignment. */
+
+{ STASG,       INAREG|FOREFF,
+       SOREG|SNAME,    TANY,
+       SAREG,          TPTRTO|TANY,
+               NSPECIAL,       RDEST,
+               "ZQ", },
+
+/* Comparisons. */
+
+{ EQ,  FORCC,
+        SAREG, TANY,
+        SAREG, TANY,
+                0,      RESCC,
+               "       cmp AL,AR                       ! eq\n"
+               "       be LC\n"
+               "       nop\n", },
+
+{ NE,  FORCC,
+        SAREG, TANY,
+        SAREG, TANY,
+                0,      RESCC,
+               "       cmp AL,AR                       ! ne\n"
+                "      bne LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+       SAREG,  TANY,
+       SZERO,  TANY,
+               0,      RESCC,
+               "       O AL,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               NAREG|NASL,     RESCC,
+               "       sub AL,AR,A1                    ! oplog\n"
+               "       O A1,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+       SAREG,  TANY,
+       SCCON,  TANY,
+               NAREG|NASL,     RESCC,
+               "       sub AL,AR,A1                    ! oplog sccon\n"
+               "       O A1,LC\n"
+               "       nop\n", },
+
+{ OPLOG,       FORCC,
+       SBREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               NBREG, RESCC,
+               "       fcmps AL,AR                     ! oplog float\n"
+               "       ZF LC\n", },
+
+{ OPLOG,       FORCC,
+       SOREG,  TFLOAT,
+       SBREG,  TFLOAT,
+               NBREG, RESCC,
+               "       ld [AL], A1                     ! oplog float oreg\n"
+               "       nop\n"
+               "       fcmps A1,AR\n"
+               "       ZF LC\n", },
+
+{ OPLOG,       FORCC,
+       SCREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG, RESCC,
+               "       fcmpd AL,AR                     ! oplog double\n"
+               "       ZF LC\n", },
+
+{ OPLOG,       FORCC,
+       SOREG,  TDOUBLE,
+       SCREG,  TDOUBLE,
+               NCREG, RESCC,
+               "       ldd [AL], A1                    ! oplog double oreg\n"
+               "       nop\n"
+               "       fcmpd A1,AR\n"
+               "       ZF LC\n", },
+
+
+/* Load constants to register. */
+
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          T64,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t     ! load const (u)int64 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ldx [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          TINT,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t     ! load const int32 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ldsw [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          TUNSIGNED,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t! load const uint32 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       lduw [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          TSHORT,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t! load const int16 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ldsh [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          TUSHORT,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t     ! load const uint16 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       lduh [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          TCHAR,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t\t! load const int8 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ldsb [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+{ OPLTYPE,     INAREG,
+       SCON,           TANY,
+       SNAME,          TUCHAR,
+               NAREG,  RESC1,
+               "       sethi %h44(AL),A1\t! load const uint8 to reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ldub [A1+%l44(AL)],A1\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INBREG,
+       SBREG,  TANY,
+       SNAME,  TANY,
+               NAREG|NBREG,    RESC2,
+               "       sethi %h44(AL),A1\t\t! load const to fp reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ld [A1+%l44(AL)],A2\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INCREG,
+       SCREG,  TANY,
+       SNAME,  TANY,
+               NAREG|NCREG,    RESC2,
+               "       sethi %h44(AL),A1\t\t! load const to fp reg\n"
+               "       or A1,%m44(AL),A1\n"
+               "       sllx A1,12,A1\n"
+               "       ldd [A1+%l44(AL)],A2\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SCON,   TANY,
+               (2*NAREG),      RESC1,
+               "ZC" },
+
+/* Convert LTYPE to reg. */
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  TCHAR,
+               NAREG,  RESC1,
+               "       ldsb [AL],A1            ! load int8 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  TUCHAR,
+               NAREG,  RESC1,
+               "       ldub [AL],A1            ! load uint8 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  TSHORT,
+               NAREG,  RESC1,
+               "       ldsh [AL],A1            ! load int16 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  TUSHORT,
+               NAREG,  RESC1,
+               "       lduh [AL],A1            ! load uint16 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  TINT,
+               NAREG,  RESC1,
+               "       ldsw [AL],A1            ! load int32 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  TUNSIGNED,
+               NAREG,  RESC1,
+               "       lduw [AL],A1            ! load uint32 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SAREG,  TANY,
+       SOREG,  T64,
+               NAREG,  RESC1,
+               "       ldx [AL],A1             ! load (u)int64 to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INAREG,
+       SANY,   TANY,
+       SZERO,  TANY,
+               NAREG,  RESC1,
+               "       mov \%g0,A1\t           ! load 0 to reg\n", },
+
+{ OPLTYPE,     INBREG,
+       SBREG,  TFLOAT,
+       SOREG,  TFLOAT,
+               NBREG,  RESC1,
+               "       ld [AL],A1              ! load float to reg\n"
+               "       nop\n", },
+
+{ OPLTYPE,     INCREG,
+       SCREG,  TDOUBLE,
+       SOREG,  TDOUBLE,
+               NCREG,  RESC1,
+               "       ldd [AL],A1             ! load double to reg\n"
+               "       nop\n", },
+
+/* Jumps. */
+
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       call LL                 ! goto LL\n"
+               "       nop\n", },
+
+{ UCALL,       FOREFF,
+       SCON,           TANY,
+       SANY,           TANY,
+               0,      0,
+               "       call CL                 ! void CL()\n"
+               "       nop\n", },
+
+{ UCALL,         INAREG,
+        SCON,          TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,
+               "       call CL                 ! = CL()\n"
+               "       nop\n", },
+
+{ CALL,                FOREFF,
+       SCON,           TANY,
+       SANY,           TANY,
+               0,      0,
+               "       call CL                 ! void CL(constant)\n"
+               "       nop\n", },
+
+{ CALL,                INAREG,
+       SCON,           TANY,
+       SAREG,          TANY,
+               NAREG,          RESC1,
+               "       call CL                 ! = CL(constant)\n"
+               "       nop\n", },
+
+{ CALL,                INBREG,
+       SCON,           TANY,
+       SBREG,          TFLOAT,
+               NBREG,          RESC1,
+               "       call CL                 ! = CL(constant)\n"
+               "       nop\n", },
+
+{ CALL,                INCREG,
+       SCON,           TANY,
+       SCREG,          TDOUBLE,
+               NCREG,          RESC1,
+               "       call CL                 ! = CL(constant)\n"
+               "       nop\n", },
+
+{ CALL,         INAREG,
+        SAREG,         TANY,
+        SAREG,         TANY,
+                NAREG,     RESC1,
+               "       call AL                 ! = AL(args)\n"
+               "       nop\n", },
+
+{ CALL,                FOREFF,
+       SAREG,          TANY,
+       SANY,           TANY,
+               0,              0,
+               "       call AL                 ! void AL(args)\n"
+               "       nop\n", },
+
+{ UCALL,       FOREFF,
+       SAREG,          TANY,
+       SANY,           TANY,
+               0,      0,
+               "       call AL                 ! (*AL)()\n"
+               "       nop\n", },
+
+{ UCALL,       INAREG,
+       SAREG,          TANY,
+       SAREG,          TANY,
+               NAREG,          RESC1,
+               "       call AL                 ! = (*AL)()\n"
+               "       nop\n", },
+
+{ CALL,                INAREG,
+       SAREG,          TANY,
+       SAREG,          TANY,
+               NAREG,          RESC1,
+               "       call AL                 ! = (*AL)(args)\n"
+               "       nop\n", },
+
+/* Function arguments. */
+
+{ FUNARG,       FOREFF,
+        SAREG,  T64,
+        SANY,   TANY,
+                0,      0,
+                "      stx AL,[%sp+AR]         \t! save func arg to stack\n"
+               "       nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TINT|TUNSIGNED,
+        SANY,   TANY,
+                0,      0,
+                "      stw AL,[%sp+AR]         \t! save func arg to stack\n"
+               "       nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TSHORT|TUSHORT,
+        SANY,   TANY,
+                0,      0,
+                "      sth AL,[%sp+AR]         \t! save func arg to stack\n"
+               "       nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TCHAR|TUCHAR,
+        SANY,   TANY,
+                0,      0,
+                "      stb AL,[%sp+AR]         \t! save func arg to stack\n"
+               "       nop\n", },
+
+{ FUNARG,       FOREFF,
+        SBREG,  TFLOAT,
+        SANY,   TANY,
+                0,      0,
+                "      st AL,[%sp+AR]          \t! save func arg to stack\n"
+               "       nop\n", },
+
+{ FUNARG,       FOREFF,
+        SCREG,  TDOUBLE,
+        SANY,   TANY,
+                0,      0,
+                "      std AL,[%sp+AR]         \t! save func arg to stack\n"
+               "       nop\n", },
+
+
+/* Indirection. */
+
+{ OPSIMP,      INAREG,
+       SAREG,  TANY,
+       SAREG,  TANY,
+               NAREG|NASR|NASL,        RESC1,
+               "       O AL,AR,A1\n", },
+
+{ UMUL, INAREG,
+       SAREG,  T64,
+       SOREG,  T64,
+               NAREG,          RESC1,
+               "       ldx [AL],A1             ! (u)int64 load\n"
+               "       nop\n", },
+{ UMUL, INAREG,
+       SAREG,  TINT,
+       SOREG,  TINT,
+               NAREG,          RESC1,
+               "       ldsw [AL],A1            ! int32 load\n"
+               "       nop\n", },
+{ UMUL, INAREG,
+       SAREG,  TUNSIGNED,
+       SOREG,  TUNSIGNED,
+               NAREG,          RESC1,
+               "       lduw [AL],A1            ! uint32 load\n"
+               "       nop\n", },
+{ UMUL, INAREG,
+       SAREG,  TCHAR,
+       SOREG,  TCHAR,
+               NAREG,          RESC1,
+               "       ldsb [AL],A1            ! int8 load\n"
+               "       nop\n", },
+{ UMUL, INAREG,
+       SAREG,  TUCHAR,
+       SOREG,  TUCHAR,
+               NAREG,          RESC1,
+               "       ldub [AL],A1            ! uint8 load\n"
+               "       nop\n", },
+{ UMUL, INAREG,
+       SAREG,  TSHORT,
+       SOREG,  TSHORT,
+               NAREG,          RESC1,
+               "       ldsh [AL],A1            ! int16 load\n"
+               "       nop\n", },
+{ UMUL, INAREG,
+       SAREG,  TUSHORT,
+       SOREG,  TUSHORT,
+               NAREG,          RESC1,
+               "       lduh [AL],A1            ! uint16 load\n"
+               "       nop\n", },
+
+{ UMUL, INBREG,
+       SAREG,  TFLOAT,
+       SOREG,  TFLOAT,
+               NBREG,          RESC1,
+               "       ld [AL],A1              ! load float\n"
+               "       nop\n", },
+
+{ UMUL, INCREG,
+       SAREG,  TDOUBLE,
+       SOREG,  TDOUBLE,
+               NCREG,          RESC1,
+               "       ldd [AL],A1             ! load double\n"
+               "       nop\n", },
+
+{ FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE, "ERR: printing free op\n" },
+
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/lang/pcc/pcc/arch/vax/code.c b/lang/pcc/pcc/arch/vax/code.c
new file mode 100644 (file)
index 0000000..f2e715d
--- /dev/null
@@ -0,0 +1,488 @@
+/*     $Id: code.c,v 1.27 2015/10/12 18:07:13 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+#ifndef LANG_CXX
+#define        NODE    P1ND
+#undef NIL
+#define        NIL NULL
+#define        tfree p1tfree
+#define        talloc p1alloc
+#define        ccopy p1tcopy
+#endif
+
+/*
+ * Print out assembler segment name.
+ */
+void
+setseg(int seg, char *name)
+{
+       switch (seg) {
+       case PROG: name = ".text"; break;
+
+       case DATA:
+       case LDATA: name = ".data"; break;
+
+       case STRNG:
+       case RDATA: name = ".section .rodata"; break;
+
+       case UDATA: break;
+
+       case DTORS:
+               name = ".section .dtors,\"aw\",@progbits";
+               break;
+       case CTORS:
+               name = ".section .ctors,\"aw\",@progbits";
+               break;
+
+       case TLSDATA:
+       case TLSUDATA:
+               uerror("FIXME: unsupported segment %d", seg);
+               break;
+
+       case PICRDATA:
+               name = ".section .data.rel.ro.local,\"aw\",@progbits";
+               break;
+
+       case PICDATA:
+               name = ".section .data.rel,\"aw\",@progbits";
+               break;
+       case PICLDATA:
+               name = ".section .data.rel.local,\"aw\",@progbits";
+               break;
+
+       case NMSEG: 
+               printf("\t.section %s,\"a%c\",@progbits\n", name,
+                   cftnsp ? 'x' : 'w');
+               return;
+       }
+       printf("\t%s\n", name);
+}
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+       char *name;
+
+       name = getexname(sp);
+
+       if (sp->sclass == EXTDEF) {
+               printf("\t.globl %s\n", name);
+               if (ISFTN(sp->stype)) {
+                       printf("\t.type %s,@function\n", name);
+               } else {
+                       printf("\t.type %s,@object\n", name);
+                       printf("\t.size %s,%d\n", name,
+                           (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
+               }
+       }
+       if (sp->slevel == 0)
+               printf("%s:\n", name);
+       else
+               printf(LABFMT ":\n", sp->soffset);
+}
+
+static int strtemp;
+
+void
+efcode(void)
+{
+       TWORD t;
+       NODE *p, *q;
+
+       /* code for the end of a function */
+       if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+               return;
+
+       t = PTR+BTYPE(cftnsp->stype);
+       /* Create struct assignment */
+       q = tempnode(strtemp, t, 0, cftnsp->sap);
+       q = buildtree(UMUL, q, NIL);
+       p = block(REG, NIL, NIL, t, 0, cftnsp->sap);
+       regno(p) = R0;
+       p = buildtree(UMUL, p, NIL);
+       p = buildtree(ASSIGN, q, p);
+       ecomp(p);
+
+       /* put hidden arg in r0 on return */
+       q = tempnode(strtemp, INT, 0, 0);
+       p = block(REG, NIL, NIL, INT, 0, 0);
+       regno(p) = R0;
+        ecomp(buildtree(ASSIGN, p, q));
+}
+
+void
+bfcode(struct symtab **sp, int n)
+{
+       struct symtab *sp2;
+       NODE *p, *q;
+       int i, argbase, sz;
+
+       if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+               /* Move return address into temporary */
+               p = tempnode(0, INT, 0, 0);
+               strtemp = regno(p);
+               q = block(REG, 0, 0, INT, 0, 0);
+               regno(q) = R1;
+               ecomp(buildtree(ASSIGN, p, q));
+       }
+
+       /* correct arg alignment XXX should be done somewhere else */
+       argbase = ARGINIT;
+       for (i = 0; i < n; i++) {
+               sp2 = sp[i];
+               sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
+
+               SETOFF(sz, SZINT);
+               sp2->soffset = argbase;
+               argbase += sz;
+       }
+
+       if (xtemps == 0)
+               return;
+
+       /* put arguments in temporaries */
+       for (i = 0; i < n; i++) {
+               if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY ||
+                   cisreg(sp[i]->stype) == 0)
+                       continue;
+               if (cqual(sp[i]->stype, sp[i]->squal) & VOL)
+                       continue;
+               sp2 = sp[i];
+               p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap);
+               p = buildtree(ASSIGN, p, nametree(sp2));
+               sp[i]->soffset = regno(p->n_left);
+               sp[i]->sflags |= STNODE;
+               ecomp(p);
+       }
+
+}
+
+void
+ejobcode(int flag)
+{
+       /* called just before final exit */
+       /* flag is 1 if errors, 0 if none */
+}
+
+void
+bjobcode(void)
+{
+       astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
+       astypnames[SHORT] = astypnames[USHORT] = "\t.word";
+}
+
+#if 0
+aobeg(void)
+{
+       /* called before removing automatics from stab */
+}
+
+aocode(struct symtab *p)
+{
+       /* called when automatic p removed from stab */
+}
+
+aoend(void)
+{
+       /* called after removing all automatics from stab */
+}
+#endif
+
+void
+fldty(struct symtab *p)
+{
+       /* fix up type of field p */
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+       return 0;
+}
+
+#ifdef notyet
+struct sw heapsw[SWITSZ];      /* heap for switches */
+
+genswitch(register struct sw *p, int n)
+{
+       /*      p points to an array of structures, each consisting
+               of a constant value and a label.
+               The first is >=0 if there is a default label;
+               its value is the label number
+               The entries p[1] to p[n] are the nontrivial cases
+               */
+       register i;
+       register CONSZ j, range;
+       register dlab, swlab;
+
+       range = p[n].sval-p[1].sval;
+
+       if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
+
+               swlab = getlab();
+               dlab = p->slab >= 0 ? p->slab : getlab();
+
+               /* already in r0 */
+               printf("        casel   r0,$%ld,$%ld\n", p[1].sval, range);
+               deflab1(swlab);
+               for( i=1,j=p[1].sval; i<=n; j++) {
+                       printf("        .word   " LABFMT "-" LABFMT "\n",
+                           (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
+                               swlab);
+                       }
+
+               if( p->slab >= 0 ) branch( dlab );
+               else deflab1(dlab);
+               return;
+
+               }
+
+       if( n>8 ) {     /* heap switch */
+
+               heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
+               makeheap(p, n, 1);      /* build heap */
+
+               walkheap(1, n); /* produce code */
+
+               if( p->slab >= 0 )
+                       branch( dlab );
+               else
+                       deflab1(dlab);
+               return;
+       }
+
+       /* debugging code */
+
+       /* out for the moment
+       if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
+       */
+
+       /* simple switch code */
+
+       for( i=1; i<=n; ++i ){
+               /* already in r0 */
+
+               printf( "       cmpl    r0,$" );
+               printf( CONFMT, p[i].sval );
+               printf( "\n     jeql    " LBLFMT "\n", p[i].slab );
+               }
+
+       if( p->slab>=0 ) branch( p->slab );
+}
+
+makeheap(register struct sw *p, int m, int n)
+{
+       register int q;
+
+       q = select(m);
+       heapsw[n] = p[q];
+       if( q>1 ) makeheap(p, q-1, 2*n);
+       if( q<m ) makeheap(p+q, m-q, 2*n+1);
+}
+
+select(int m)
+{
+       register int l,i,k;
+
+       for(i=1; ; i*=2)
+               if( (i-1) > m ) break;
+       l = ((k = i/2 - 1) + 1)/2;
+       return( l + (m-k < l ? m-k : l));
+}
+
+walkheap(int start, int limit)
+{
+       int label;
+
+       if( start > limit ) return;
+       printf("        cmpl    r0,$%d\n",  heapsw[start].sval);
+       printf("        jeql    " LBLFMT "\n", heapsw[start].slab);
+       if( (2*start) > limit ) {
+               printf("        jbr     " LBLFMT "\n", heapsw[0].slab);
+               return;
+       }
+       if( (2*start+1) <= limit ) {
+               label = getlab();
+               printf("        jgtr    " LBLFMT "\n", label);
+       } else
+               printf("        jgtr    " LBLFMT "\n", heapsw[0].slab);
+       walkheap( 2*start, limit);
+       if( (2*start+1) <= limit ) {
+               deflab1(label);
+               walkheap( 2*start+1, limit);
+       }
+}
+#endif
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+       NODE *r, *l;
+
+       /* Fix function call arguments. On vax, just add funarg */
+       for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+               if (r->n_right->n_op != STARG) {
+                       r->n_right = intprom(r->n_right);
+                       r->n_right = block(FUNARG, r->n_right, NIL,
+                           r->n_right->n_type, r->n_right->n_df,
+                           r->n_right->n_ap);
+               }
+       }
+       if (r->n_op != STARG) {
+               l = talloc();
+               *l = *r;
+               r->n_op = FUNARG;
+               r->n_left = l;
+               r->n_left = intprom(r->n_left);
+               r->n_type = r->n_left->n_type;
+       }
+       return p;
+}
+
+/*
+ * Generate the builtin code for FFS.
+ */
+NODE *
+builtin_ffs(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q, *r;
+
+       p = tempnode(0, bt->rt, 0, 0);
+       r = block(XARG, ccopy(p), NIL, INT, 0, 0);
+       r->n_name = "=&r";
+       q = block(XARG, a, NIL, INT, 0, 0);
+       q->n_name = "g";
+       q = block(CM, r, q, INT, 0, 0);
+       q = block(XASM, q, block(ICON, 0, 0, STRTY, 0, 0), INT, 0, 0);
+       q->n_name = "ffs $0,$32,%1,%0;bneq 1f;mnegl $1,%0;1:;incl %0";
+       p = block(COMOP, q, p, bt->rt, 0, 0);
+       return p;
+}
+
+NODE *  
+builtin_ffsl(const struct bitable *bt, NODE *a)
+{       
+       return builtin_ffs(bt, a);
+}
+
+NODE *  
+builtin_ffsll(const struct bitable *bt, NODE *a)
+{
+       cerror("builtin_ffsll unimplemented");
+       return NIL;
+}
+
+NODE *
+builtin_return_address(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+       int v;
+
+       if (a->n_op != ICON)
+               goto bad;
+       v =a->n_lval;
+       tfree(a);
+
+       if (v != 0) {
+               werror("unsupported argument");
+               return xbcon(0, NULL, VOID|PTR);
+       }
+
+       f = block(REG, NIL, NIL, INCREF(PTR+CHAR), 0, 0);
+       regno(f) = FPREG;
+       f = block(UMUL,
+               block(PLUS, f,
+                   bcon(16), INCREF(PTR+CHAR), 0, 0), NIL, PTR+CHAR, 0, 0);
+       f = makety(f, PTR+VOID, 0, 0, 0);
+
+       return f;
+bad:
+       uerror("bad argument to __builtin_return_address");
+       return bcon(0);
+}
+
+NODE *
+builtin_frame_address(const struct bitable *bt, NODE *a)
+{
+       int nframes;
+       NODE *f;
+
+       if (a->n_op != ICON)
+               goto bad;
+
+       nframes = a->n_lval;
+
+       tfree(a);
+
+       f = block(REG, NIL, NIL, PTR+CHAR, 0, 0);
+       regno(f) = FPREG;
+
+       while (nframes--) {
+               f = block(UMUL,
+                       block(PLUS, f,
+                           bcon(12), INCREF(PTR+CHAR), 0, 0),
+                               NIL, PTR+CHAR, 0, 0);
+               f = makety(f, PTR+CHAR, 0, 0, 0);
+       }
+
+       return f;
+bad:
+       uerror("bad argument to __builtin_frame_address");
+       return bcon(0);
+}
+
+/*
+ * Return "canonical frame address".
+ */
+NODE *
+builtin_cfa(const struct bitable *bt, NODE *a)
+{
+       uerror("missing builtin_cfa");
+       return bcon(0);
+}
+
diff --git a/lang/pcc/pcc/arch/vax/local.c b/lang/pcc/pcc/arch/vax/local.c
new file mode 100644 (file)
index 0000000..189af24
--- /dev/null
@@ -0,0 +1,379 @@
+/*     $Id: local.c,v 1.31 2015/11/13 11:38:47 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+#ifndef LANG_CXX
+#define NODE P1ND
+#undef NIL
+#define        NIL NULL
+#define        nfree p1nfree
+#define        fwalk p1fwalk
+#endif
+
+static void r1arg(NODE *p, NODE *q);
+
+
+/*     this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(p) NODE *p; {
+
+       /* this is called to do local transformations on
+          an expression tree preparitory to its being
+          written out in intermediate code.
+       */
+
+       /* the major essential job is rewriting the
+          automatic variables and arguments in terms of
+          REG and OREG nodes */
+       /* conversion ops which are not necessary are also clobbered here */
+       /* in addition, any special features (such as rewriting
+          exclusive or) are easily handled here as well */
+
+       register struct symtab *q;
+       register NODE *r, *l;
+       register int o;
+       register int ml;
+
+
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal(%p)\n", p);
+               if (xdebug>1)
+                       fwalk(p, eprint, 0);
+       }
+#endif
+
+       switch( o = p->n_op ){
+
+       case NAME:
+               if((q = p->n_sp) == 0 ) { /* already processed; ignore... */
+                       return(p);
+                       }
+               switch( q->sclass ){
+
+               case REGISTER:
+               case AUTO:
+               case PARAM:
+                       /* fake up a structure reference */
+                       r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 );
+                       r->n_lval = 0;
+                       r->n_rval = (q->sclass==PARAM?ARGREG:FPREG);
+                       p = stref( block( STREF, r, p, 0, 0, 0 ) );
+                       break;
+               }
+               break;
+
+       case FORCE:
+               p->n_op = ASSIGN;
+               p->n_right = p->n_left;
+               p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
+               p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                   RETREG(CHAR) : RETREG(p->n_type);
+               break;
+
+       case SCONV:
+               l = p->n_left;
+               ml = p->n_type;
+#if 0
+               if (ml == INT && l->n_type == UNSIGNED) {
+                       p = nfree(p);
+                       break;
+               }
+#endif
+               if (l->n_op == ICON) {
+                       if (l->n_sp == 0) {
+                               p->n_type = UNSIGNED;
+                               concast(l, p->n_type);
+                       } else if (ml != INT && ml != UNSIGNED)
+                               break;
+                       l->n_type = ml;
+                       l->n_ap = 0;
+                       p = nfree(p);
+                       break;
+               }
+               break;
+
+       case STCALL:
+               /* see if we have been here before */
+               for (r = p->n_right; r->n_op == CM; r = r->n_left)
+                       ;
+               if (r->n_op == ASSIGN)
+                       break;
+
+               /* FALLTHROUGH */
+       case USTCALL:
+               /* Allocate buffer on stack to bounce via */
+               /* create fake symtab here */
+               q = getsymtab("77fake", STEMP);
+               q->stype = BTYPE(p->n_type);
+               q->sdf = p->n_df;
+               q->sap = p->n_ap;
+               q->soffset = NOOFFSET;
+               q->sclass = AUTO;
+               oalloc(q, &autooff);
+               r1arg(p, buildtree(ADDROF, nametree(q), 0));
+               break;
+       }
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("clocal end(%p)\n", p);
+               if (xdebug>1)
+                       fwalk(p, eprint, 0);
+       }
+#endif
+
+       return(p);
+}
+
+/*
+ * Add R1 with the dest address as arg to a struct return call.
+ */
+static void
+r1arg(NODE *p, NODE *q)
+{
+       NODE *r;
+
+       r = block(REG, NIL, NIL, PTR|VOID, 0, 0);
+       regno(r) = R1;
+       r = buildtree(ASSIGN, r, q);
+       if (p->n_op == USTCALL) {
+               p->n_op = STCALL;
+               p->n_right = r;
+       } else if (p->n_right->n_op != CM) {
+               p->n_right = block(CM, r, p->n_right, INT, 0, 0);
+       } else {
+               for (q = p->n_right; q->n_left->n_op == CM; q = q->n_left)
+                       ;
+               q->n_left = block(CM, r, q->n_left, INT, 0, 0);
+       }
+}
+
+void
+myp2tree(NODE *p)
+{
+       struct symtab *sp;
+
+       if ((cdope(p->n_op) & CALLFLG) && p->n_left->n_op == ADDROF &&
+           p->n_left->n_left->n_op == NAME) {
+               NODE *q = p->n_left->n_left;
+               nfree(p->n_left);
+               p->n_left = q;
+               q->n_op = ICON;
+       }
+
+       if (p->n_op != FCON) 
+               return;
+
+       sp = tmpalloc(sizeof(struct symtab));
+       sp->sclass = STATIC;
+       sp->sap = 0;
+       sp->slevel = 1; /* fake numeric label */
+       sp->soffset = getlab();
+       sp->sflags = 0;
+       sp->stype = p->n_type;
+       sp->squal = (CON >> TSHIFT);
+
+       defloc(sp);
+       inval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+       p->n_op = NAME;
+       p->n_lval = 0;
+       p->n_sp = sp;
+
+}
+
+/*
+ * Can we take & of a NAME?
+ */
+int
+andable(NODE *p)
+{
+       /* for now, delay name reference to table, for PIC code generation */
+       /* functions are called by name, convert they in myp2tree */
+       return 0;
+}
+
+/* is an automatic variable of type t OK for a register variable */
+int
+cisreg(TWORD t)
+{
+       return(1);      /* all are now */
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+       NODE *sp;
+
+       p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+       /* sub the size from sp */
+       sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       ecomp(buildtree(MINUSEQ, sp, p));
+
+       /* save the address of sp */
+       sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+       sp->n_lval = 0;
+       sp->n_rval = STKREG;
+       t->n_type = sp->n_type;
+       ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+char *
+exname( p ) char *p; {
+       /* make a name look like an external name in the local machine */
+       /* vad is elf now */
+       if (p == NULL)
+               return "";
+       return( p );
+       }
+
+/* map types which are not defined on the local machine */
+TWORD
+ctype(TWORD type) {
+       switch( BTYPE(type) ){
+
+       case LONG:
+               MODTYPE(type,INT);
+               break;
+
+       case ULONG:
+               MODTYPE(type,UNSIGNED);
+               break;
+
+       case LDOUBLE:   /* for now */
+               MODTYPE(type,DOUBLE);
+               }
+       return( type );
+       }
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+       int off, al;
+       char *name;
+
+       name = getexname(sp);
+       off = tsize(sp->stype, sp->sdf, sp->sap);
+       SETOFF(off,SZCHAR);
+       off /= SZCHAR;
+       al = talign(sp->stype, sp->sap)/SZCHAR;
+
+       if (sp->sclass == STATIC) {
+               if (sp->slevel == 0)
+                       printf("\t.local %s\n", name);
+               else
+                       printf("\t.local " LABFMT "\n", sp->soffset);
+       }
+       if (sp->slevel == 0) {
+               printf("\t.comm %s,0%o,%d\n", name, off, al);
+       } else
+               printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ * XXX - floating point constants may be wrong if cross-compiling.
+ */
+int
+ninval(CONSZ off, int fsz, NODE *p)
+{
+       union { float f; double d; long double l; int i[3]; } u;
+
+       switch (p->n_type) {
+       case LDOUBLE:
+               u.i[2] = 0;
+               u.l = (long double)((union flt *)p->n_dcon)->fp;
+               printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+               break;
+       case DOUBLE:
+               u.d = (double)((union flt *)p->n_dcon)->fp;
+               printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+               break;
+       case FLOAT:
+               u.f = (float)((union flt *)p->n_dcon)->fp;
+               printf("\t.long\t0x%x\n", u.i[0]);
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+
+}
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+       return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
diff --git a/lang/pcc/pcc/arch/vax/local2.c b/lang/pcc/pcc/arch/vax/local2.c
new file mode 100644 (file)
index 0000000..3bfeace
--- /dev/null
@@ -0,0 +1,1455 @@
+/*     $Id: local2.c,v 1.42 2015/01/04 19:17:23 ragge Exp $    */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include "ctype.h"
+/* a lot of the machine dependent parts of the second pass */
+
+static void prtype(NODE *n);
+static void acon(NODE *p);
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+void
+prologue(struct interpass_prolog *ipp)
+{
+       printf("        .word 0x%llx\n", (unsigned long long)ipp->ipp_regs[0]);
+       if (p2maxautooff)
+               printf("        subl2 $%d,%%sp\n", p2maxautooff);
+       if (pflag) {
+               int i = getlab2();
+               printf("\tmovab\t" LABFMT ",%%r0\n", i);
+               printf("\tjsb\t__mcount\n");
+               printf("\t.data\n");
+               printf("\t.align  2\n");
+               printf(LABFMT ":\t.long\t0\n", i);
+               printf("\t.text\n");
+       }
+}
+
+/*
+ * Called after all instructions in a function are emitted.
+ * Generates code for epilog here.
+ */
+void
+eoftn(struct interpass_prolog *ipp)
+{
+       if (ipp->ipp_ip.ip_lbl == 0)
+               return; /* no code needs to be generated */
+       printf("        ret\n");
+}
+
+struct hoptab { int opmask; char * opstring; } ioptab[] = {
+
+       { PLUS, "add", },
+       { MINUS,        "sub", },
+       { MUL,  "mul", },
+       { DIV,  "div", },
+       { OR,   "bis", },
+       { ER,   "xor", },
+       { AND,  "bic", },
+       { -1, ""     },
+};
+
+void
+hopcode( f, o ){
+       /* output the appropriate string from the above table */
+
+       register struct hoptab *q;
+
+       for( q = ioptab;  q->opmask>=0; ++q ){
+               if( q->opmask == o ){
+                       printf( "%s", q->opstring );
+/* tbl
+                       if( f == 'F' ) printf( "e" );
+                       else if( f == 'D' ) printf( "d" );
+   tbl */
+/* tbl */
+                       switch( f ) {
+                               case 'L':
+                               case 'W':
+                               case 'B':
+                               case 'D':
+                               case 'F':
+                                       printf("%c", tolower(f));
+                                       break;
+
+                               }
+/* tbl */
+                       return;
+                       }
+               }
+       cerror( "no hoptab for %s", opst[o] );
+       }
+
+char *
+rnames[] = {  /* keyed to register number tokens */
+
+       "%r0", "%r1", "%r2", "%r3", "%r4", "%r5",
+       "%r6", "%r7", "%r8", "%r9", "%r10", "%r11",
+       "%ap", "%fp", "%sp", "%pc",
+       /* The concatenated regs has the name of the lowest */
+       "%r0", "%r1", "%r2", "%r3", "%r4", "%r5",
+       "%r6", "%r7", "%r8", "%r9", "%r10"
+       };
+
+int
+tlen(NODE *p)
+{
+       switch(p->n_type) {
+       case CHAR:
+       case UCHAR:
+               return(1);
+
+       case SHORT:
+       case USHORT:
+               return(2);
+
+       case DOUBLE:
+       case LONGLONG:
+       case ULONGLONG:
+               return(8);
+
+       default:
+               return(4);
+       }
+}
+
+void
+prtype(NODE *n)
+{
+       static char pt[] = { 0, 0, 'b', 'b', 'w', 'w', 'l', 'l', 0, 0,
+           'q', 'q', 'f', 'd' };
+       TWORD t = n->n_type;
+
+       if (ISPTR(t))
+               t = UNSIGNED;
+
+       if (t > DOUBLE || pt[t] == 0)
+               comperr("prtype: bad type");
+       putchar(pt[t]);
+}
+
+/*
+ * Emit conversions as given by the following table. Dest is always reg,
+ *   if it should be something else let peephole optimizer deal with it.
+ *   This code ensures type correctness in 32-bit registers.
+ *   XXX is that necessary?
+ *
+ * From                                To
+ *      char   uchar  short  ushort int    uint   ll    ull   float double
+ * char  movb   movb   cvtbw  cvtbw  cvtbl  cvtbl  A     A     cvtbf cvtbd
+ * uchar movb   movb   movzbw movzbw movzbl movzbl B     B     G     G
+ * short movb   movb   movw   movw   cvtwl  cvtwl  C(A)  C(A)  cvtwf cvtwd
+ * ushrt movb   movb   movw   movw   movzwl movzwl D(B)  D(B)  H     H
+ * int   movb   movb   movw   movw   movl   movl   E     E     cvtlf cvtld
+ * uint  movb   movb   movw   movw   movl   movl   F     F     I     I
+ * ll    movb   movb   movw   movw   movl   movl   movq  movq  J     K
+ * ull   movb   movb   movw   movw   movl   movl   movq  movq  L     M
+ * float cvtfb  cvtfb  cvtfw  cvtfw  cvtfl  cvtfl  N     O     movf  cvtfd
+ * doubl cvtdb  cvtdb  cvtdw  cvtdw  cvtdl  cvtdl  P     Q     cvtdf movd
+ *
+ *  A: cvtbl + sign extend
+ *  B: movzbl + zero extend
+ *  G: movzbw + cvtwX
+ *  H: movzwl + cvtwX
+ *  I: cvtld + addX
+ *  J: call __floatdisf
+ *  K: call __floatdidf
+ *  L: xxx + call __floatdisf
+ *  M: xxx + call __floatdidf
+ *  N: call __fixsfdi
+ *  O: call __fixunssfdi
+ *  P: call __fixdfdi
+ *  Q: call __fixunsdfdi
+ */
+
+#define        MVD     1 /* mov + dest type */
+#define        CVT     2 /* cvt + src type + dst type */
+#define        MVZ     3 /* movz + src type + dst type */
+#define        CSE     4 /* cvt + src type + l + sign extend upper */
+#define        MZE     5 /* movz + src type + l + zero extend upper */
+#define        MLE     6 /* movl + sign extend upper */
+#define        MLZ     7 /* movl + zero extend upper */
+#define        MZC     8 /* movz + cvt */
+
+static char scary[][10] = {
+       { MVD, MVD, CVT, CVT, CVT, CVT, CSE, CSE, CVT, CVT },
+       { MVD, MVD, MVZ, MVZ, MVZ, MVZ, MZE, MZE, MZC, MZC },
+       { MVD, MVD, MVD, MVD, CVT, CVT, CSE, CSE, CVT, CVT },
+       { MVD, MVD, MVD, MVD, MVZ, MVZ, MZE, MZE, MZC, MZC },
+       { MVD, MVD, MVD, MVD, MVD, MVD, MLE, MLE, CVT, CVT },
+       { MVD, MVD, MVD, MVD, MVD, MVD, MLZ, MLZ, 'I', 'I' },
+       { MVD, MVD, MVD, MVD, MVD, MVD, MVD, MVD, 'J', 'K' },
+       { MVD, MVD, MVD, MVD, MVD, MVD, MVD, MVD, 'L', 'M' },
+       { CVT, CVT, CVT, CVT, CVT, CVT, 'N', 'O', MVD, CVT },
+       { CVT, CVT, CVT, CVT, CVT, CVT, 'P', 'Q', CVT, MVD },
+};
+
+static void
+sconv(NODE *p)
+{
+       NODE *l = p->n_left;
+       TWORD ts, td;
+       int o;
+
+       /*
+        * Source node may be in register or memory.
+        * Result is always in register.
+        */
+       ts = l->n_type;
+       if (ISPTR(ts))
+               ts = UNSIGNED;
+       td = p->n_type;
+       ts = ts < LONG ? ts-2 : ts-4;
+       td = td < LONG ? td-2 : td-4;
+
+       o = scary[ts][td];
+       switch (o) {
+       case MLE:
+       case MLZ:
+               expand(p, INAREG|INBREG, "\tmovl\tAL,A1\n");
+               break;
+
+       case MVD:
+               if (l->n_op == REG && regno(l) == regno(getlr(p, '1')))
+                       break; /* unneccessary move */
+               expand(p, INAREG|INBREG, "\tmovZR\tAL,A1\n");
+               break;
+
+       case CSE:
+               expand(p, INAREG|INBREG, "\tcvtZLl\tAL,A1\n");
+               break;
+
+       case CVT:
+               expand(p, INAREG|INBREG, "\tcvtZLZR\tAL,A1\n");
+               break;
+
+       case MZE:
+               expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n");
+               break;
+
+       case MVZ:
+               expand(p, INAREG|INBREG, "\tmovzZLZR\tAL,A1\n");
+               break;
+
+       case MZC:
+               expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n");
+               expand(p, INAREG|INBREG, "\tcvtlZR\tA1,A1\n");
+               break;
+
+       case 'I': /* unsigned to double */
+               expand(p, INAREG|INBREG, "\tcvtld\tAL,A1\n");
+               printf("\tjgeq\t1f\n");
+               expand(p, INAREG|INBREG, "\taddd2\t$0d4.294967296e+9,A1\n");
+               printf("1:\n");
+               break;
+       default:
+               comperr("unsupported conversion %d", o);
+       }
+       switch (o) {
+       case MLE:
+       case CSE:
+               expand(p, INBREG, "\tashl\t$-31,A1,U1\n");
+               break;
+       case MLZ:
+       case MZE:
+               expand(p, INAREG|INBREG, "\tclrl\tU1\n");
+               break;
+       }
+}
+
+/*
+ * Assign a constant from p to q.  Both are expected to be leaves by now.
+ * This is for 64-bit integers.
+ */
+static void
+casg64(NODE *p)
+{
+       NODE *l, *r;
+       char *str;
+       int mneg = 1;
+       
+       l = p->n_left;
+       r = p->n_right;
+
+#ifdef PCC_DEBUG
+       if (r->n_op != ICON)
+               comperr("casg");
+#endif
+       if (r->n_name[0] != '\0') {
+               /* named constant, nothing to do */
+               str = "movq\tAR,AL";
+               mneg = 0;
+       } else if (r->n_lval == 0) {
+               str = "clrq\tAL";
+               mneg = 0;
+       } else if (r->n_lval < 0) {
+               if (r->n_lval >= -63) {
+                       r->n_lval = -r->n_lval;
+                       str = "mnegl\tAR,AL";
+               } else if (r->n_lval >= -128) {
+                       str = "cvtbl\tAR,AL";
+               } else if (r->n_lval >= -32768) {
+                       str = "cvtwl\tAR,AL";
+               } else if (r->n_lval >= -4294967296LL) {
+                       str = "movl\tAR,AL";
+               } else {
+                       str = "movq\tAR,AL";
+                       mneg = 0;
+               }
+       } else {
+               mneg = 0;
+               if (r->n_lval <= 63 || r->n_lval > 4294967295LL) {
+                       str = "movq\tAR,AL";
+               } else if (r->n_lval <= 255) {
+                       str = "movzbl\tAR,AL\n\tclrl\tUL";
+               } else if (r->n_lval <= 65535) {
+                       str = "movzwl\tAR,AL\n\tclrl\tUL";
+               } else /* if (r->n_lval <= 4294967295) */ {
+                       str = "movl\tAR,AL\n\tclrl\tUL";
+               }
+       }
+       expand(p, FOREFF, str);
+       if (mneg)
+               expand(p, FOREFF, "\n\tmnegl $1,UL");
+}
+
+/*
+ * Assign a constant from p to q.  Both are expected to be leaves by now.
+ * This is only for 32-bit integer types.
+ */
+static void
+casg(NODE *p)
+{
+       NODE *l, *r;
+       char *str;
+       
+       l = p->n_left;
+       r = p->n_right;
+
+#ifdef PCC_DEBUG
+       if (r->n_op != ICON)
+               comperr("casg");
+#endif
+       if (r->n_name[0] != '\0') {
+               /* named constant, nothing to do */
+               str = "movZL\tAR,AL";
+       } else if (r->n_lval == 0) {
+               str = "clrZL\tAL";
+       } else if (r->n_lval < 0) {
+               if (r->n_lval >= -63) {
+                       r->n_lval = -r->n_lval;
+                       str = "mnegZL\tAR,AL";
+               } else if (r->n_lval >= -128) {
+                       if (l->n_type == CHAR)
+                               str = "movb\tAR,AL";
+                       else
+                               str = "cvtbZL\tAR,AL";
+               } else if (r->n_lval >= -32768) {
+                       if (l->n_type == SHORT)
+                               str = "movw\tAR,AL";
+                       else
+                               str = "cvtwZL\tAR,AL";
+               } else
+                       str = "movZL\tAR,AL";
+       } else {
+               if (r->n_lval <= 63 || r->n_lval > 65535) {
+                       str = "movZL\tAR,AL";
+               } else if (r->n_lval <= 255) {
+                       str = l->n_type < SHORT ?
+                           "movb\tAR,AL" : "movzbZL\tAR,AL";
+               } else /* if (r->n_lval <= 65535) */ {
+                       str = l->n_type < INT ?
+                           "movw\tAR,AL" : "movzwZL\tAR,AL";
+               }
+       }
+       expand(p, FOREFF, str);
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+       int u;
+       int s = getlab2();
+       int e = p->n_label;
+       int cb1, cb2;
+
+       u = p->n_op;
+       switch (p->n_op) {
+       case NE:
+               cb1 = 0;
+               cb2 = NE;
+               break;
+       case EQ:
+               cb1 = NE;
+               cb2 = 0;
+               break;
+       case LE:
+       case LT:
+               u += (ULE-LE);
+               /* FALLTHROUGH */
+       case ULE:
+       case ULT:
+               cb1 = GT;
+               cb2 = LT;
+               break;
+       case GE:
+       case GT:
+               u += (ULE-LE);
+               /* FALLTHROUGH */
+       case UGE:
+       case UGT:
+               cb1 = LT;
+               cb2 = GT;
+               break;
+       
+       default:
+               cb1 = cb2 = 0; /* XXX gcc */
+       }
+       if (p->n_op >= ULE)
+               cb1 += 4, cb2 += 4;
+       expand(p, 0, "  cmpl UL,UR\n");
+       if (cb1) cbgen(cb1, s);
+       if (cb2) cbgen(cb2, e);
+       expand(p, 0, "  cmpl AL,AR\n");
+       cbgen(u, e);
+       deflab(s);
+}
+
+
+void
+zzzcode(NODE *p, int c)
+{
+       NODE *l, *r;
+       TWORD t;
+       int m;
+       char *ch;
+
+       switch (c) {
+       case 'N':  /* logical ops, turned into 0-1 */
+               /* use register given by register 1 */
+               cbgen( 0, m=getlab2());
+               deflab( p->n_label );
+               printf( "       clrl    %s\n", rnames[getlr( p, '1' )->n_rval] );
+               deflab( m );
+               return;
+
+       case 'A': /* Assign a constant directly to a memory position */
+               printf("\t");
+               if (p->n_type < LONG || ISPTR(p->n_type))
+                       casg(p);
+               else
+                       casg64(p);
+               printf("\n");
+               break;
+
+       case 'B': /* long long compare */
+               twollcomp(p);
+               break;
+
+       case 'C':       /* num words pushed on arg stack */
+               printf("$%d", p->n_qual);
+               break;
+
+       case 'D':       /* INCR and DECR */
+               zzzcode(p->n_left, 'A');
+               printf("\n      ");
+
+#if 0
+       case 'E':       /* INCR and DECR, FOREFF */
+               if (p->n_right->n_lval == 1)
+                       {
+                       printf("%s", (p->n_op == INCR ? "inc" : "dec") );
+                       prtype(p->n_left);
+                       printf("        ");
+                       adrput(stdout, p->n_left);
+                       return;
+                       }
+               printf("%s", (p->n_op == INCR ? "add" : "sub") );
+               prtype(p->n_left);
+               printf("2       ");
+               adrput(stdout, p->n_right);
+               printf(",");
+               adrput(p->n_left);
+               return;
+#endif
+
+       case 'F':       /* register type of right operand */
+               {
+               register NODE *n;
+               register int ty;
+
+               n = getlr( p, 'R' );
+               ty = n->n_type;
+
+               if (x2debug) printf("->%d<-", ty);
+
+               if ( ty==DOUBLE) printf("d");
+               else if ( ty==FLOAT ) printf("f");
+               else printf("l");
+               return;
+               }
+
+       case 'G': /* emit conversion instructions */
+               sconv(p);
+               break;
+
+       case 'J': /* jump or ret? */
+               {
+                       struct interpass *ip =
+                           DLIST_PREV((struct interpass *)p2env.epp, qelem);
+                       if (ip->type != IP_DEFLAB ||
+                           ip->ip_lbl != getlr(p, 'L')->n_lval)
+                               expand(p, FOREFF, "jbr  LL");
+                       else
+                               printf("ret");
+               }
+               break;
+
+       case 'L':       /* type of left operand */
+       case 'R':       /* type of right operand */
+               {
+               register NODE *n;
+
+               n = getlr ( p, c);
+               if (x2debug) printf("->%d<-", n->n_type);
+
+               prtype(n);
+               return;
+               }
+
+       case 'l': /* print out long long constant as hex */
+       case 'r': /* works around a bug in gas */
+               l = getlr(p, c == 'l' ? 'L' : 'R');
+               if (l->n_op == ICON && ISLONGLONG(l->n_type)) {
+                       printf("$0x%llx", l->n_lval);
+               } else
+                       adrput(stdout, l);
+               break;
+
+       case 'O': /* print out emulated ops */
+               expand(p, FOREFF, "\tmovq       AR,-(%sp)\n");
+               expand(p, FOREFF, "\tmovq       AL,-(%sp)\n");
+               if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
+               else if (p->n_op == DIV) ch = "div";
+               else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
+               else if (p->n_op == MOD) ch = "mod";
+               else if (p->n_op == MUL) ch = "mul";
+               else ch = 0, comperr("ZO %d", p->n_op);
+               printf("\tcalls $4,__%sdi3\n", ch);
+               break;
+
+
+       case 'Z':       /* complement mask for bit instr */
+               printf("$%lld", ~p->n_right->n_lval);
+               return;
+
+       case 'U':       /* 32 - n, for unsigned right shifts */
+               t = DEUNSIGN(p->n_left->n_type);
+               m = t == CHAR ? 8 : t == SHORT ? 16 : 32;
+               printf("$" CONFMT, m - p->n_right->n_lval);
+               return;
+
+       case 'T':       /* rounded structure length for arguments */
+               {
+               int size;
+
+               size = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+               SETOFF( size, 4);
+               printf("$%d", size);
+               return;
+               }
+
+       case 'S':  /* structure assignment */
+               {
+                       register int size;
+
+                       size = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
+                       SETOFF(size, 4);
+                       l = r = NULL; /* XXX gcc */
+                       if( p->n_op == STASG ){
+                               l = p->n_left;
+                               r = p->n_right;
+
+                               }
+                       else if( p->n_op == STARG ){
+                               /* store an arg into a temporary */
+                               printf("\tsubl2 $%d,%%sp\n",
+                                   size < 4 ? 4 : size);
+                               l = mklnode(OREG, 0, SP, INT);
+                               r = p->n_left;
+                               }
+                       else cerror( "STASG bad" );
+
+                       if( r->n_op == ICON ) r->n_op = NAME;
+                       else if( r->n_op == REG ) r->n_op = OREG;
+                       else if( r->n_op != OREG ) cerror( "STASG-r" );
+
+               if (size != 0) {
+                       if( size <= 0 || size > 65535 )
+                               cerror("structure size <0=0 or >65535");
+
+                       switch(size) {
+                               case 1:
+                                       printf("        movb    ");
+                                       break;
+                               case 2:
+                                       printf("        movw    ");
+                                       break;
+                               case 4:
+                                       printf("        movl    ");
+                                       break;
+                               case 8:
+                                       printf("        movq    ");
+                                       break;
+                               default:
+                                       printf("        movc3   $%d,", size);
+                                       break;
+                       }
+                       adrput(stdout, r);
+                       printf(",");
+                       adrput(stdout, l);
+                       printf("\n");
+               }
+
+                       if( r->n_op == NAME ) r->n_op = ICON;
+                       else if( r->n_op == OREG ) r->n_op = REG;
+                       if (p->n_op == STARG)
+                               tfree(l);
+
+                       }
+               break;
+
+       default:
+               comperr("illegal zzzcode '%c'", c);
+       }
+}
+
+void
+rmove(int rt, int rs, TWORD t)
+{
+       char c = (t == FLOAT ? 'f' : t == DOUBLE ? 'd' :
+           t == LONGLONG || t == ULONGLONG ? 'q' : 'l');
+       printf("        mov%c   %s,%s\n", c, rnames[rt], rnames[rs]);
+}
+
+int
+rewfld(NODE *p)
+{
+       return(1);
+}
+
+#if 0
+int
+callreg(NODE *p)
+{
+       return( R0 );
+}
+
+int
+base(register NODE *p)
+{
+       register int o = p->op;
+
+       if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */
+       if( o==REG ) return( p->rval );
+    if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON)
+               return( p->left->rval );
+    if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
+               return( p->rval + 0200*1 );
+       if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 );
+       if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 );
+       if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG
+         && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
+               return( p->left->left->rval + 0200*(1+2) );
+       return( -1 );
+}
+
+int
+offset(register NODE *p, int tyl)
+{
+
+       if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval );
+       if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) &&
+             (p->right->op==ICON && p->right->name[0]=='\0')
+             && (1<<p->right->lval)==tyl))
+               return( p->left->rval );
+       return( -1 );
+}
+#endif
+
+#if 0
+void
+makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
+       register NODE *t;
+       NODE *f;
+
+       p->n_op = OREG;
+       f = p->n_left;  /* have to free this subtree later */
+
+       /* init base */
+       switch (q->n_op) {
+               case ICON:
+               case REG:
+               case OREG:
+                       t = q;
+                       break;
+
+               case MINUS:
+                       q->n_right->n_lval = -q->n_right->n_lval;
+               case PLUS:
+                       t = q->n_right;
+                       break;
+
+               case UMUL:
+                       t = q->n_left->n_left;
+                       break;
+
+               default:
+                       cerror("illegal makeor2");
+                       t = NULL; /* XXX gcc */
+       }
+
+       p->n_lval = t->n_lval;
+       p->n_name = t->n_name;
+
+       /* init offset */
+       p->n_rval = R2PACK( (b & 0177), o, (b>>7) );
+
+       tfree(f);
+       return;
+       }
+
+int
+canaddr( p ) NODE *p; {
+       register int o = p->n_op;
+
+       if( o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, STARNM|SOREG)) ) return(1);
+       return(0);
+       }
+
+shltype( o, p ) register NODE *p; {
+       return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UMUL && shumul(p->n_left, STARNM|SOREG)) );
+       }
+#endif
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+       return 0;
+}
+
+int
+flshape(register NODE *p)
+{
+       return( p->n_op == REG || p->n_op == NAME || p->n_op == ICON ||
+               (p->n_op == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)) );
+}
+
+int
+shtemp(register NODE *p)
+{
+       if( p->n_op == STARG ) p = p->n_left;
+       return( p->n_op==NAME || p->n_op ==ICON || p->n_op == OREG || (p->n_op==UMUL && shumul(p->n_left, STARNM|SOREG)) );
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("shumul(%p)\n", p);
+
+       /* Turns currently anything into OREG on vax */
+       if (shape & SOREG)
+               return SROREG;
+       return SRNOPE;
+}
+
+
+#ifdef notdef
+int
+shumul( p, shape ) register NODE *p; int shape; {
+       register int o;
+
+       if (x2debug) {
+                printf("\nshumul:op=%d,lop=%d,rop=%d", p->n_op, p->n_left->n_op, p->n_right->n_op);
+               printf(" prname=%s,plty=%d, prlval=%lld\n", p->n_right->n_name, p->n_left->n_type, p->n_right->n_lval);
+               }
+
+
+       o = p->n_op;
+       if( o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON )
+               if (shape & STARNM)
+                       return SRDIR;
+
+       if( ( o == INCR || o == ASG MINUS ) &&
+           ( p->n_left->n_op == REG && p->n_right->n_op == ICON ) &&
+           p->n_right->n_name[0] == '\0' )
+               {
+               switch (p->n_left->n_type)
+                       {
+                       case CHAR|PTR:
+                       case UCHAR|PTR:
+                               o = 1;
+                               break;
+
+                       case SHORT|PTR:
+                       case USHORT|PTR:
+                               o = 2;
+                               break;
+
+                       case INT|PTR:
+                       case UNSIGNED|PTR:
+                       case LONG|PTR:
+                       case ULONG|PTR:
+                       case FLOAT|PTR:
+                               o = 4;
+                               break;
+
+                       case DOUBLE|PTR:
+                               o = 8;
+                               break;
+
+                       default:
+                               if ( ISPTR(p->n_left->n_type) ) {
+                                       o = 4;
+                                       break;
+                                       }
+                               else return(0);
+                       }
+               return( p->n_right->n_lval == o ? STARREG : 0);
+               }
+
+       return( SRNOPE );
+       }
+#endif
+
+void
+adrcon(CONSZ val)
+{
+       comperr("adrcon");
+       printf( "$" );
+       printf( CONFMT, val );
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+       switch( p->n_op ){
+
+       case ICON:
+               acon( p );
+               return;
+
+       case REG:
+               printf( "%s", rnames[p->n_rval] );
+               return;
+
+       default:
+               cerror( "illegal conput" );
+               }
+       }
+
+void
+insput(register NODE *p)
+{
+       cerror( "insput" );
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+       size /= SZCHAR;
+       switch (p->n_op) {
+       case REG:
+               printf("%s", rnames[regno(p)-16+1]);
+               break;
+
+       case NAME:
+               if (kflag)
+                       comperr("upput NAME");
+       case OREG:
+               p->n_lval += size;
+               adrput(stdout, p);
+               p->n_lval -= size;
+               break;
+       case ICON:
+               printf("$" CONFMT, (p->n_lval >> 32) & 0xffffffff);
+               break;
+       default:
+               comperr("upput bad op %d size %d", p->n_op, size);
+       }
+}
+
+void
+adrput(FILE *fp, NODE *p)
+{
+       register int r;
+       /* output an address, with offsets, from p */
+
+       if( p->n_op == FLD ){
+               p = p->n_left;
+               }
+       switch( p->n_op ){
+
+       case NAME:
+               acon( p );
+               return;
+
+       case ICON:
+               /* addressable value of the constant */
+               if (p->n_name[0] == '\0') /* uses xxxab */
+                       printf("$");
+               if (ISLONGLONG(p->n_type))
+                       printf("0x%llx", p->n_lval);
+               else
+                       acon(p);
+               return;
+
+       case REG:
+               printf( "%s", rnames[p->n_rval] );
+               return;
+
+       case OREG:
+               r = p->n_rval;
+               if( R2TEST(r) ){ /* double indexing */
+                       register int flags;
+
+                       flags = R2UPK3(r);
+                       if( flags & 1 ) printf("*");
+                       if( flags & 4 ) printf("-");
+                       if( p->n_lval != 0 || p->n_name[0] != '\0' ) acon(p);
+                       if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
+                       if( flags & 2 ) printf("+");
+                       printf( "[%s]", rnames[R2UPK2(r)] );
+                       return;
+                       }
+               if( r == AP ){  /* in the argument region */
+                       if( p->n_lval <= 0 || p->n_name[0] != '\0' )
+                               werror( "bad arg temp" );
+                       printf( CONFMT, p->n_lval );
+                       printf( "(%%ap)" );
+                       return;
+                       }
+               if( p->n_lval != 0 || p->n_name[0] != '\0') acon( p );
+               printf( "(%s)", rnames[p->n_rval] );
+               return;
+
+       case UMUL:
+               /* STARNM or STARREG found */
+               if( tshape(p, STARNM) ) {
+                       printf( "*" );
+                       adrput(0,  p->n_left);
+                       }
+               else {  /* STARREG - really auto inc or dec */
+                       register NODE *q;
+
+/* tbl
+                       p = p->n_left;
+                       p->n_left->n_op = OREG;
+                       if( p->n_op == INCR ) {
+                               adrput( p->n_left );
+                               printf( "+" );
+                               }
+                       else {
+                               printf( "-" );
+                               adrput( p->n_left );
+                               }
+   tbl */
+#ifdef notyet
+                       printf("%c(%s)%c", (p->n_left->n_op==INCR ? '\0' : '-'),
+                               rnames[p->n_left->n_left->n_rval], 
+                               (p->n_left->n_op==INCR ? '+' : '\0') );
+#else
+                       printf("%c(%s)%c", '-',
+                               rnames[p->n_left->n_left->n_rval], 
+                               '\0' );
+#endif
+                       p->n_op = OREG;
+                       p->n_rval = p->n_left->n_left->n_rval;
+                       q = p->n_left;
+#ifdef notyet
+
+                       p->n_lval = (p->n_left->n_op == INCR ? -p->n_left->n_right->n_lval : 0);
+#else
+                       p->n_lval = 0;
+#endif
+                       p->n_name[0] = '\0';
+                       tfree(q);
+               }
+               return;
+
+       default:
+               cerror( "illegal address" );
+               return;
+       }
+
+}
+
+/*
+ * print out a constant
+ */
+void
+acon(NODE *p)
+{
+       int u = (int)p->n_lval;;
+       CONSZ v = u;
+
+       if (p->n_name[0] == '\0') {
+               printf(CONFMT, v);
+       } else if( p->n_lval == 0 ) {
+               printf("%s", p->n_name);
+       } else {
+               printf("%s+", p->n_name);
+               printf(CONFMT, v);
+       }
+}
+
+#if 0
+genscall( p, cookie ) register NODE *p; {
+       /* structure valued call */
+       return( gencall( p, cookie ) );
+       }
+
+/* tbl */
+int gc_numbytes;
+/* tbl */
+
+gencall( p, cookie ) register NODE *p; {
+       /* generate the call given by p */
+       register NODE *p1, *ptemp;
+       register temp, temp1;
+       register m;
+
+       if( p->right ) temp = argsize( p->right );
+       else temp = 0;
+
+       if( p->op == STCALL || p->op == UNARY STCALL ){
+               /* set aside room for structure return */
+
+               if( p->stsize > temp ) temp1 = p->stsize;
+               else temp1 = temp;
+               }
+
+       if( temp > maxargs ) maxargs = temp;
+       SETOFF(temp1,4);
+
+       if( p->right ){ /* make temp node, put offset in, and generate args */
+               ptemp = talloc();
+               ptemp->op = OREG;
+               ptemp->lval = -1;
+               ptemp->rval = SP;
+               ptemp->name[0] = '\0';
+               ptemp->rall = NOPREF;
+               ptemp->su = 0;
+               genargs( p->right, ptemp );
+               nfree(ptemp);
+               }
+
+       p1 = p->left;
+       if( p1->op != ICON ){
+               if( p1->op != REG ){
+                       if( p1->op != OREG || R2TEST(p1->rval) ){
+                               if( p1->op != NAME ){
+                                       order( p1, INAREG );
+                                       }
+                               }
+                       }
+               }
+
+/*
+       if( p1->op == REG && p->rval == R5 ){
+               cerror( "call register overwrite" );
+               }
+ */
+/* tbl
+       setup gc_numbytes so reference to ZC works */
+
+       gc_numbytes = temp;
+/* tbl */
+
+       p->op = UNARY CALL;
+       m = match( p, INTAREG|INTBREG );
+/* tbl
+       switch( temp ) {
+       case 0:
+               break;
+       case 2:
+               printf( "       tst     (%sp)+\n" );
+               break;
+       case 4:
+               printf( "       cmp     (%sp)+,(%sp)+\n" );
+               break;
+       default:
+               printf( "       add     $%d,%sp\n", temp);
+               }
+   tbl */
+       return(m != MDONE);
+       }
+#endif
+
+static char *
+ccbranches[] = {
+       "jeql",
+       "jneq",
+       "jleq",
+       "jlss",
+       "jgeq",
+       "jgtr",
+       "jlequ",
+       "jlssu",
+       "jgequ",
+       "jgtru",
+};
+
+/*
+ * printf conditional and unconditional branches
+ */
+void
+cbgen(int o, int lab)
+{
+
+       if (o == 0) {
+               printf("        jbr     " LABFMT "\n", lab);
+       } else {
+               if (o > UGT)
+                       comperr("bad conditional branch: %s", opst[o]);
+               printf("\t%s\t" LABFMT "\n", ccbranches[o-EQ], lab);
+       }
+}
+
+static void
+mkcall(NODE *p, char *name)
+{
+       p->n_op = CALL;
+       p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
+       p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
+       p->n_left->n_name = name;
+}
+
+/* do local tree transformations and optimizations */
+static void
+optim2(NODE *p, void *arg)
+{
+       NODE *r, *s;
+       TWORD lt;
+
+       switch (p->n_op) {
+       case DIV:
+       case MOD:
+               if (p->n_type == USHORT || p->n_type == UCHAR) {
+                       r = mkunode(SCONV, p->n_left, 0, UNSIGNED);
+                       r = mkunode(FUNARG, r, 0, UNSIGNED);
+                       s = mkunode(SCONV, p->n_right, 0, UNSIGNED);
+                       s = mkunode(FUNARG, s, 0, UNSIGNED);
+                       r = mkbinode(CM, r, s, INT);
+                       s = mklnode(ICON, 0, 0, FTN|UNSIGNED);
+                       s->n_name = p->n_op == MOD ? "__urem" : "__udiv";
+                       p->n_left = mkbinode(CALL, s, r, UNSIGNED);
+                       p->n_op = SCONV;
+               } else if (p->n_type == UNSIGNED) {
+                       p->n_left = mkunode(FUNARG, p->n_left, 0, UNSIGNED);
+                       p->n_right = mkunode(FUNARG, p->n_right, 0, UNSIGNED);
+                       p->n_right = mkbinode(CM, p->n_left, p->n_right, INT);
+                       p->n_left = mklnode(ICON, 0, 0, FTN|UNSIGNED);
+                       p->n_left->n_name = p->n_op == MOD ? "__urem" : "__udiv";
+                       p->n_op = CALL;
+               }
+               break;
+
+       case RS:
+               if (p->n_type == ULONGLONG) {
+                       p->n_right = mkbinode(CM, 
+                           mkunode(FUNARG, p->n_left, 0, p->n_left->n_type),
+                           mkunode(FUNARG, p->n_right, 0, p->n_right->n_type),
+                           INT);
+                       p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
+                       p->n_left->n_name = "__lshrdi3";
+                       p->n_op = CALL;
+               } else if (p->n_type == INT || p->n_type == LONGLONG) {
+                       /* convert >> to << with negative shift count */
+                       /* RS of char & short must use extv */
+                       if (p->n_right->n_op == ICON) {
+                               p->n_right->n_lval = -p->n_right->n_lval;
+                       } else if (p->n_right->n_op == UMINUS) {
+                               r = p->n_right->n_left;
+                               nfree(p->n_right);
+                               p->n_right = r;
+                       } else {
+                               p->n_right = mkunode(UMINUS, p->n_right,
+                                   0, p->n_right->n_type);
+                       }
+                       p->n_op = LS;
+               }
+               break;
+
+       case AND:
+               /* commute L and R to eliminate compliments and constants */
+               if ((p->n_left->n_op == ICON && p->n_left->n_name[0] == 0) ||
+                   p->n_left->n_op==COMPL) {
+                       r = p->n_left;
+                       p->n_left = p->n_right;
+                       p->n_right = r;
+               }
+               /* change meaning of AND to ~R&L - bic on pdp11 */
+               r = p->n_right;
+               if (r->n_op == ICON && r->n_name[0] == 0) {
+                       /* compliment constant */
+                       r->n_lval = ~r->n_lval;
+               } else if (r->n_op == COMPL) { /* ~~A => A */
+                       s = r->n_left;
+                       nfree(r);
+                       p->n_right = s;
+               } else { /* insert complement node */
+                       p->n_right = mkunode(COMPL, r, 0, r->n_type);
+               }
+               break;
+       case SCONV:
+               lt = p->n_left->n_type;
+               switch (p->n_type) {
+               case LONGLONG:
+                       if (lt == FLOAT)
+                               mkcall(p, "__fixsfdi");
+                       else if (lt == DOUBLE)
+                               mkcall(p, "__fixdfdi");
+                       break;
+               case ULONGLONG:
+                       if (lt == FLOAT)
+                               mkcall(p, "__fixunssfdi");
+                       else if (lt == DOUBLE)
+                               mkcall(p, "__fixunsdfdi");
+                       break;
+               case FLOAT:
+                       if (lt == LONGLONG)
+                               mkcall(p, "__floatdisf");
+                       else if (lt == ULONGLONG) {
+                               p->n_left = mkunode(SCONV, p->n_left,0, DOUBLE);
+                               p->n_type = FLOAT;
+                               mkcall(p->n_left, "__floatundidf");
+                       } else if (lt == UNSIGNED) {
+                               /* insert an extra double-to-float sconv */
+                               p->n_left = mkunode(SCONV, p->n_left,0, DOUBLE);
+                       }
+                       break;
+               case DOUBLE:
+                       if (lt == LONGLONG)
+                               mkcall(p, "__floatdidf");
+                       else if (lt == ULONGLONG)
+                               mkcall(p, "__floatundidf");
+                       break;
+                       
+               }
+               break;
+       }
+}
+
+static void
+aofname(NODE *p, void *arg)
+{
+       int o = optype(p->n_op);
+       TWORD t;
+
+       if (o == LTYPE || p->n_op == ADDROF)
+               return;
+       t = p->n_left->n_type;
+       if (p->n_left->n_op == NAME && ISLONGLONG(t))
+               p->n_left = mkunode(UMUL,
+                   mkunode(ADDROF, p->n_left, 0, INCREF(t)), 0, t);
+       if (o == BITYPE && p->n_right->n_op == NAME &&
+           ISLONGLONG(p->n_right->n_type)) {
+               t = p->n_right->n_type;
+               p->n_right = mkunode(UMUL,
+                   mkunode(ADDROF, p->n_right, 0, INCREF(t)), 0, t);
+       }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+       struct interpass *ip;
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               if (kflag)
+                       walkf(ip->ip_node, aofname, 0);
+               walkf(ip->ip_node, optim2, 0);
+       }
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+/*
+ * Return argument size in regs.
+ */
+static int
+argsiz(NODE *p)
+{
+       TWORD t = p->n_type;
+
+       if (t == STRTY || t == UNIONTY)
+               return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3)/4;
+       return szty(t);
+}
+
+/*
+ * Last chance to do something before calling a function.
+ */
+void
+lastcall(NODE *p)
+{
+       NODE *op = p;
+       int size = 0;
+
+       /* Calculate argument sizes */
+       p->n_qual = 0;
+       if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+               return;
+       for (p = p->n_right; p->n_op == CM; p = p->n_left)
+               size += argsiz(p->n_right);
+       if (p->n_op != ASSIGN)
+               size += argsiz(p);
+       op->n_qual = size; /* XXX */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+       return (szty(t) == 2 ? CLASSB : CLASSA);
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+       int num;
+       int a,b;
+
+       a = r[CLASSA];
+       b = r[CLASSB];
+       switch (c) {
+       case CLASSA:
+               /* there are 12 classa, so min 6 classb are needed to block */
+               num = b * 2;
+               num += a;
+               return num < 12;
+       case CLASSB:
+               if (b > 3) return 0;
+               if (b > 2 && a) return 0;
+               if (b > 1 && a > 2) return 0;
+               if (b && a > 3) return 0;
+               if (a > 5) return 0;
+               return 1;
+       }
+       comperr("COLORMAP");
+       return 0; /* XXX gcc */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+       return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+       char *c;
+       int i;
+
+       /* Discard o<> constraints since they will not be generated */
+       for (c = p->n_name; *c; c++) {
+               if (*c == 'o' || *c == '<' || *c == '>') {
+                       for (i = 0; c[i]; i++)
+                               c[i] = c[i+1];
+                       c--;
+               }
+       }
+       return 0;
+}
+
+int
+xasmconstregs(char *s)
+{
+       int i;
+
+       for (i = 0; i < 16; i++)
+               if (strcmp(&rnames[i][1], s) == 0)
+                       return i;
+       return -1;
+}
diff --git a/lang/pcc/pcc/arch/vax/macdefs.h b/lang/pcc/pcc/arch/vax/macdefs.h
new file mode 100644 (file)
index 0000000..70fe98c
--- /dev/null
@@ -0,0 +1,266 @@
+/*     $Id: macdefs.h,v 1.23 2016/03/05 15:53:04 ragge Exp $   */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);  
+
+# define  ARGINIT 32 
+# define  AUTOINIT 0 
+# define  SZCHAR 8
+# define  SZBOOL 8
+# define  SZINT 32
+# define  SZFLOAT 32
+# define  SZDOUBLE 64
+# define  SZLDOUBLE 64 /* XXX use longer? */
+# define  SZLONG 32
+# define  SZLONGLONG 64
+# define  SZSHORT 16
+# define SZPOINT(t) 32
+# define ALCHAR 8
+# define ALBOOL 8
+# define ALINT 32
+# define ALFLOAT 32
+# define ALDOUBLE 32
+# define ALLDOUBLE 32
+# define ALLONG 32
+# define ALLONGLONG 32
+# define ALSHORT 16
+# define ALPOINT 32
+# define ALSTRUCT 8
+# define  ALSTACK 32 
+#define MYVAARGSZ SZINT
+
+/*
+ * Min/max values.
+ */
+#define MIN_CHAR        -128
+#define MAX_CHAR        127
+#define MAX_UCHAR       255
+#define MIN_SHORT       -32768
+#define MAX_SHORT       32767
+#define MAX_USHORT      65535
+#define MIN_INT         (-0x7fffffff-1)
+#define MAX_INT         0x7fffffff
+#define MAX_UNSIGNED    0xffffffff
+#define MIN_LONG        MIN_INT
+#define MAX_LONG        MAX_INT
+#define MAX_ULONG       MAX_UNSIGNED
+#define MIN_LONGLONG    0x8000000000000000LL
+#define MAX_LONGLONG    0x7fffffffffffffffLL
+#define MAX_ULONGLONG   0xffffffffffffffffULL
+
+/* Default char is signed */
+#undef  CHAR_UNSIGNED
+#define BOOL_TYPE       CHAR    /* what used to store _Bool */
+#define        HASP2ALIGN
+/*     size in which constants are converted */
+/*     should be long if feasable */
+
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+
+# define CONFMT "%lld"
+# define LABFMT ".L%d"
+# define STABLBL ".LL%d"
+
+/*     size in which offsets are kept
+ *     should be large enough to cover address space in bits
+ */
+typedef long long OFFSZ;
+
+/* register cookie for stack poINTer */
+
+
+/* show stack grows negatively */
+#define BACKAUTO
+#define BACKTEMP
+
+/* show field hardware support on VAX */
+/* XXX notyet */
+#undef FIELDOPS
+
+/* bytes are numbered from right to left */
+#define TARGET_ENDIAN TARGET_LE
+#define        UNALIGNED_ACCESS
+
+/* we want prtree included */
+# define STDPRTREE
+
+/*     VAX-11/780 Registers */
+
+       /* scratch registers */
+# define R0 0
+# define R1 1
+# define R2 2
+# define R3 3
+# define R4 4
+# define R5 5
+
+       /* register variables */
+# define R6 6
+# define R7 7
+# define R8 8
+# define R9 9
+# define R10 10
+# define R11 11
+
+       /* special purpose */
+# define AP 12         /* argument pointer */
+# define FP 13         /* frame pointer */
+# define SP 14 /* stack pointer */
+# define PC 15 /* program counter */
+
+       /* floating registers */
+
+       /* there are no floating point registers on the VAX */
+       /* but there are concatenated regs */
+       /* we call them XR? */
+#define        XR0     16
+#define        XR1     17
+#define        XR2     18
+#define        XR3     19
+#define        XR4     20
+#define        XR5     21
+#define        XR6     22
+#define        XR7     23
+#define        XR8     24
+#define        XR9     25
+#define        XR10    26
+
+
+
+
+extern int fregs;
+extern int maxargs;
+
+# define BYTEOFF(x) ((x)&03)
+# define wdal(k) (BYTEOFF(k)==0)
+
+# define REGSZ 16
+
+# define TMPREG FP
+
+//# define R2REGS   /* permit double indexing */
+
+# define STOARG(p)     /* just evaluate the arguments, and be done with it... */
+# define STOFARG(p)
+# define STOSTARG(p)
+# define genfcall(a,b) gencall(a,b)
+
+# define NESTCALL
+
+/*
+ * Register allocator stuff.
+ * The register allocator sees this as 16 general regs (AREGs)
+ * and 11 64-bit concatenated regs. (BREGs)
+ */
+#define MAXREGS 033     /* 27 registers */
+
+#define RSTATUS \
+        SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+        SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG,    \
+        SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,    \
+       0, 0, 0, 0, /* do not care about ap, fp, sp or pc */            \
+       SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,         \
+       SBREG, SBREG, SBREG,
+
+#define ROVERLAP \
+       { XR0, -1 },                    \
+       { XR0, XR1, -1 },               \
+       { XR1, XR2, -1 },               \
+       { XR2, XR3, -1 },               \
+       { XR3, XR4, -1 },               \
+       { XR4, XR5, -1 },               \
+       { XR5, XR6, -1 },               \
+       { XR6, XR7, -1 },               \
+       { XR7, XR8, -1 },               \
+       { XR8, XR9, -1 },               \
+       { XR9, XR10, -1 },              \
+       { XR10, -1 },                   \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { -1 },                         \
+       { R0, R1, XR1, -1 },            \
+       { R1, R2, XR0, XR2, -1 },       \
+       { R2, R3, XR1, XR3, -1 },       \
+       { R3, R4, XR2, XR4, -1 },       \
+       { R4, R5, XR3, XR5, -1 },       \
+       { R5, R6, XR4, XR6, -1 },       \
+       { R6, R7, XR5, XR7, -1 },       \
+       { R7, R8, XR6, XR8, -1 },       \
+       { R8, R9, XR7, XR9, -1 },       \
+       { R9, R10, XR8, XR10, -1 },     \
+       { R10, R11, XR9, -1 },
+
+#define NUMCLASS        2       /* highest number of reg classes used */
+
+/* size, in registers, needed to hold thing of type t */
+#define        szty(t) (((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+#define FPREG  FP      /* frame pointer */
+#define STKREG SP
+#define ARGREG AP
+
+#define DECRA(x,y)      (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)       ((x) << 6)      /* A1 */
+#define ENCRA2(x)       ((x) << 12)     /* A2 */
+#define ENCRA(x,y)      ((x) << (6+y*6))        /* encode regs in int */
+
+#define PCLASS(p)      (szty(p->n_type) == 2 ? SBREG : SAREG)
+#define RETREG(x)      (szty(x) == 2 ? XR0 : R0)
+#define GCLASS(x)      (x < XR0 ? CLASSA : CLASSB)
+int xasmconstregs(char *s);
+#define XASMCONSTREGS(x) xasmconstregs(x)
+int COLORMAP(int c, int *r);
+
+#define        SNCON           (MAXSPECIAL+1)  /* named constand */
+
+#define TARGET_FLT_EVAL_METHOD 0       /* all as their type */
+/*
+ * Builtins.
+ */
+#ifdef LANG_CXX
+#define P1ND struct node
+#else
+#define P1ND struct p1node
+#endif
+struct p1node;
+struct bitable;
+
+#define        TARGET_FFS              /* target-specific ffs */
+P1ND *builtin_ffs(const struct bitable *, P1ND *a);
+P1ND *builtin_ffsl(const struct bitable *, P1ND *a);
+P1ND *builtin_ffsll(const struct bitable *, P1ND *a);
+#undef P1ND
diff --git a/lang/pcc/pcc/arch/vax/order.c b/lang/pcc/pcc/arch/vax/order.c
new file mode 100644 (file)
index 0000000..d3f5901
--- /dev/null
@@ -0,0 +1,667 @@
+/*     $Id: order.c,v 1.10 2014/10/12 13:16:32 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+
+int canaddr(NODE *);
+
+int maxargs = { -1 };
+
+#if 0
+stoasg( p, o ) register NODE *p; {
+       /* should the assignment op p be stored,
+          given that it lies as the right operand of o
+          (or the left, if o==UNARY MUL) */
+/*
+       if( p->op == INCR || p->op == DECR ) return;
+       if( o==UNARY MUL && p->left->op == REG && !isbreg(p->left->rval) ) SETSTO(p,INAREG);
+ */
+       }
+
+int
+deltest( p ) register NODE *p; {
+       /* should we delay the INCR or DECR operation p */
+       p = p->n_left;
+       return( p->n_op == REG || p->n_op == NAME || p->n_op == OREG );
+       }
+
+autoincr( p ) NODE *p; {
+       register NODE *q = p->left, *r;
+
+       if( q->op == INCR && (r=q->left)->op == REG &&
+           ISPTR(q->type) && p->type == DECREF(q->type) &&
+           tlen(p) == q->right->lval ) return(1);
+
+       return(0);
+       }
+
+mkadrs(p) register NODE *p; {
+       register o;
+
+       o = p->op;
+
+       if( asgop(o) ){
+               if( p->left->su >= p->right->su ){
+                       if( p->left->op == UNARY MUL ){
+                               SETSTO( p->left->left, INTEMP );
+                               }
+                       else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+                               SETSTO( p->left->left->left, INTEMP );
+                               }
+                       else { /* should be only structure assignment */
+                               SETSTO( p->left, INTEMP );
+                               }
+                       }
+               else SETSTO( p->right, INTEMP );
+               }
+       else {
+               if( p->left->su > p->right->su ){
+                       SETSTO( p->left, INTEMP );
+                       }
+               else {
+                       SETSTO( p->right, INTEMP );
+                       }
+               }
+       }
+#endif
+
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+       /* is it legal to make an OREG or NAME entry which has an
+        * offset of off, (from a register of r), if the
+        * resulting thing had type t */
+
+/*     if( r == R0 ) return( 1 );  / * NO */
+       return(0);  /* YES */
+       }
+
+# define max(x,y) ((x)<(y)?(y):(x))
+
+#if 0
+sucomp( p ) register NODE *p; {
+
+       /* set the su field in the node to the sethi-ullman
+          number, or local equivalent */
+
+       register o, ty, sul, sur, r;
+
+       o = p->op;
+       ty = optype( o );
+       p->su = szty( p->type );   /* 2 for float or double, else 1 */;
+
+       if( ty == LTYPE ){
+               if( o == OREG ){
+                       r = p->rval;
+                       /* oreg cost is (worst case) 1 + number of temp registers used */
+                       if( R2TEST(r) ){
+                               if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->su;
+                               if( istreg(R2UPK2(r)) ) ++p->su;
+                               }
+                       else {
+                               if( istreg( r ) ) ++p->su;
+                               }
+                       }
+               if( p->su == szty(p->type) &&
+                  (p->op!=REG || !istreg(p->rval)) &&
+                  (p->type==INT || p->type==UNSIGNED || p->type==DOUBLE) )
+                       p->su = 0;
+               return;
+               }
+
+       else if( ty == UTYPE ){
+               switch( o ) {
+               case UNARY CALL:
+               case UNARY STCALL:
+                       p->su = fregs;  /* all regs needed */
+                       return;
+
+               default:
+                       p->su =  p->left->su + (szty( p->type ) > 1 ? 2 : 0) ;
+                       return;
+                       }
+               }
+
+
+       /* If rhs needs n, lhs needs m, regular su computation */
+
+       sul = p->left->su;
+       sur = p->right->su;
+
+       if( o == ASSIGN ){
+               /* computed by doing right, then left (if not in mem), then doing it */
+               p->su = max(sur,sul+1);
+               return;
+               }
+
+       if( o == CALL || o == STCALL ){
+               /* in effect, takes all free registers */
+               p->su = fregs;
+               return;
+               }
+
+       if( o == STASG ){
+               /* right, then left */
+               p->su = max( max( 1+sul, sur), fregs );
+               return;
+               }
+
+       if( asgop(o) ){
+               /* computed by doing right, doing left address, doing left, op, and store */
+               p->su = max(sur,sul+2);
+/*
+               if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->su = max(p->su,fregs);
+ */
+               return;
+               }
+
+       switch( o ){
+       case ANDAND:
+       case OROR:
+       case QUEST:
+       case COLON:
+       case COMOP:
+               p->su = max( max(sul,sur), 1);
+               return;
+
+       case PLUS:
+       case OR:
+       case ER:
+               /* commutative ops; put harder on left */
+               if( p->right->su > p->left->su && !istnode(p->left) ){
+                       register NODE *temp;
+                       temp = p->left;
+                       p->left = p->right;
+                       p->right = temp;
+                       }
+               break;
+               }
+
+       /* binary op, computed by left, then right, then do op */
+       p->su = max(sul,szty(p->right->type)+sur);
+/*
+       if( o==MUL||o==DIV||o==MOD) p->su = max(p->su,fregs);
+ */
+
+       }
+
+int radebug = 0;
+
+rallo( p, down ) NODE *p; {
+       /* do register allocation */
+       register o, type, down1, down2, ty;
+
+       if( radebug ) printf( "rallo( %o, %d )\n", p, down );
+
+       down2 = NOPREF;
+       p->rall = down;
+       down1 = ( down &= ~MUSTDO );
+
+       ty = optype( o = p->op );
+       type = p->type;
+
+
+       if( type == DOUBLE || type == FLOAT ){
+               if( o == FORCE ) down1 = R0|MUSTDO;
+               }
+       else switch( o ) {
+       case ASSIGN:    
+               down1 = NOPREF;
+               down2 = down;
+               break;
+
+/*
+       case MUL:
+       case DIV:
+       case MOD:
+               down1 = R3|MUSTDO;
+               down2 = R5|MUSTDO;
+               break;
+
+       case ASG MUL:
+       case ASG DIV:
+       case ASG MOD:
+               p->left->rall = down1 = R3|MUSTDO;
+               if( p->left->op == UNARY MUL ){
+                       rallo( p->left->left, R4|MUSTDO );
+                       }
+               else if( p->left->op == FLD  && p->left->left->op == UNARY MUL ){
+                       rallo( p->left->left->left, R4|MUSTDO );
+                       }
+               else rallo( p->left, R3|MUSTDO );
+               rallo( p->right, R5|MUSTDO );
+               return;
+ */
+
+       case CALL:
+       case STASG:
+       case EQ:
+       case NE:
+       case GT:
+       case GE:
+       case LT:
+       case LE:
+       case NOT:
+       case ANDAND:
+       case OROR:
+               down1 = NOPREF;
+               break;
+
+       case FORCE:     
+               down1 = R0|MUSTDO;
+               break;
+
+               }
+
+       if( ty != LTYPE ) rallo( p->left, down1 );
+       if( ty == BITYPE ) rallo( p->right, down2 );
+
+       }
+#endif
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+
+       if (x2debug)
+               printf("offstar(%p)\n", p);
+
+       if (isreg(p))
+               return; /* Is already OREG */
+
+#if 0 /* notyet */
+       NODE *r;
+       r = p->n_right;
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( r->n_op == ICON ){
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       /* Converted in ormake() */
+                       return;
+               }
+               if (r->n_op == LS && r->n_right->n_op == ICON &&
+                   r->n_right->n_lval == 2 && p->n_op == PLUS) {
+                       if (isreg(p->n_left) == 0)
+                               (void)geninsn(p->n_left, INAREG);
+                       if (isreg(r->n_left) == 0)
+                               (void)geninsn(r->n_left, INAREG);
+                       return;
+               }
+       }
+#endif
+       (void)geninsn(p, INAREG);
+}
+
+
+#if 0
+void
+offstar( p, s ) register NODE *p; {
+       if( p->n_op == PLUS ) {
+               if( p->n_left->n_su == fregs ) {
+                       order( p->n_left, INAREG );
+                       return;
+               } else if( p->n_right->n_su == fregs ) {
+                       order( p->n_right, INAREG );
+                       return;
+               }
+               if( p->n_left->n_op==LS && 
+                 (p->n_left->n_left->n_op!=REG || tlen(p->n_left->n_left)!=sizeof(int) ) ) {
+                       order( p->n_left->n_left, INAREG );
+                       return;
+               }
+               if( p->n_right->n_op==LS &&
+                 (p->n_right->n_left->n_op!=REG || tlen(p->n_right->n_left)!=sizeof(int) ) ) {
+                       order( p->n_right->n_left, INAREG );
+                       return;
+               }
+               if( p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR) ) {
+                       if( p->n_left->n_op!=REG || tlen(p->n_left)!=sizeof(int) ) {
+                               order( p->n_left, INAREG );
+                               return;
+                       }
+                       else if( p->n_right->n_op!=REG || tlen(p->n_right)!=sizeof(int) ) {
+                               order(p->n_right, INAREG);
+                               return;
+                       }
+               }
+       }
+       if( p->n_op == PLUS || p->n_op == MINUS ){
+               if( p->n_right->n_op == ICON ){
+                       p = p->n_left;
+                       order( p , INAREG);
+                       return;
+                       }
+               }
+
+       if( p->n_op == UMUL && !canaddr(p) ) {
+               offstar( p->n_left, 0 );
+               return;
+       }
+
+       order( p, INAREG );
+       }
+#endif
+
+int
+setbin( p ) register NODE *p; {
+
+#if 0
+       register int ro, rt;
+
+       rt = p->n_right->n_type;
+       ro = p->n_right->n_op;
+
+       if( canaddr( p->n_left ) && !canaddr( p->n_right ) ) { /* address rhs */
+               if( ro == UMUL ) {
+                       offstar( p->n_right->n_left, 0 );
+                       return(1);
+               } else {
+                       order( p->n_right, INAREG|SOREG );
+                       return(1);
+               }
+       }
+       if( !istnode( p->n_left) ) { /* try putting LHS into a reg */
+/*             order( p->n_left, logop(p->n_op)?(INAREG|INBREG|INTAREG|INTBREG|SOREG):(INTAREG|INTBREG|SOREG) );*/
+               order( p->n_left, INAREG|INTAREG|INBREG|INTBREG|SOREG );
+               return(1);
+               }
+       else if( ro == UNARY MUL && rt != CHAR && rt != UCHAR ){
+               offstar( p->n_right->n_left );
+               return(1);
+               }
+       else if( rt == CHAR || rt == UCHAR || rt == SHORT || rt == USHORT || (ro != REG &&
+                       ro != NAME && ro != OREG && ro != ICON ) ){
+               order( p->n_right, INAREG|INBREG );
+               return(1);
+               }
+/*
+       else if( logop(p->n_op) && rt==USHORT ){  / * must get rhs into register */
+/*
+               order( p->n_right, INAREG );
+               return( 1 );
+               }
+ */
+#endif
+       return(0);
+       }
+
+#if 0
+int
+setstr( p ) register NODE *p; { /* structure assignment */
+       if( p->right->op != REG ){
+               order( p->right, INTAREG );
+               return(1);
+               }
+       p = p->left;
+       if( p->op != NAME && p->op != OREG ){
+               if( p->op != UNARY MUL ) cerror( "bad setstr" );
+               order( p->left, INTAREG );
+               return( 1 );
+               }
+       return( 0 );
+       }
+#endif
+
+int
+setasg( p, s ) register NODE *p; {
+
+#if 0
+       /* setup for assignment operator */
+
+       if( !canaddr(p->n_right) ) {
+               if( p->n_right->n_op == UNARY MUL )
+                       offstar(p->n_right->n_left);
+               else
+                       order( p->n_right, INAREG|INBREG|SOREG );
+               return(1);
+               }
+       if( p->n_left->n_op == UMUL ) {
+               offstar( p->n_left->n_left );
+               return(1);
+               }
+       if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+               offstar( p->left->left->left );
+               return(1);
+               }
+/* FLD patch */
+       if( p->left->op == FLD && !(p->right->type==INT || p->right->type==UNSIGNED)) {
+               order( p->right, INAREG);
+               return(1);
+               }
+/* end of FLD patch */
+#endif
+       return(0);
+       }
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+       return 0;
+}
+
+
+#if 0
+int
+setasop( p ) register NODE *p; {
+       /* setup for =ops */
+       register rt, ro;
+
+       rt = p->right->type;
+       ro = p->right->op;
+
+       if( ro == UNARY MUL && rt != CHAR ){
+               offstar( p->right->left );
+               return(1);
+               }
+       if( ( rt == CHAR || rt == SHORT || rt == UCHAR || rt == USHORT ||
+                       ( ro != REG && ro != ICON && ro != NAME && ro != OREG ) ) ){
+               order( p->right, INAREG|INBREG );
+               return(1);
+               }
+/*
+       if( (p->op == ASG LS || p->op == ASG RS) && ro != ICON && ro != REG ){
+               order( p->right, INAREG );
+               return(1);
+               }
+ */
+
+
+       p = p->left;
+       if( p->op == FLD ) p = p->left;
+
+       switch( p->op ){
+
+       case REG:
+       case ICON:
+       case NAME:
+       case OREG:
+               return(0);
+
+       case UNARY MUL:
+               if( p->left->op==OREG )
+                       return(0);
+               else
+                       offstar( p->left );
+               return(1);
+
+               }
+       cerror( "illegal setasop" );
+       }
+#endif
+
+void
+deflab(int l)
+{
+       printf(LABFMT ":\n", l);
+}
+
+#if 0
+genargs( p, ptemp ) register NODE *p, *ptemp; {
+       register NODE *pasg;
+       register align;
+       register size;
+       register TWORD type;
+
+       /* generate code for the arguments */
+
+       /*  first, do the arguments on the right */
+       while( p->op == CM ){
+               genargs( p->right, ptemp );
+               p->op = FREE;
+               p = p->left;
+               }
+
+       if( p->op == STARG ){ /* structure valued argument */
+
+               size = p->stsize;
+               align = p->stalign;
+
+ /*            ptemp->lval = (ptemp->lval/align)*align;  / * SETOFF for negative numbers */
+               ptemp->lval = 0;        /* all moves to (sp) */
+
+               p->op = STASG;
+               p->right = p->left;
+               p->left = tcopy( ptemp );
+
+               /* the following line is done only with the knowledge
+               that it will be undone by the STASG node, with the
+               offset (lval) field retained */
+
+               if( p->right->op == OREG ) p->right->op = REG;  /* only for temporaries */
+
+               order( p, FORARG );
+               ptemp->lval += size;
+               return;
+               }
+
+       /* ordinary case */
+
+       order( p, FORARG );
+       }
+
+argsize( p ) register NODE *p; {
+       register t;
+       t = 0;
+       if( p->op == CM ){
+               t = argsize( p->left );
+               p = p->right;
+               }
+       if( p->type == DOUBLE || p->type == FLOAT ){
+               SETOFF( t, 4 );
+               return( t+8 );
+               }
+       else if( p->op == STARG ){
+               SETOFF( t, 4 );  /* alignment */
+               return( t + ((p->stsize+3)/4)*4 );  /* size */
+               }
+       else {
+               SETOFF( t, 4 );
+               return( t+4 );
+               }
+       }
+#endif
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+       switch (q->op) {
+       case STARG:
+       case STASG:
+               {
+               static struct rspecial s[] = {
+                   { NEVER, R0, }, { NEVER, R1, }, { NEVER, R2, },
+                   { NEVER, R3, }, { NEVER, R4, }, { NEVER, R5 }, { 0 } };
+               return s;
+               }
+       case MOD:
+       case MUL:
+       case DIV:
+               {
+               static struct rspecial s[] = {
+                   { NEVER, R0, }, { NEVER, R1, }, { NEVER, R2, },
+                   { NEVER, R3, }, { NEVER, R4, }, { NEVER, R5 },
+                   { NRES, XR0 }, { 0 }, };
+               return s;
+               }
+       default:
+               comperr("nspecial");
+               return NULL;
+       }
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+       return 0; /* nothing differs on vax */
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+}
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+       static int r[1] = { -1 }; /* Terminate with -1 */
+
+       return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+       return 1;
+}
diff --git a/lang/pcc/pcc/arch/vax/table.c b/lang/pcc/pcc/arch/vax/table.c
new file mode 100644 (file)
index 0000000..0c1137c
--- /dev/null
@@ -0,0 +1,879 @@
+/*     $Id: table.c,v 1.28 2014/10/12 10:05:28 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+
+# define WPTR TPTRTO|TINT|TFLOAT|TDOUBLE|TPOINT|TUNSIGNED
+# define SAWM SNAME|SOREG|STARNM|STARREG
+# define AWD SAWM|SCON
+/* tbl */
+# define TANYSIGNED TINT|TSHORT|TCHAR
+# define TANYUSIGNED TPOINT|TUNSIGNED|TUSHORT|TUCHAR
+# define TANYFIXED TANYSIGNED|TANYUSIGNED
+# define TWORD TINT|TUNSIGNED|TPOINT
+/* tbl */
+# define TLL TLONGLONG|TULONGLONG
+# define TBREG TLONGLONG|TULONGLONG|TDOUBLE
+# define TAREG TANYFIXED|TFLOAT
+
+struct optab  table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,       INAREG,
+       SAREG,  TWORD,
+       SAREG,  TWORD,
+               0,      RLEFT,
+               "", },
+
+{ PCONV,       INAREG|INAREG,
+       SAREG|AWD,      TCHAR|TSHORT,
+       SANY,   TPOINT,
+               NAREG|NASL,     RESC1,
+               "       cvtZLl  AL,A1\n", },
+
+{ PCONV,       INAREG|INAREG,
+       SAREG|AWD,      TUCHAR|TUSHORT,
+       SANY,   TPOINT,
+               NAREG|NASL,     RESC1,
+               "       movzZLl AL,A1\n", },
+
+/* Handle conversions in C code */
+{ SCONV,       INAREG,
+       SAREG|AWD,      TAREG,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "ZG", },
+
+{ SCONV,       INAREG,
+       SBREG|AWD,      TBREG,
+       SANY,           TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "ZG", },
+
+{ SCONV,       INBREG,
+       SBREG|AWD,      TBREG,
+       SANY,           TANY,
+               NBREG|NBSL,     RESC1|RESCC,
+               "ZG", },
+
+{ SCONV,       INBREG,
+       SAREG|AWD,      TAREG,
+       SANY,           TANY,
+               NBREG|NBSL,     RESC1|RESCC,
+               "ZG", },
+
+{ GOTO,        FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       ZJ\n", },
+
+{ GOTO,        FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      RNOP,
+               "       jmp     (AL)\n", },
+
+{ STARG,       FOREFF,
+       SCON|SAREG,     TANY,
+       SANY,   TANY,
+               NSPECIAL,       RNOP,
+               "ZS", },
+
+{ ADDROF,      INAREG,
+       SNAME,  TANY,
+       SAREG,  TANY,
+               NAREG,  RESC1,
+               "       movab   AL,A1\n", },
+
+{ STASG,       FOREFF,
+       SNAME|SOREG,    TANY,
+       SCON|SAREG,     TANY,
+               NSPECIAL,       RNOP,
+               "ZS", },
+
+{ STASG,       INAREG,
+       SNAME|SOREG,    TANY,
+       SCON,   TANY,
+               NSPECIAL|NAREG, RDEST,
+               "ZS     movl    AR,A1\n", },
+
+{ STASG,       INAREG,
+       SNAME|SOREG,    TANY,
+       SAREG,  TANY,
+               NSPECIAL,       RDEST,
+               "       pushl   AR\nZS  movl    (%sp)+,AR\n", },
+
+{ FLD, INAREG|INAREG,
+       SANY,   TANY,
+       SFLD,   TANYSIGNED,
+               NAREG|NASR,     RESC1,
+               "       extv    H,S,AR,A1\n", },
+
+{ FLD, INAREG|INAREG,
+       SANY,   TANY,
+       SFLD,   TANYUSIGNED,
+               NAREG|NASR,     RESC1,
+               "       extzv   H,S,AR,A1\n", },
+
+#if 0
+{ FLD, FORARG,
+       SANY,   TANY,
+       SFLD,   ANYSIGNED,
+               0,      RNULL,
+               "       extv    H,S,AR,-(%sp)\n", },
+
+{ FLD, FORARG,
+       SANY,   TANY,
+       SFLD,   ANYUSIGNED,
+               0,      RNULL,
+               "       extzv   H,S,AR,-(%sp)\n", },
+#endif
+
+{ OPLOG,       FORCC,
+       SBREG|AWD,      TLONGLONG|TULONGLONG,
+       SBREG|AWD,      TLONGLONG|TULONGLONG,
+               0,      0,
+               "ZB", },
+
+{ OPLOG,       FORCC,
+       SAREG|AWD,      TWORD,
+       SAREG|AWD,      TWORD,
+               0,      RESCC,
+               "       cmpl    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|AWD,      TSHORT|TUSHORT,
+       SAREG|AWD,      TSHORT|TUSHORT,
+               0,      RESCC,
+               "       cmpw    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|AWD,      TCHAR|TUCHAR,
+       SAREG|AWD,      TCHAR|TUCHAR,
+               0,      RESCC,
+               "       cmpb    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|AWD,      TSHORT|TUSHORT,
+       SSCON,  TANY,
+               0,      RESCC,
+               "       cmpw    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|AWD,      TCHAR|TUCHAR,
+       SCCON,  TANY,
+               0,      RESCC,
+               "       cmpb    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SBREG|AWD,      TDOUBLE,
+       SBREG|AWD,      TDOUBLE,
+               0,      RESCC,
+               "       cmpd    AL,AR\n", },
+
+{ OPLOG,       FORCC,
+       SAREG|AWD,      TFLOAT,
+       SAREG|AWD,      TFLOAT,
+               0,      RESCC,
+               "       cmpf    AL,AR\n", },
+
+{ CCODES,      INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TANY,
+               NAREG,  RESC1,
+               "       movl    $1,A1\nZN", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,                FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       calls   ZC,CL\n", },
+
+{ UCALL,       FOREFF,
+       SCON,   TANY,
+       SANY,   TANY,
+               0,      0,
+               "       calls   $0,CL\n", },
+
+{ CALL,                INAREG,
+       SCON,   TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1, /* should be register 0 */
+               "       calls   ZC,CL # 1\n", },
+
+{ UCALL,       INAREG,
+       SCON,   TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1, /* should be register 0 */
+               "       calls   $0,CL\n", },
+
+{ CALL,                INBREG,
+       SCON,   TANY,
+       SANY,   TBREG,
+               NBREG|NBSL,     RESC1, /* should be register 0 */
+               "       calls   ZC,CL # 2\n", },
+
+{ UCALL,       INBREG,
+       SCON,   TANY,
+       SANY,   TBREG,
+               NBREG|NASL,     RESC1, /* should be register 0 */
+               "       calls   $0,CL\n", },
+
+{ CALL,                INBREG,
+       SAREG,  TANY,
+       SANY,   TBREG,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+{ UCALL,       INBREG,
+       SAREG,  TANY,
+       SANY,   TBREG,
+               NBREG|NBSL,     RESC1,  /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+{ CALL,                FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,      /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+{ CALL,                INAREG,
+       SAREG,  TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+{ UCALL,       FOREFF,
+       SAREG,  TANY,
+       SANY,   TANY,
+               0,      0,      /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+{ UCALL,       INAREG,
+       SAREG,  TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+#if 0
+{ UCALL,       FOREFF,
+       SNAME,  TANY,
+       SANY,   TANY,
+               0,      0,      /* really reg 0 */
+               "       calls   ZC,*AL\n", },
+
+{ UCALL,       INAREG,
+       SNAME,  TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1,  /* really reg 0 */
+               "       calls   ZC,*AL\n", },
+
+{ UCALL,       FOREFF,
+       SSOREG, TANY,
+       SANY,   TANY,
+               0,      0,      /* really reg 0 */
+               "       calls   ZC,*AL\n", },
+
+{ UCALL,       INAREG,
+       SSOREG, TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1,  /* really reg 0 */
+               "       calls   ZC,*AL\n", },
+#endif
+
+{ STCALL,      INAREG,
+       SCON,   TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1, /* should be register 0 */
+               "       calls   ZC,CL\n", },
+
+{ STCALL,      FOREFF,
+       SCON,   TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     0, /* should be register 0 */
+               "       calls   ZC,CL\n", },
+
+{ STCALL,      INAREG,
+       SAREG,  TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     RESC1,  /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+{ STCALL,      FOREFF,
+       SAREG,  TANY,
+       SANY,   TAREG,
+               NAREG|NASL,     0,      /* should be 0 */
+               "       calls   ZC,(AL)\n", },
+
+/*
+ * Function arguments
+ */
+{ FUNARG,      FOREFF,
+       SCON|SAREG|SNAME|SOREG, TANY,
+       SANY,   TWORD|TPOINT|TFLOAT,
+               0,      RNULL,
+               "       pushl   AL\n" },
+
+{ FUNARG,      FOREFF,
+       SCON|SBREG|SNAME|SOREG, TLL|TDOUBLE,
+       SANY,   TANY,
+               0,      RNULL,
+               "       movq    Zl,-(%sp)\n" },
+
+/* RS for signed <= int converted to negative LS */
+#if 0
+/* RS ulonglong converted to function call */
+/* RS longlong converted to negative LS */
+{ RS,  INBREG|FORCC,
+       SBREG|AWD,              TLONGLONG,
+       SAREG|SBREG|AWD,        TANY,
+               NBREG|NBSL|NBSR,        RESC1|RESCC,
+               "       ashq    AR,AL,A1\n", },
+#endif
+
+{ RS,  INAREG|FORCC,
+       SAREG,          TUCHAR,
+       SAREG|SAWM,     TANYFIXED,
+               NAREG,  RLEFT|RESCC,
+               "       subl3   AR,$8,A1\n      extzv   AR,A1,AL,AL\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,          TUSHORT,
+       SAREG|SAWM,     TANYFIXED,
+               NAREG,  RLEFT|RESCC,
+               "       subl3   AR,$16,A1\n     extzv   AR,A1,AL,AL\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,  TUNSIGNED,
+       SAREG|SAWM,     TANYFIXED,
+               NAREG,  RLEFT|RESCC,
+               "       subl3   AR,$32,A1\n     extzv   AR,A1,AL,AL\n", },
+
+{ RS,  INAREG|FORCC,
+       SAREG,  TUNSIGNED|TUSHORT|TUCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       extzv   AR,ZU,AL,A1\n", },
+
+/* extv only for short and char, rest uses ashl/q */
+{ RS,  INAREG|FORCC,
+       SAREG,  TSHORT|TCHAR,
+       SCON,   TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       extv    AR,ZU,AL,A1\n", },
+
+{ LS,  INBREG|FORCC,
+       SBREG|AWD,      TLL,
+       SAREG|SBREG|AWD,        TANY,
+               NBREG|NBSL|NBSR,        RESC1|RESCC,
+               "       ashq    AR,Zl,A1\n", },
+
+{ LS,  INAREG|INAREG|FORCC,
+       SAREG|AWD,      TANYFIXED,
+       SAREG|AWD,      TANYFIXED,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       ashl    AR,AL,A1\n", },
+
+#if 0
+{ INCR,        FOREFF,
+       SAREG|AWD,      TANY,
+       SANY,   TANY,
+               0,      RLEFT,
+               "       ZE\n", },
+
+{ DECR,        FOREFF,
+       SAREG|AWD,      TANY,
+       SCON,   TANY,
+               0,      RLEFT,
+               "       ZE\n", },
+
+{ INCR,        INAREG|INAREG,
+       SAREG|AWD,      TANY,
+       SCON,   TANY,
+               NAREG,  RESC1,
+               "       ZD\n", },
+
+{ DECR,        INAREG|INAREG,
+       SAREG|AWD,      TANY,
+       SCON,   TANY,
+               NAREG,  RESC1,
+               "       ZD\n", },
+#endif
+
+/* Assign to 64-bit register, three entries */
+/* Have FOREFF first to catch mem-mem moves */
+{ ASSIGN,      FOREFF,
+       SBREG|AWD,      TBREG,
+       SCON,           TBREG,
+               0,      0,
+               "ZA", },
+
+{ ASSIGN,      FOREFF,
+       SBREG|AWD,      TBREG,
+       SBREG|AWD,      TBREG,
+               0,      0,
+               "       movq    Zr,AL\n", },
+
+{ ASSIGN,      INBREG,
+       SBREG,  TBREG,
+       SBREG|AWD,      TBREG,
+               0,      RDEST,
+               "       movq    Zr,AL\n", },
+
+{ ASSIGN,      INBREG,
+       SBREG|AWD,      TBREG,
+       SBREG,  TBREG,
+               0,      RDEST,
+               "       movq    AR,AL\n", },
+
+/* Assign to 32-bit register, three entries */
+{ ASSIGN,      FOREFF|FORCC,
+       SAREG|AWD,      TAREG,
+       SCON,           TAREG,
+               0,      RESCC,
+               "ZA", },
+
+{ ASSIGN,      FOREFF|FORCC,
+       SAREG|AWD,      TAREG,
+       SAREG|AWD,      TAREG,
+               0,      RESCC,
+               "       movZL   AR,AL\n", },
+
+{ ASSIGN,      INAREG|FORCC,
+       SAREG,          TAREG,
+       SAREG|AWD,      TAREG,
+               0,      RDEST|RESCC,
+               "       movZL   AR,AL\n", },
+
+{ ASSIGN,      INAREG|FORCC,
+       SAREG|AWD,      TAREG,
+       SAREG,          TAREG,
+               0,      RDEST|RESCC,
+               "       movZL   AR,AL\n", },
+
+/* Bitfields, not yet */
+{ ASSIGN,      INAREG|FOREFF|FORCC,
+       SFLD,   TANY,
+       SAREG|AWD,      TWORD,
+               0,      RDEST|RESCC,
+               "       insv    AR,H,S,AL\n", },
+
+{ ASSIGN,      INAREG|FOREFF|FORCC,
+       SAREG|AWD,      TWORD,
+       SFLD,   TANYSIGNED,
+               0,      RDEST|RESCC,
+               "       extv    H,S,AR,AL\n", },
+
+{ ASSIGN,      INAREG|FOREFF|FORCC,
+       SAREG|AWD,      TWORD,
+       SFLD,   TANYUSIGNED,
+               0,      RDEST|RESCC,
+               "       extzv   H,S,AR,AL\n", },
+
+/* dummy UNARY MUL entry to get U* to possibly match OPLTYPE */
+{ UMUL,        FOREFF,
+       SCC,    TANY,
+       SCC,    TANY,
+               0,      RNULL,
+               "       HELP HELP HELP\n", },
+
+{ UMUL, INBREG,
+       SANY,   TPOINT,
+       SOREG,  TBREG,
+               NBREG|NBSL,     RESC1,
+               "       movq AL,A1\n", },
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TWORD,
+       SOREG,  TPOINT|TWORD,
+               NAREG|NASL,     RESC1,
+               "       movl AL,A1\n", },
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TSHORT|TUSHORT,
+       SOREG,  TPOINT|TSHORT|TUSHORT,
+               NAREG|NASL,     RESC1,
+               "       movw AL,A1\n", },
+
+{ UMUL, INAREG,
+       SANY,   TPOINT|TCHAR|TUCHAR,
+       SOREG,  TPOINT|TCHAR|TUCHAR,
+               NAREG|NASL,     RESC1,
+               "       movb AL,A1\n", },
+
+#if 0
+{ REG, FORARG,
+       SANY,   TANY,
+       SAREG,  TDOUBLE|TFLOAT,
+               0,      RNULL,
+               "       movZR   AR,-(%sp)\n", },
+
+{ REG, INTEMP,
+       SANY,   TANY,
+       SAREG,  TDOUBLE,
+               2*NTEMP,        RESC1,
+               "       movd    AR,A1\n", },
+
+{ REG, INTEMP,
+       SANY,   TANY,
+       SAREG,  TANY,
+               NTEMP,  RESC1,
+               "       movZF   AR,A1\n", },
+#endif
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SCON|SOREG|SNAME,       TLONGLONG|TULONGLONG,
+               NBREG,  RESC1,
+               "       movq Zl,A1\n", },
+
+{ OPLTYPE,     INBREG,
+       SANY,   TANY,
+       SANY,   TBREG,
+               NBREG|NBSR,     RESC1,
+               "       movZR AR,A1\n", },
+
+{ OPLTYPE,     INAREG|INAREG,
+       SANY,   TANY,
+       SANY,   TAREG,
+               NAREG|NASR,     RESC1,
+               "       movZR AR,A1\n", },
+
+{ OPLTYPE,     FORCC,
+       SANY,   TANY,
+       SANY,   TANY,
+               0,      RESCC,
+               "       tstZR   AR\n", },
+
+#if 0
+{ OPLTYPE,     FORARG,
+       SANY,   TANY,
+       SANY,   TWORD,
+               0,      RNULL,
+               "       pushl   AR\n", },
+
+{ OPLTYPE,     FORARG,
+       SANY,   TANY,
+       SANY,   TCHAR|TSHORT,
+               0,      RNULL,
+               "       cvtZRl  AR,-(%sp)\n", },
+
+{ OPLTYPE,     FORARG,
+       SANY,   TANY,
+       SANY,   TUCHAR|TUSHORT,
+               0,      RNULL,
+               "       movzZRl AR,-(%sp)\n", },
+
+{ OPLTYPE,     FORARG,
+       SANY,   TANY,
+       SANY,   TDOUBLE,
+               0,      RNULL,
+               "       movd    AR,-(%sp)\n", },
+
+{ OPLTYPE,     FORARG,
+       SANY,   TANY,
+       SANY,   TFLOAT,
+               0,      RNULL,
+               "       cvtfd   AR,-(%sp)\n", },
+#endif
+
+{ UMINUS,      INBREG,
+       SBREG|AWD,      TLL,
+       SANY,   TLL,
+               NBREG|NBSL,     RESC1|RESCC,
+               "       mnegl   UL,U1\n mnegl   AL,A1\n sbwc    $0,U1\n", },
+
+{ UMINUS,      INAREG|FORCC,
+       SAREG|AWD,      TAREG|TDOUBLE,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       mnegZL  AL,A1\n", },
+
+{ UMINUS,      INBREG|FORCC,
+       SBREG|AWD,      TDOUBLE,
+       SANY,   TANY,
+               NBREG|NASL,     RESC1|RESCC,
+               "       mnegZL  AL,A1\n", },
+
+{ COMPL,       INBREG,
+       SBREG|AWD,      TLL,
+       SANY,           TLL,
+               NBREG|NBSL,     RESC1|RESCC,
+               "       mcoml   AL,A1\n mcoml   UL,U1\n", },
+
+{ COMPL,       INAREG|FORCC,
+       SAREG|AWD,      TINT|TUNSIGNED,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       mcomZL  AL,A1\n", },
+
+{ COMPL,       INAREG|FORCC,
+       SAREG|AWD,      TANYSIGNED|TANYUSIGNED,
+       SANY,   TANY,
+               NAREG|NASL,     RESC1|RESCC,
+               "       cvtZLl  AL,A1\n mcoml   A1,A1\n", },
+
+{ AND, FORCC,
+       SAREG|AWD,      TWORD,
+       SCON,   TWORD,
+               0,      RESCC,
+               "       bitl    ZZ,AL\n", },
+
+{ AND, FORCC,
+       SAREG|AWD,      TSHORT|TUSHORT,
+       SSCON,  TWORD,
+               0,      RESCC,
+               "       bitw    ZZ,AL\n", },
+
+{ AND, FORCC,
+       SAREG|AWD,      TCHAR|TUCHAR,
+       SCCON,  TWORD,
+               0,      RESCC,
+               "       bitb    ZZ,AL\n", },
+
+{ MUL, INAREG|FORCC,
+       SAREG|AWD,              TANYFIXED,
+       SAREG|AWD,              TANYFIXED,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       mulZL3  AR,AL,A1\n", },
+
+{ OPMUL,       INAREG|INAREG|FORCC,
+       SAREG,  TINT|TUNSIGNED|TLONG|TULONG,
+       SAREG|AWD,      TINT|TUNSIGNED|TLONG|TULONG,
+               0,      RLEFT|RESCC,
+               "       OL2     AR,AL\n", },
+
+{ OPMUL,       INAREG|INAREG|FORCC,
+       SAREG|AWD,      TINT|TUNSIGNED|TLONG|TULONG,
+       SAREG|AWD,      TINT|TUNSIGNED|TLONG|TULONG,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       OL3     AR,AL,A1\n", },
+
+{ MOD, INAREG|INAREG,
+       SAREG|AWD,      TINT,
+       SAREG|AWD,      TINT,
+               NAREG,  RESC1,
+               "       divl3   AR,AL,A1\n      mull2   AR,A1\n subl3   A1,AL,A1\n", },
+
+{ PLUS,        INBREG|FORCC,
+       SBREG,          TLL,
+       SBREG|AWD,      TLL,
+               0,      RLEFT,
+               "       addl2   AR,AL\n"
+               "       adwc    UR,UL\n", },
+
+{ PLUS,                INAREG|FORCC,
+       SAREG,  TANYFIXED,
+       SONE,   TANY,
+               0,      RLEFT|RESCC,
+               "       incZL   AL\n", },
+
+{ MINUS,       INAREG|FORCC,
+       SAREG,  TANYFIXED,
+       SONE,   TANY,
+               0,      RLEFT|RESCC,
+               "       decZL   AL\n", },
+
+{ MINUS,       INBREG|FORCC,
+       SBREG,          TLL,
+       SBREG|AWD,      TLL,
+               0,      RLEFT,
+               "       subl2   AR,AL\n"
+               "       sbwc    UR,UL\n", },
+{ DIV, INBREG,
+       SBREG|AWD,      TLL,
+       SBREG|AWD,      TLL,
+               NSPECIAL|NBREG|NBSL|NBSR,       RESC1,
+               "ZO", },
+
+{ MOD, INBREG,
+       SBREG|AWD,      TLL,
+       SBREG|AWD,      TLL,
+               NSPECIAL|NBREG|NBSL|NBSR,       RESC1,
+               "ZO", },
+
+{ MUL, INBREG,
+       SBREG|AWD,      TLL,
+       SBREG|AWD,      TLL,
+               NSPECIAL|NBREG|NBSL|NBSR,       RESC1,
+               "ZO", },
+
+{ OR,  INBREG,
+       SBREG,          TLL,
+       SBREG|AWD,      TLL,
+               0,      RLEFT,
+               "       bisl2   AR,AL\n bisl2   UR,UL\n", },
+
+{ OR,  INBREG,
+       SBREG|AWD,      TLL,
+       SBREG|AWD,      TLL,
+               NBREG,  RESC1,
+               "       bisl3   AR,AL,A1\n      bisl3   UR,UL,U1\n", },
+
+{ ER,  INBREG,
+       SBREG,          TLL,
+       SBREG|AWD,      TLL,
+               0,      RLEFT,
+               "       xorl2   AR,AL\n xorl2   UR,UL\n", },
+
+{ ER,  INBREG,
+       SBREG|AWD,      TLL,
+       SBREG|AWD,      TLL,
+               NBREG,  RESC1,
+               "       xorl3   AR,AL,A1\n      xorl3   UR,UL,U1\n", },
+
+{ AND, INBREG,
+       SBREG,          TLL,
+       SBREG|AWD,      TLL,
+               0,      RLEFT,
+               "       bicl2   AR,AL\n bicl2   UR,UL\n", },
+
+{ AND, INBREG,
+       SBREG|AWD,      TLL,
+       SBREG|AWD,      TLL,
+               NBREG,  RESC1,
+               "       bicl3   AR,AL,A1\n      bicl3   UR,UL,U1\n", },
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,          TWORD,
+       SAREG|AWD,      TWORD,
+               0,      RLEFT|RESCC,
+               "       OL2     AR,AL\n", },
+
+{ OPSIMP,      INAREG|FORCC,
+       SAREG|AWD,      TWORD,
+       SAREG|AWD,      TWORD,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       OL3     AR,AL,A1\n", },
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,          TSHORT|TUSHORT,
+       SAREG|AWD,      TSHORT|TUSHORT,
+               0,      RLEFT|RESCC,
+               "       OW2     AR,AL\n", },
+
+{ OPSIMP,      INAREG|FORCC,
+       SAREG|AWD,      TSHORT|TUSHORT,
+       SAREG|AWD,      TSHORT|TUSHORT,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       OW3     AR,AL,A1\n", },
+
+{ OPSIMP,      INAREG|FOREFF|FORCC,
+       SAREG,          TCHAR|TUCHAR,
+       SAREG|AWD,      TCHAR|TUCHAR,
+               0,      RLEFT|RESCC,
+               "       OB2     AR,AL\n", },
+
+{ OPSIMP,      INAREG|FORCC,
+       SAREG|AWD,      TCHAR|TUCHAR,
+       SAREG|AWD,      TCHAR|TUCHAR,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       OB3     AR,AL,A1\n", },
+
+{ OPFLOAT,     INAREG|FORCC,
+       SAREG,          TFLOAT,
+       SAREG|AWD,      TFLOAT,
+               0,      RLEFT|RESCC,
+               "       OF2     AR,AL\n", },
+
+{ OPFLOAT,     INAREG|FORCC,
+       SAREG|AWD,      TFLOAT,
+       SAREG|AWD,      TFLOAT,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       OF3     AR,AL,A1\n", },
+
+{ OPFLOAT,     INBREG|FORCC,
+       SBREG,          TDOUBLE,
+       SBREG|AWD,      TDOUBLE,
+               0,      RLEFT|RESCC,
+               "       OD2     AR,AL\n", },
+
+{ OPFLOAT,     INBREG|FORCC,
+       SBREG|AWD,      TDOUBLE,
+       SBREG|AWD,      TDOUBLE,
+               NBREG|NBSL|NBSR,        RESC1|RESCC,
+               "       OD3     AR,AL,A1\n", },
+
+#if 0 /* XXX probably wrong */
+{ OPFLOAT,     INAREG|INAREG|FORCC,
+       SAREG|AWD,      TFLOAT,
+       SAREG|AWD,      TDOUBLE,
+               NAREG|NASL,     RESC1|RESCC,
+               "       cvtfd   AL,A1\n OD2     AR,A1\n", },
+
+{ OPFLOAT,     INAREG|INAREG|FORCC,
+       SAREG|AWD,      TDOUBLE,
+       SAREG|AWD,      TFLOAT,
+               NAREG|NASR,     RESC1|RESCC,
+               "       cvtfd   AR,A1\n OD3     A1,AL,A1\n", },
+
+{ OPFLOAT,     INAREG|INAREG|FORCC,
+       SAREG|AWD,      TFLOAT,
+       SAREG|AWD,      TFLOAT,
+               NAREG|NASL|NASR,        RESC1|RESCC,
+               "       OF3     AR,AL,A1\n      cvtfd   A1,A1\n", },
+#endif
+
+       /* Default actions for hard trees ... */
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ OPLEAF, DF(NAME), },
+
+{ OPLOG,       FORCC,
+       SANY,   TANY,
+       SANY,   TANY,
+               REWRITE,        BITYPE,
+               "", },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,        FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   FREE,   "help; I'm in trouble\n" }
+};
diff --git a/lang/pcc/pcc/cc/Makefile.in b/lang/pcc/pcc/cc/Makefile.in
new file mode 100644 (file)
index 0000000..710139b
--- /dev/null
@@ -0,0 +1,28 @@
+#      $Id: Makefile.in,v 1.9 2012/01/01 16:27:25 ragge Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+@SET_MAKE@
+
+ALL_SUBDIRS=   cc cpp ccom cxxcom
+DIST_SUBDIRS=  $(ALL_SUBDIRS) driver
+
+all install clean:
+       @for subdir in $(ALL_SUBDIRS); do \
+               _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \
+               echo "===> $$_nextdir_"; \
+               (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \
+                   exec $(MAKE) $(MFLAGS) $@) || exit $$?; \
+               echo "<=== $$_nextdir_"; \
+       done
+
+distclean:
+       @for subdir in $(DIST_SUBDIRS); do \
+               _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \
+               echo "===> $$_nextdir_"; \
+               (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \
+                   exec $(MAKE) $(MFLAGS) $@) || exit $$?; \
+               echo "<=== $$_nextdir_"; \
+       done
+       rm -f Makefile
diff --git a/lang/pcc/pcc/cc/cc/Makefile.in b/lang/pcc/pcc/cc/cc/Makefile.in
new file mode 100644 (file)
index 0000000..34266f8
--- /dev/null
@@ -0,0 +1,82 @@
+#      $Id: Makefile.in,v 1.37 2016/03/08 18:42:13 ragge Exp $
+#
+# Makefile.in for the cc part of pcc.
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+top_builddir=@top_builddir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+includedir = @includedir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+CC = @CC@
+EXEEXT = @EXEEXT@
+BINPREFIX = @BINPREFIX@
+TARGOS = @targos@
+TARGOSVER = @targosver@
+TARGMACH = @targmach@
+TARGET = @target@
+VERSION = @PACKAGE_VERSION@
+PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib
+PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"$(libexecdir)/\" \
+       @ADD_CPPFLAGS@ -DINCLUDEDIR=\"$(includedir)/\" \
+       -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \
+       -Dos_$(TARGOS) -Dmach_$(TARGMACH) -DTARGOSVER=$(TARGOSVER) \
+       -DCXXPROGNAME=\"$(BINPREFIX)p++$(EXEEXT)\" \
+       -DCPPROGNAME=\"$(BINPREFIX)pcpp$(EXEEXT)\" \
+       -I$(top_srcdir)/cc/driver -I$(top_builddir) \
+       -I$(top_srcdir)/os/$(TARGOS) -I$(MIPDIR) -I$(MDIR) -I$(COMMONDIR)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+MIPDIR=$(top_srcdir)/mip
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+COMMONDIR=$(top_srcdir)/common
+
+DEST=cc$(EXEEXT)
+DRIVERS=pcc pcpp p++
+
+all: $(DEST)
+
+OBJS=  cc.o compat.o strlist.o xalloc.o
+
+cc.o:  $(srcdir)/cc.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cc.c
+
+compat.o: $(COMMONDIR)/compat.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c
+
+strlist.o: $(top_srcdir)/cc/driver/strlist.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(top_srcdir)/cc/driver/strlist.c
+
+xalloc.o: $(top_srcdir)/cc/driver/xalloc.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(top_srcdir)/cc/driver/xalloc.c
+
+$(DEST): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+install:
+       test -z "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)"
+       test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1"
+       @for driver in $(DRIVERS); do \
+               $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(bindir)/$(BINPREFIX)$$driver$(EXEEXT); \
+               $(INSTALL_DATA) $(srcdir)/cc.1 $(DESTDIR)$(mandir)/man1/$$driver.1; \
+       done
+       test -z "$(DESTDIR)$(PCCINCDIR)" || mkdir -p "$(DESTDIR)$(PCCINCDIR)"
+       test -z "$(DESTDIR)$(PCCLIBDIR)" || mkdir -p "$(DESTDIR)$(PCCLIBDIR)"
+
+clean:
+       rm -f  $(OBJS) $(DEST)
+
+distclean: clean
+       rm -f  Makefile
diff --git a/lang/pcc/pcc/cc/cc/cc.1 b/lang/pcc/pcc/cc/cc/cc.1
new file mode 100644 (file)
index 0000000..1dd60b1
--- /dev/null
@@ -0,0 +1,395 @@
+.\"    $Id: cc.1,v 1.43 2014/12/24 09:55:32 plunky Exp $
+.\"
+.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
+.\"
+.\" Permission to use, copy, modify, and/or distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
+.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
+.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+.\" THIS SOFTWARE.
+.\"
+.Dd June 20, 2014
+.Dt CC 1
+.Os
+.Sh NAME
+.Nm cc
+.Nd front-end to the C compiler
+.Sh SYNOPSIS
+.Nm
+.Op Fl cEgkMPStvX
+.Op Fl B Ns Ar prefix
+.Op Fl D Ar macro Ns Oo = Ns Ar value Oc
+.Op Fl d Ns Ar flags
+.Op Fl f Ns Ar feature
+.Op Fl I Ar path
+.Op Fl include Ar file
+.Op Fl isystem Ar path
+.Op Fl L Ns Ar path
+.Op Fl m Ns Ar option
+.Op Fl nodefaultlibs
+.Op Fl nostartfiles
+.Op Fl nostdinc
+.Op Fl nostdlib
+.Op Fl O Ns Oo Ar level Oc
+.Op Fl o Ar outfile
+.Op Fl pg
+.Op Fl pthread
+.Op Fl shared
+.Op Fl static
+.Op Fl U Ar macro
+.Op Fl Wa Ns , Ns Ar options
+.Op Fl Wc Ns , Ns Ar options
+.Op Fl Wl Ns , Ns Ar options
+.Op Fl Wp Ns , Ns Ar options
+.Op Fl x Ar language
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a front-end to the
+.Dq portable C compiler .
+Multiple files may be given on the command line.
+Unrecognized options are all sent directly to
+.Xr ld 1 .
+.Pp
+.\" Brief description of its syntax:
+Filenames that end with
+.Sy \&.c
+are passed via
+.Xr cpp 1
+\(->
+.Xr ccom 1
+\(->
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.i
+are passed via
+.Xr ccom 1
+\(->
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.s
+are passed via
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.S
+are passed via
+.Xr cpp 1
+\(->
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.o
+are passed directly to
+.Xr ld 1 .
+.Pp
+.\"
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl B Ns Ar prefix
+Define alternate prefix path for
+.Xr cpp 1 ,
+.Xr ccom 1 ,
+.Xr as 1 ,
+or
+.Xr ld 1
+executables.
+.\" TODO: provide an example of -B
+.It Fl C
+Passed to the
+.Xr cpp 1
+preprocessor to not discard comments.
+.It Fl c
+Stop after generating object code with
+.Xr as 1 .
+Do not link.
+The resulting object output is saved
+as a filename with a
+.Dq \&.o
+suffix unless
+.Fl o
+option is used.
+Note: cannot be combined with
+.Fl o
+if multiple files are given.
+.It Fl D Ar macro Ns Oo = Ns Ar value Oc
+Passed to the
+.Xr cpp 1
+preprocessor to define
+.Ar macro
+with an optional
+.Ar value .
+.It Fl d Ns Ar flags
+Debug options.
+.Ar flags
+is a string of characters, which signify the following actions.
+.Bl -tag -width ".Sy M"
+.It Sy M
+Cause the preprocessor to output a list of macro definitions.
+.El
+.Lp
+any unknown flags are ignored.
+.It Fl E
+Stop after preprocessing with
+.Xr cpp 1 .
+Do not compile, assemble, or link.
+Output is sent to standard output unless the
+.Fl o
+option is used.
+.It Fl ffreestanding
+Assume a freestanding environment.
+.It Fl fPIC
+Generate PIC code.
+.\" TODO: document about avoiding machine-specific maximum size?
+.It Fl fpic
+Tells C compiler to generate PIC code
+and tells assembler that PIC code has been generated.
+.\" TODO: document difference between PIC and pic
+.It Fl funsigned-char
+Tell the compiler to treat
+.Sq char
+types as if they were unsigned unless explicitly defined otherwise.
+.Fl fsigned-char
+can be used to signify the opposite behaviour.
+The default for the
+.Sq char
+type depends on the compiler target architecture.
+.It Fl fstack-protector
+Tell the compiler to wrap functions with code which checks at
+runtime that a stack overflow has not occurred.
+When stack protection is in effect, the
+.Dv __SSP__
+macro will be defined.
+.\" other -f GCC compatibility flags are ignored for now
+.It Fl g
+Send
+.Fl g
+flag to
+.Xr ccom 1
+to create debug output.
+Debug information output can be disabled with
+.Fl g0 .
+.It Fl I Ar path
+Passed to the
+.Xr cpp 1
+preprocessor to add header search directory to override system defaults.
+.It Fl include Ar file
+Tells the
+.Xr cpp 1
+preprocessor to include the
+.Ar file
+during preprocessing.
+.It Fl isystem Ar path
+Defines
+.Ar path
+as a system header directory for the
+.Xr cpp 1
+preprocessor.
+.It Fl k
+Generate PIC code.
+See
+.Fl fpic
+option.
+.It Fl L Ns Ar path
+Passed to the linker, to add
+.Ar path
+to the list of directories searched for shared libraries.
+.It Fl M
+Pass
+.Fl M
+flag to
+.Xr cpp 1
+to generate dependencies for
+.Xr make 1 .
+.It Fl m Ns Ar option
+Target-dependent options.
+Multiple
+.Fl m
+options can be given, the following are supported:
+.Bl -tag -width PowerPC
+.It ARM
+\-mlittle-endian \-mbig-endian \-mfpe=fpa \-mfpe=vpf \-msoft-float \-march=armv1 \-march=armv2 \-march=armv2a \-march=armv3 \-march=armv4 \-march=armv4t \-march=armv4tej \-march=armv5 \-march=armv6 \-march=armv6t2 \-march=armv6kz \-march=armv6k \-march=armv7
+.It HPPA
+.It i386
+.It MIPS
+\-mlittle-endian \-mbig-endian \-mhard-float \-msoft-float
+.It PDP-10
+.It PowerPC
+.It Sparc64
+.It VAX
+.El
+.It Fl nodefaultlibs
+Do not link with the system default libraries (libc, etc.)
+.It Fl nostartfiles
+Do not link with the system startup files (crt0.c, etc.)
+.It Fl nostdinc
+Do not use the system include paths (/usr/include, etc.)
+.It Fl nostdlib
+Do not link with the system default libraries or startup files.
+.It Fl O Ns Oo Ar level Oc
+Enable compiler optimizations.
+Currently, for levels higher than zero,
+this defines
+.Dv __OPTIMIZE__
+in the
+.Xr cpp 1
+preprocessor, and passes
+.Fl xdce ,
+.Fl xdeljumps ,
+.Fl xtemps
+and
+.Fl xinline
+to
+.Xr ccom 1 .
+If no level is given the optimization level is increased, or
+optimizations can be disabled using
+.Fl O0 .
+.It Fl o Ar outfile
+Save result to
+.Ar outfile .
+.It Fl P
+Inhibit generation of line markers in preprocessor output.
+This is sometimes useful when running the preprocessor on something other than C code.
+.It Fl pg
+Enable profiling on the generated executable.
+.It Fl pthread
+Defines the
+.Dv _PTHREADS
+preprocessor identifier for
+.Xr cpp 1 , and
+adds
+.Fl lpthread
+to the
+.Xr ld 1
+linker arguments.
+.It Fl S
+Stop after compilation by
+.Xr ccom 1 .
+Do not assemble and do not link.
+The resulting assembler-language output is saved
+as a filename with a
+.Dq \&.s
+suffix unless the
+.Fl o
+option is used.
+Note: cannot be combined with
+.Fl o
+if multiple files are given.
+.It Fl shared
+Create a shared object of the result.
+Tells the linker not to generate an executable.
+.It Fl static
+Do not use dynamic linkage.
+By default, it will link using the dynamic linker options
+and/or shared objects for the platform.
+.It Fl t
+Passed to
+.Xr cpp 1
+to suppress some default macro definitions and enable use
+of traditional C preprocessor syntax.
+.It Fl U Ar macro
+Passes to the
+.Xr cpp 1
+preprocessor to remove the initial macro definition.
+.It Fl v
+Outputs the version of
+.Nm
+and shows commands as they are run with their command line arguments.
+.It Fl ###
+As per
+.Fl v
+except that the commands are not run, and the arguments will be quoted
+if they contain unusual characters or spaces.
+.It Fl Wa Ns , Ns Ar options
+Comma separated list of options for the assembler.
+.It Fl Wc Ns , Ns Ar options
+Comma separated list of options for the compiler.
+.It Fl Wl Ns , Ns Ar options
+Comma separated list of options for the linker.
+.It Fl Wp Ns , Ns Ar options
+Comma separated list of options for the preprocessor.
+.It Fl X
+Don't remove temporary files on exit.
+.It Fl x Ar language
+GCC compatibility option; specify the language in use rather than
+interpreting the filename extension.
+Currently known language values are
+.Sy none ,
+.Sy c ,
+.Sy c++ ,
+.Sy assembler
+and
+.Sy assembler-with-cpp .
+Any unknown
+.Fl x
+options are passed to
+.Xr ccom 1 .
+.El
+.Ss Predefined Macros
+A few
+macros are predefined by
+.Nm
+when sent to
+.Xr cpp 1 .
+.Bl -diag
+.It __PCC__
+Set to the major version of
+.Xr pcc 1 .
+These macros can be used to select code based on
+.Xr pcc 1
+compatibility.
+See the
+.Fl v
+option.
+.It __PCC_MINOR__
+Set to the minor version.
+.It __PCC_MINORMINOR__
+Set to the minor-minor version \(em the number after the minor version.
+.It _PTHREADS
+Defined when
+.Fl pthread
+switch is used.
+.It __ASSEMBLER__
+Defined when input files have a .S suffix, or if the
+.Fl x Ns assembler-with-cpp
+option is specified.
+.El
+.Pp
+Also system- and/or machine-dependent macros may also be predefined;
+for example:
+.Dv __NetBSD__ ,
+.Dv __ELF__ ,
+and
+.Dv __i386__ .
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr ccom 1 ,
+.Xr cpp 1 ,
+.Xr ld 1
+.Sh HISTORY
+The
+.Nm
+command comes from the original Portable C Compiler by
+.An "S. C. Johnson" ,
+written in the late 70's.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
diff --git a/lang/pcc/pcc/cc/cc/cc.c b/lang/pcc/pcc/cc/cc/cc.c
new file mode 100644 (file)
index 0000000..da01b68
--- /dev/null
@@ -0,0 +1,2132 @@
+/*     $Id: cc.c,v 1.305 2016/02/23 11:14:08 ragge Exp $       */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Front-end to the C compiler.
+ *
+ * Brief description of its syntax:
+ * - Files that end with .c are passed via cpp->ccom->as->ld
+ * - Files that end with .i are passed via ccom->as->ld
+ * - Files that end with .S are passed via cpp->as->ld
+ * - Files that end with .s are passed via as->ld
+ * - Files that end with .o are passed directly to ld
+ * - Multiple files may be given on the command line.
+ * - Unrecognized options are all sent directly to ld.
+ * -c or -S cannot be combined with -o if multiple files are given.
+ *
+ * This file should be rewritten readable.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <assert.h>
+#include <time.h>
+
+#ifdef  _WIN32
+#include <windows.h>
+#include <process.h>
+#include <io.h>
+#define F_OK   0x00
+#define R_OK   0x04
+#define W_OK   0x02
+#define X_OK   R_OK
+#endif
+
+#include "compat.h"
+
+#include "macdefs.h"
+
+#include "xalloc.h"
+#include "strlist.h"
+
+#include "ccconfig.h"
+/* C command */
+
+#define        MKS(x) _MKS(x)
+#define _MKS(x) #x
+
+/* default program names in pcc */
+/* May be overridden if cross-compiler is generated */
+#ifndef        CXXPROGNAME             /* name as C++ front end */
+#define        CXXPROGNAME     "c++"
+#endif
+#ifndef CPPROGNAME
+#define        CPPROGNAME      "cpp"   /* name as CPP front end */
+#endif
+#ifndef PREPROCESSOR
+#define        PREPROCESSOR    "cpp"   /* "real" preprocessor name */
+#endif
+#ifndef COMPILER
+#define COMPILER       "ccom"
+#endif
+#ifndef CXXCOMPILER
+#define CXXCOMPILER    "cxxcom"
+#endif
+#ifndef ASSEMBLER
+#define ASSEMBLER      "as"
+#endif
+#ifndef LINKER
+#define LINKER         "ld"
+#endif
+char   *passp = PREPROCESSOR;
+char   *pass0 = COMPILER;
+char   *passxx0 = CXXCOMPILER;
+char   *as = ASSEMBLER;
+char   *ld = LINKER;
+char   *sysroot = "", *isysroot;
+
+
+/* crt files using pcc default names */
+#ifndef CRTBEGIN_S
+#define        CRTBEGIN_S      "crtbeginS.o"
+#endif
+#ifndef CRTEND_S
+#define        CRTEND_S        "crtendS.o"
+#endif
+#ifndef CRTBEGIN_T
+#define        CRTBEGIN_T      "crtbeginT.o"
+#endif
+#ifndef CRTEND_T
+#define        CRTEND_T        "crtendT.o"
+#endif
+#ifndef CRTBEGIN
+#define        CRTBEGIN        "crtbegin.o"
+#endif
+#ifndef CRTEND
+#define        CRTEND          "crtend.o"
+#endif
+#ifndef CRTI
+#define        CRTI            "crti.o"
+#endif
+#ifndef CRTN
+#define        CRTN            "crtn.o"
+#endif
+#ifndef CRT0
+#define        CRT0            "crt0.o"
+#endif
+#ifndef GCRT0
+#define        GCRT0           "gcrt0.o"
+#endif
+
+/* preprocessor stuff */
+#ifndef STDINC
+#define        STDINC          "/usr/include/"
+#endif
+#ifdef MULTIARCH_PATH
+#define STDINC_MA      STDINC MULTIARCH_PATH "/"
+#endif
+
+
+char *cppadd[] = CPPADD;
+char *cppmdadd[] = CPPMDADD;
+
+/* Default libraries and search paths */
+#ifndef PCCLIBDIR      /* set by autoconf */
+#define PCCLIBDIR      NULL
+#endif
+#ifndef LIBDIR
+#define LIBDIR         "/usr/lib/"
+#endif
+#ifndef DEFLIBDIRS     /* default library search paths */
+#ifdef MULTIARCH_PATH
+#define DEFLIBDIRS     { LIBDIR, LIBDIR MULTIARCH_PATH "/", 0 }
+#else
+#define DEFLIBDIRS     { LIBDIR, 0 }
+#endif
+#endif
+#ifndef DEFLIBS                /* default libraries included */
+#define        DEFLIBS         { "-lpcc", "-lc", "-lpcc", 0 }
+#endif
+#ifndef DEFPROFLIBS    /* default profiling libraries */
+#define        DEFPROFLIBS     { "-lpcc", "-lc_p", "-lpcc", 0 }
+#endif
+#ifndef DEFCXXLIBS     /* default c++ libraries */
+#define        DEFCXXLIBS      { "-lp++", "-lpcc", "-lc", "-lpcc", 0 }
+#endif
+#ifndef STARTLABEL
+#define STARTLABEL "__start"
+#endif
+#ifndef DYNLINKARG
+#define DYNLINKARG     "-dynamic-linker"
+#endif
+#ifndef DYNLINKLIB
+#define DYNLINKLIB     NULL
+#endif
+
+char *dynlinkarg = DYNLINKARG;
+char *dynlinklib = DYNLINKLIB;
+char *pcclibdir = PCCLIBDIR;
+char *deflibdirs[] = DEFLIBDIRS;
+char *deflibs[] = DEFLIBS;
+char *defproflibs[] = DEFPROFLIBS;
+char *defcxxlibs[] = DEFCXXLIBS;
+
+char   *outfile, *MFfile, *fname;
+static char **lav;
+static int lac;
+static char *find_file(const char *file, struct strlist *path, int mode);
+static int preprocess_input(char *input, char *output, int dodep);
+static int compile_input(char *input, char *output);
+static int assemble_input(char *input, char *output);
+static int run_linker(void);
+static int strlist_exec(struct strlist *l);
+
+char *cat(const char *, const char *);
+char *setsuf(char *, char);
+int cxxsuf(char *);
+int getsuf(char *);
+char *getsufp(char *s);
+int main(int, char *[]);
+void errorx(int, char *, ...);
+int cunlink(char *);
+void exandrm(char *);
+void dexit(int);
+void idexit(int);
+char *gettmp(void);
+void oerror(char *);
+char *argnxt(char *, char *);
+char *nxtopt(char *o);
+void setup_cpp_flags(void);
+void setup_ccom_flags(void);
+void setup_as_flags(void);
+void setup_ld_flags(void);
+static void expand_sysroot(void);
+#ifdef  _WIN32
+char *win32pathsubst(char *);
+char *win32commandline(struct strlist *l);
+#endif
+int    sspflag;
+int    freestanding;
+int    Sflag;
+int    cflag;
+int    gflag;
+int    rflag;
+int    vflag;
+int    noexec; /* -### */
+int    tflag;
+int    Eflag;
+int    Oflag;
+int    kflag;  /* generate PIC/pic code */
+#define F_PIC  1
+#define F_pic  2
+int    Mflag, needM, MDflag, MMDflag;  /* dependencies only */
+int    pgflag;
+int    Xflag;
+int    nostartfiles, Bstatic, shared;
+int    nostdinc, nostdlib;
+int    pthreads;
+int    xgnu89, xgnu99, c89defs, c99defs, c11defs;
+int    ascpp;
+#ifdef CHAR_UNSIGNED
+int    xuchar = 1;
+#else
+int    xuchar = 0;
+#endif
+int    cxxflag;
+int    cppflag;
+int    printprogname, printfilename;
+enum { SC11, STRAD, SC89, SGNU89, SC99, SGNU99 } cstd;
+
+#ifdef SOFTFLOAT
+int    softfloat = 1;
+#else
+int    softfloat = 0;
+#endif
+
+#ifdef TARGET_BIG_ENDIAN
+int    bigendian = 1;
+#else
+int    bigendian = 0;
+#endif
+
+#ifdef mach_amd64
+int amd64_i386;
+#endif
+
+#define        match(a,b)      (strcmp(a,b) == 0)
+
+/* handle gcc warning emulations */
+struct Wflags {
+       char *name;
+       int flags;
+#define        INWALL          1
+} Wflags[] = {
+       { "truncate", 0 },
+       { "strict-prototypes", 0 },
+       { "missing-prototypes", 0 },
+       { "implicit-int", INWALL },
+       { "implicit-function-declaration", INWALL },
+       { "shadow", 0 },
+       { "pointer-sign", INWALL },
+       { "sign-compare", 0 },
+       { "unknown-pragmas", INWALL },
+       { "unreachable-code", 0 },
+       { "deprecated-declarations", 0 },
+       { "attributes", 0 },
+       { NULL, 0 },
+};
+
+#ifndef USHORT
+/* copied from mip/manifest.h */
+#define        USHORT          5
+#define        INT             6
+#define        UNSIGNED        7
+#endif
+
+/*
+ * Wide char defines.
+ */
+#if WCHAR_TYPE == USHORT
+#define        WCT "short unsigned int"
+#define WCM "65535U"
+#if WCHAR_SIZE != 2
+#error WCHAR_TYPE vs. WCHAR_SIZE mismatch
+#endif
+#elif WCHAR_TYPE == INT
+#define WCT "int"
+#define WCM "2147483647"
+#if WCHAR_SIZE != 4
+#error WCHAR_TYPE vs. WCHAR_SIZE mismatch
+#endif
+#elif WCHAR_TYPE == UNSIGNED
+#define WCT "unsigned int"
+#define WCM "4294967295U"
+#if WCHAR_SIZE != 4
+#error WCHAR_TYPE vs. WCHAR_SIZE mismatch
+#endif
+#else
+#error WCHAR_TYPE not defined or invalid
+#endif
+
+#ifdef GCC_COMPAT
+#ifndef REGISTER_PREFIX
+#define REGISTER_PREFIX ""
+#endif
+#ifndef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+#endif
+#endif
+
+#ifndef PCC_WINT_TYPE
+#define PCC_WINT_TYPE "unsigned int"
+#endif
+
+#ifndef PCC_SIZE_TYPE
+#define PCC_SIZE_TYPE "unsigned long"
+#endif
+
+#ifndef PCC_PTRDIFF_TYPE
+#define PCC_PTRDIFF_TYPE "long int"
+#endif
+
+
+struct strlist preprocessor_flags;
+struct strlist depflags;
+struct strlist incdirs;
+struct strlist user_sysincdirs;
+struct strlist includes;
+struct strlist sysincdirs;
+struct strlist dirafterdirs;
+struct strlist crtdirs;
+struct strlist libdirs;
+struct strlist progdirs;
+struct strlist early_linker_flags;
+struct strlist middle_linker_flags;
+struct strlist late_linker_flags;
+struct strlist inputs;
+struct strlist assembler_flags;
+struct strlist temp_outputs;
+struct strlist compiler_flags;
+
+int
+main(int argc, char *argv[])
+{
+       struct Wflags *Wf;
+       struct string *s;
+       char *t, *u, *argp;
+       char *msuffix;
+       int ninput, j;
+
+       lav = argv;
+       lac = argc;
+       ninput = 0;
+
+       strlist_init(&crtdirs);
+       strlist_init(&libdirs);
+       strlist_init(&progdirs);
+       strlist_init(&preprocessor_flags);
+       strlist_init(&incdirs);
+       strlist_init(&user_sysincdirs);
+       strlist_init(&includes);
+       strlist_init(&sysincdirs);
+       strlist_init(&dirafterdirs);
+       strlist_init(&depflags);
+       strlist_init(&early_linker_flags);
+       strlist_init(&middle_linker_flags);
+       strlist_init(&late_linker_flags);
+       strlist_init(&inputs);
+       strlist_init(&assembler_flags);
+       strlist_init(&temp_outputs);
+       strlist_init(&compiler_flags);
+
+       if ((t = strrchr(argv[0], '/')))
+               t++;
+       else
+               t = argv[0];
+
+       if (match(t, CXXPROGNAME)) {
+               cxxflag = 1;
+       } else if (match(t, CPPROGNAME)) {
+               Eflag = cppflag = 1;
+       }
+
+#ifdef PCC_EARLY_SETUP
+       PCC_EARLY_SETUP
+#endif
+
+#ifdef _WIN32
+       /* have to prefix path early.  -B may override */
+       incdir = win32pathsubst(incdir);
+       altincdir = win32pathsubst(altincdir);
+       libdir = win32pathsubst(libdir);
+#ifdef PCCINCDIR
+       pccincdir = win32pathsubst(pccincdir);
+       pxxincdir = win32pathsubst(pxxincdir);
+#endif
+#ifdef PCCLIBDIR
+       pcclibdir = win32pathsubst(pcclibdir);
+#endif
+       passp = win32pathsubst(passp);
+       pass0 = win32pathsubst(pass0);
+#ifdef STARTFILES
+       for (i = 0; startfiles[i] != NULL; i++)
+               startfiles[i] = win32pathsubst(startfiles[i]);
+       for (i = 0; endfiles[i] != NULL; i++)
+               endfiles[i] = win32pathsubst(endfiles[i]);
+#endif
+#ifdef STARTFILES_T
+       for (i = 0; startfiles_T[i] != NULL; i++)
+               startfiles_T[i] = win32pathsubst(startfiles_T[i]);
+       for (i = 0; endfiles_T[i] != NULL; i++)
+               endfiles_T[i] = win32pathsubst(endfiles_T[i]);
+#endif
+#ifdef STARTFILES_S
+       for (i = 0; startfiles_S[i] != NULL; i++)
+               startfiles_S[i] = win32pathsubst(startfiles_S[i]);
+       for (i = 0; endfiles_S[i] != NULL; i++)
+               endfiles_S[i] = win32pathsubst(endfiles_S[i]);
+#endif
+#endif
+
+       while (--lac) {
+               ++lav;
+               argp = *lav;
+
+#ifdef PCC_EARLY_ARG_CHECK
+               PCC_EARLY_ARG_CHECK
+#endif
+
+               if (*argp != '-' || match(argp, "-")) {
+                       /* Check for duplicate .o files. */
+                       if (getsuf(argp) == 'o') {
+                               j = 0;
+                               STRLIST_FOREACH(s, &inputs)
+                                       if (match(argp, s->value))
+                                               j++;
+                               if (j)
+                                       continue; /* skip it */
+                       }
+                       strlist_append(&inputs, argp);
+                       ninput++;
+                       continue;
+               }
+
+               switch (argp[1]) {
+               default:
+                       oerror(argp);
+                       break;
+
+               case '#':
+                       if (match(argp, "-###")) {
+                               printf("%s\n", VERSSTR);
+                               vflag++;
+                               noexec++;
+                       } else
+                               oerror(argp);
+                       break;
+
+               case '-': /* double -'s */
+                       if (match(argp, "--version")) {
+                               printf("%s\n", VERSSTR);
+                               return 0;
+                       } else if (strncmp(argp, "--sysroot=", 10) == 0) {
+                               sysroot = argp + 10;
+                       } else if (strncmp(argp, "--sysroot", 9) == 0) {
+                               sysroot = nxtopt(argp);
+                       } else if (strcmp(argp, "--param") == 0) {
+                               /* NOTHING YET */;
+                               (void)nxtopt(0); /* ignore arg */
+                       } else
+                               oerror(argp);
+                       break;
+
+               case 'B': /* other search paths for binaries */
+                       t = nxtopt("-B");
+                       strlist_append(&crtdirs, t);
+                       strlist_append(&libdirs, t);
+                       strlist_append(&progdirs, t);
+                       break;
+
+               case 'C':
+                       if (match(argp, "-C") || match(argp, "-CC"))
+                               strlist_append(&preprocessor_flags, argp);
+                       else
+                               oerror(argp);
+                       break;
+
+               case 'c':
+                       cflag++;
+                       break;
+
+               case 'd': /* debug options */
+                       for (t = &argp[2]; *t; t++) {
+                               if (*t == 'M')
+                                       strlist_append(&preprocessor_flags, "-dM");
+
+                               /* ignore others */
+                       }
+                       break;
+
+               case 'E':
+                       Eflag++;
+                       break;
+
+               case 'f': /* GCC compatibility flags */
+                       u = &argp[2];
+                       j = 0;
+                       if (strncmp(u, "no-", 3) == 0)
+                               j = 1, u += 3;
+                       if (match(u, "PIC") || match(u, "pic")) {
+                               kflag = j ? 0 : *u == 'P' ? F_PIC : F_pic;
+                       } else if (match(u, "freestanding")) {
+                               freestanding = j ? 0 : 1;
+                       } else if (match(u, "signed-char")) {
+                               xuchar = j ? 1 : 0;
+                       } else if (match(u, "unsigned-char")) {
+                               xuchar = j ? 0 : 1;
+                       } else if (match(u, "stack-protector") ||
+                           match(u, "stack-protector-all")) {
+                               sspflag = j ? 0 : 1;
+                       }
+                       /* silently ignore the rest */
+                       break;
+
+               case 'g': /* create debug output */
+                       if (argp[2] == '0')
+                               gflag = 0;
+                       else
+                               gflag++;
+                       break;
+
+
+               case 'X':
+                       Xflag++;
+                       break;
+
+               case 'D':
+               case 'U':
+                       strlist_append(&preprocessor_flags, argp);
+                       if (argp[2] != 0)
+                               break;
+                       strlist_append(&preprocessor_flags, nxtopt(argp));
+                       break;
+
+               case 'I': /* Add include dirs */
+                       strlist_append(&incdirs, nxtopt("-I"));
+                       break;
+
+               case 'i':
+                       if (match(argp, "-isystem")) {
+                               strlist_append(&user_sysincdirs, nxtopt(0));
+                       } else if (match(argp, "-include")) {
+                               strlist_append(&includes, nxtopt(0));
+                       } else if (match(argp, "-isysroot")) {
+                               isysroot = nxtopt(0);
+                       } else if (strcmp(argp, "-idirafter") == 0) {
+                               strlist_append(&dirafterdirs, nxtopt(0));
+                       } else
+                               oerror(argp);
+                       break;
+
+               case 'k': /* generate PIC code */
+                       kflag = argp[2] ? argp[2] - '0' : F_pic;
+                       break;
+
+               case 'l':
+               case 'L':
+                       if (argp[2] == 0)
+                               argp = cat(argp, nxtopt(0));
+                       strlist_append(&inputs, argp);
+                       break;
+
+               case 'm': /* target-dependent options */
+                       if (strncmp(argp, "-march=", 6) == 0) {
+                               strlist_append(&compiler_flags, argp);
+                               break;
+                       }
+#ifdef mach_amd64
+                       /* need to call i386 ccom for this */
+                       if (strcmp(argp, "-melf_i386") == 0) {
+                               pass0 = LIBEXECDIR "/ccom_i386";
+                               amd64_i386 = 1;
+                               break;
+                       }
+#endif
+#if defined(mach_arm) || defined(mach_mips)
+                       if (match(argp, "-mbig-endian")) {
+                               bigendian = 1;
+                               strlist_append(&compiler_flags, argp);
+                               break;
+                       }
+                       if (match(argp, "-mlittle-endian")) {
+                               bigendian = 0;
+                               strlist_append(&compiler_flags, argp);
+                               break;
+                       }
+                       if (match(argp, "-msoft-float")) {
+                               softfloat = 1;
+                               strlist_append(&compiler_flags, argp);
+                               break;
+                       }
+#endif
+#if defined(mach_mips)
+                       if (match(argp, "-mhard-float")) {
+                               softfloat = 0;
+                               strlist_append(&compiler_flags, argp);
+                               break;
+                       }
+#endif
+                       strlist_append(&middle_linker_flags, argp);
+                       if (argp[2] == 0) {
+                               t = nxtopt(0);
+                               strlist_append(&middle_linker_flags, t);
+                       }
+                       break;
+
+               case 'n': /* handle -n flags */
+                       if (strcmp(argp, "-nostdinc") == 0)
+                               nostdinc++;
+                       else if (strcmp(argp, "-nostdlib") == 0) {
+                               nostdlib++;
+                               nostartfiles++;
+                       } else if (strcmp(argp, "-nostartfiles") == 0)
+                               nostartfiles = 1;
+                       else if (strcmp(argp, "-nodefaultlibs") == 0)
+                               nostdlib++;
+                       else
+                               oerror(argp);
+                       break;
+
+               case 'p':
+                       if (strcmp(argp, "-pg") == 0 ||
+                           strcmp(argp, "-p") == 0)
+                               pgflag++;
+                       else if (strcmp(argp, "-pthread") == 0)
+                               pthreads++;
+                       else if (strcmp(argp, "-pipe") == 0)
+                               /* NOTHING YET */;
+                       else if (strcmp(argp, "-pedantic") == 0)
+                               /* NOTHING YET */;
+                       else if ((t = argnxt(argp, "-print-prog-name="))) {
+                               fname = t;
+                               printprogname = 1;
+                       } else if ((t = argnxt(argp, "-print-file-name="))) {
+                               fname = t;
+                               printfilename = 1;
+                       } else if (match(argp, "-print-libgcc-file-name")) {
+                               fname = "libpcc.a";
+                               printfilename = 1;
+                       } else
+                               oerror(argp);
+                       break;
+
+               case 'R':
+                       if (argp[2] == 0)
+                               argp = cat(argp, nxtopt(0));
+                       strlist_append(&middle_linker_flags, argp);
+                       break;
+
+               case 'r':
+                       rflag = 1;
+                       break;
+
+               case 'T':
+                       strlist_append(&inputs, argp);
+                       if (argp[2] == 0 ||
+                           strcmp(argp, "-Ttext") == 0 ||
+                           strcmp(argp, "-Tdata") == 0 ||
+                           strcmp(argp, "-Tbss") == 0)
+                               strlist_append(&inputs, nxtopt(0));
+                       break;
+
+               case 's':
+                       if (match(argp, "-shared")) {
+                               shared = 1;
+                       } else if (match(argp, "-static")) {
+                               Bstatic = 1;
+                       } else if (match(argp, "-symbolic")) {
+                               strlist_append(&middle_linker_flags,
+                                   "-Bsymbolic");
+                       } else if (strncmp(argp, "-std", 4) == 0) {
+                               if (strcmp(&argp[5], "gnu99") == 0 ||
+                                   strcmp(&argp[5], "gnu9x") == 0)
+                                       cstd = SGNU99;
+                               if (strcmp(&argp[5], "c89") == 0)
+                                       cstd = SC89;
+                               if (strcmp(&argp[5], "gnu89") == 0)
+                                       cstd = SGNU89;
+                               if (strcmp(&argp[5], "c99") == 0)
+                                       cstd = SC99;
+                       } else
+                               oerror(argp);
+                       break;
+
+               case 'S':
+                       Sflag++;
+                       cflag++;
+                       break;
+
+               case 't':
+                       tflag++;
+                       cstd = STRAD;
+                       break;
+
+               case 'o':
+                       if (outfile)
+                               errorx(8, "too many -o");
+                       outfile = nxtopt("-o");
+                       break;
+
+               case 'O':
+                       if (argp[2] == '\0')
+                               Oflag++;
+                       else if (argp[3] == '\0' &&
+                           isdigit((unsigned char)argp[2]))
+                               Oflag = argp[2] - '0';
+                       else if (argp[3] == '\0' && argp[2] == 's')
+                               Oflag = 1;      /* optimize for space only */
+                       else
+                               oerror(argp);
+                       break;
+
+               case 'P':
+                       strlist_append(&preprocessor_flags, argp);
+                       break;
+
+               case 'M':
+                       needM = 1;
+                       if (match(argp, "-M")) {
+                               Mflag++;
+                               strlist_append(&depflags, argp);
+                       } else if (match(argp, "-MP")) {
+                               strlist_append(&depflags, "-xMP");
+                       } else if (match(argp, "-MF")) {
+                               MFfile = nxtopt("-MF");
+                       } else if (match(argp, "-MT") || match(argp, "-MQ")) {
+                               t = cat("-xMT,", nxtopt("-MT"));
+                               t[3] = argp[2];
+                               strlist_append(&depflags, t);
+                       } else if (match(argp, "-MD")) {
+                               MDflag++;
+                               needM = 0;
+                               strlist_append(&depflags, "-M");
+                       } else if (match(argp, "-MMD")) {
+                               MMDflag++;
+                               needM = 0;
+                               strlist_append(&depflags, "-M");
+                               strlist_append(&depflags, "-xMMD");
+                       } else
+                               oerror(argp);
+                       break;
+
+               case 'v':
+                       printf("%s\n", VERSSTR);
+                       vflag++;
+                       break;
+
+               case 'w': /* no warnings at all emitted */
+                       strlist_append(&compiler_flags, "-w");
+                       break;
+
+               case 'W': /* Ignore (most of) W-flags */
+                       if ((t = argnxt(argp, "-Wl,"))) {
+                               u = strtok(t, ",");
+                               do {
+                                       strlist_append(&inputs, u);
+                               } while ((u = strtok(NULL, ",")) != NULL);
+                       } else if ((t = argnxt(argp, "-Wa,"))) {
+                               u = strtok(t, ",");
+                               do {
+                                       strlist_append(&assembler_flags, u);
+                               } while ((u = strtok(NULL, ",")) != NULL);
+                       } else if ((t = argnxt(argp, "-Wc,"))) {
+                               u = strtok(t, ",");
+                               do {
+                                       strlist_append(&compiler_flags, u);
+                               } while ((u = strtok(NULL, ",")) != NULL);
+                       } else if ((t = argnxt(argp, "-Wp,"))) {
+                               u = strtok(t, ",");
+                               do {
+                                       strlist_append(&preprocessor_flags, u);
+                               } while ((u = strtok(NULL, ",")) != NULL);
+                       } else if (strcmp(argp, "-Werror") == 0) {
+                               strlist_append(&compiler_flags, "-Werror");
+                               strlist_append(&preprocessor_flags, "-E");
+                       } else if (strcmp(argp, "-Wall") == 0) {
+                               for (Wf = Wflags; Wf->name; Wf++)
+                                       if (Wf->flags & INWALL)
+                                               strlist_append(&compiler_flags,
+                                                   cat("-W", Wf->name));
+                       } else if (strcmp(argp, "-WW") == 0) {
+                               for (Wf = Wflags; Wf->name; Wf++)
+                                       strlist_append(&compiler_flags,
+                                           cat("-W", Wf->name));
+                       } else {
+                               /* pass through, if supported */
+                               t = &argp[2];
+                               if (strncmp(t, "no-", 3) == 0)
+                                       t += 3;
+                               if (strncmp(t, "error=", 6) == 0)
+                                       t += 6;
+                               for (Wf = Wflags; Wf->name; Wf++) {
+                                       if (strcmp(t, Wf->name) == 0)
+                                               strlist_append(&compiler_flags,
+                                                   argp);
+                               }
+                       }
+                       break;
+
+               case 'x':
+                       t = nxtopt("-x");
+                       if (match(t, "none"))
+                               strlist_append(&inputs, ")");
+                       else if (match(t, "c"))
+                               strlist_append(&inputs, ")c");
+                       else if (match(t, "assembler"))
+                               strlist_append(&inputs, ")s");
+                       else if (match(t, "assembler-with-cpp"))
+                               strlist_append(&inputs, ")S");
+                       else if (match(t, "c++"))
+                               strlist_append(&inputs, ")c++");
+                       else {
+                               strlist_append(&compiler_flags, "-x");
+                               strlist_append(&compiler_flags, t);
+                       }
+                       break;
+
+               }
+               continue;
+
+       }
+
+       /* Sanity checking */
+       if (cppflag) {
+               if (ninput == 0) {
+                       strlist_append(&inputs, "-");
+                       ninput++;
+               } else if (ninput > 2 || (ninput == 2 && outfile)) {
+                       errorx(8, "too many files");
+               } else if (ninput == 2) {
+                       outfile = STRLIST_NEXT(STRLIST_FIRST(&inputs))->value;
+                       STRLIST_FIRST(&inputs)->next = NULL;
+                       ninput--;
+               }
+       }
+       if (tflag && Eflag == 0)
+               errorx(8,"-t only allowed fi -E given");
+
+       /* Correct C standard */
+       switch (cstd) {
+       case STRAD: break;
+       case SC89: c89defs = 1; break;
+       case SGNU89: xgnu89 = c89defs = 1; break;
+       case SC99: c89defs = c99defs = 1; break;
+       case SGNU99: c89defs = c99defs = xgnu99 = 1; break;
+       case SC11: c89defs = c11defs = 1; break;
+       }
+
+       if (ninput == 0 && !(printprogname || printfilename))
+               errorx(8, "no input files");
+       if (outfile && (cflag || Sflag || Eflag) && ninput > 1)
+               errorx(8, "-o given with -c || -E || -S and more than one file");
+#if 0
+       if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0)
+               errorx(8, "output file will be clobbered");
+#endif
+
+       if (needM && !Mflag && !MDflag && !MMDflag)
+               errorx(8, "to make dependencies needs -M");
+
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN) /* interrupt */
+               signal(SIGINT, idexit);
+       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)        /* terminate */
+               signal(SIGTERM, idexit);
+
+       /* after arg parsing */
+       strlist_append(&progdirs, LIBEXECDIR);
+       if (pcclibdir)
+               strlist_append(&crtdirs, pcclibdir);
+       for (j = 0; deflibdirs[j]; j++) {
+               if (sysroot)
+                       deflibdirs[j] = cat(sysroot, deflibdirs[j]);
+               strlist_append(&crtdirs, deflibdirs[j]);
+       }
+
+       setup_cpp_flags();
+       setup_ccom_flags();
+       setup_as_flags();
+
+       if (isysroot == NULL)
+               isysroot = sysroot;
+       expand_sysroot();
+
+       if (printprogname) {
+               printf("%s\n", find_file(fname, &progdirs, X_OK));
+               return 0;
+       } else if (printfilename) {
+               printf("%s\n", find_file(fname, &crtdirs, R_OK));
+               return 0;
+       }
+
+       msuffix = NULL;
+       STRLIST_FOREACH(s, &inputs) {
+               char *suffix;
+               char *ifile, *ofile = NULL;
+
+               ifile = s->value;
+               if (ifile[0] == ')') { /* -x source type given */
+                       msuffix = ifile[1] ? &ifile[1] : NULL;
+                       continue;
+               }
+               if (ifile[0] == '-' && ifile[1] == 0)
+                       suffix = msuffix ? msuffix : "c";
+               else if (ifile[0] == '-')
+                       suffix = "o"; /* source files cannot begin with - */
+               else if (msuffix)
+                       suffix = msuffix;
+               else
+                       suffix = getsufp(ifile);
+               /*
+                * C preprocessor
+                */
+               ascpp = match(suffix, "S");
+               if (ascpp || cppflag || match(suffix, "c") || cxxsuf(suffix)) {
+                       /* find out next output file */
+                       if (Mflag || MDflag || MMDflag) {
+                               char *Mofile = NULL;
+
+                               if (MFfile)
+                                       Mofile = MFfile;
+                               else if (outfile)
+                                       Mofile = setsuf(outfile, 'd');
+                               else if (MDflag || MMDflag)
+                                       Mofile = setsuf(ifile, 'd');
+                               if (preprocess_input(ifile, Mofile, 1))
+                                       exandrm(Mofile);
+                       }
+                       if (Mflag)
+                               continue;
+                       if (Eflag) {
+                               /* last pass */
+                               ofile = outfile;
+                       } else {
+                               /* to temp file */
+                               strlist_append(&temp_outputs, ofile = gettmp());
+                       }
+                       if (preprocess_input(ifile, ofile, 0))
+                               exandrm(ofile);
+                       if (Eflag)
+                               continue;
+                       ifile = ofile;
+                       suffix = match(suffix, "S") ? "s" : "i";
+               }
+
+               /*
+                * C compiler
+                */
+               if (match(suffix, "i")) {
+                       /* find out next output file */
+                       if (Sflag) {
+                               ofile = outfile;
+                               if (outfile == NULL)
+                                       ofile = setsuf(s->value, 's');
+                       } else
+                               strlist_append(&temp_outputs, ofile = gettmp());
+                       if (compile_input(ifile, ofile))
+                               exandrm(ofile);
+                       if (Sflag)
+                               continue;
+                       ifile = ofile;
+                       suffix = "s";
+               }
+
+               /*
+                * Assembler
+                */
+               if (match(suffix, "s")) {
+                       if (cflag) {
+                               ofile = outfile;
+                               if (ofile == NULL)
+                                       ofile = setsuf(s->value, 'o');
+                       } else {
+                               strlist_append(&temp_outputs, ofile = gettmp());
+                               /* strlist_append linker */
+                       }
+                       if (assemble_input(ifile, ofile))
+                               exandrm(ofile);
+                       ifile = ofile;
+               }
+
+               strlist_append(&middle_linker_flags, ifile);
+       }
+
+       if (cflag || Eflag || Mflag)
+               dexit(0);
+
+       /*
+        * Linker
+        */
+       setup_ld_flags();
+       if (run_linker())
+               exandrm(0);
+
+#ifdef notdef
+       strlist_free(&crtdirs);
+       strlist_free(&libdirs);
+       strlist_free(&progdirs);
+       strlist_free(&incdirs);
+       strlist_free(&preprocessor_flags);
+       strlist_free(&user_sysincdirs);
+       strlist_free(&includes);
+       strlist_free(&sysincdirs);
+       strlist_free(&dirafterdirs);
+       strlist_free(&depflags);
+       strlist_free(&early_linker_flags);
+       strlist_free(&middle_linker_flags);
+       strlist_free(&late_linker_flags);
+       strlist_free(&inputs);
+       strlist_free(&assembler_flags);
+       strlist_free(&temp_outputs);
+       strlist_free(&compiler_flags);
+#endif
+       dexit(0);
+       return 0;
+}
+
+/*
+ * exit and cleanup after interrupt.
+ */
+void
+idexit(int arg)
+{
+       dexit(100);
+}
+
+/*
+ * exit and cleanup.
+ */
+void
+dexit(int eval)
+{
+       struct string *s;
+
+       if (!Xflag) {
+               STRLIST_FOREACH(s, &temp_outputs)
+                       cunlink(s->value);
+       }
+       exit(eval);
+}
+
+/*
+ * Called when something failed.
+ */
+void
+exandrm(char *s)
+{
+       if (s && *s)
+               strlist_append(&temp_outputs, s);
+       dexit(1);
+}
+
+/*
+ * complain and exit.
+ */
+void
+errorx(int eval, char *s, ...)
+{
+       va_list ap;
+
+       va_start(ap, s);
+       fputs("error: ", stderr);
+       vfprintf(stderr, s, ap);
+       putc('\n', stderr);
+       va_end(ap);
+       dexit(eval);
+}
+
+static char *
+find_file(const char *file, struct strlist *path, int mode)
+{
+       struct string *s;
+       char *f;
+       size_t lf, lp;
+       int need_sep;
+
+       lf = strlen(file);
+       STRLIST_FOREACH(s, path) {
+               lp = strlen(s->value);
+               need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0;
+               f = xmalloc(lp + lf + need_sep + 1);
+               memcpy(f, s->value, lp);
+               if (need_sep)
+                       f[lp] = '/';
+               memcpy(f + lp + need_sep, file, lf + 1);
+               if (access(f, mode) == 0)
+                       return f;
+               free(f);
+       }
+       return xstrdup(file);
+}
+
+#ifdef TWOPASS
+static int
+compile_input(char *input, char *output)
+{
+       struct strlist args;
+       char *tfile;
+       int retval;
+
+       strlist_append(&temp_outputs, tfile = gettmp());
+
+       strlist_init(&args);
+       strlist_append_list(&args, &compiler_flags);
+       strlist_append(&args, input);
+       strlist_append(&args, tfile);
+       strlist_prepend(&args,
+           find_file(cxxflag ? "cxx0" : "cc0", &progdirs, X_OK));
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       if (retval)
+               return retval;
+
+       strlist_init(&args);
+       strlist_append_list(&args, &compiler_flags);
+       strlist_append(&args, tfile);
+       strlist_append(&args, output);
+       strlist_prepend(&args,
+           find_file(cxxflag ? "cxx1" : "cc1", &progdirs, X_OK));
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+#else
+static int
+compile_input(char *input, char *output)
+{
+       struct strlist args;
+       int retval;
+
+       strlist_init(&args);
+       strlist_append_list(&args, &compiler_flags);
+       strlist_append(&args, input);
+       strlist_append(&args, output);
+       strlist_prepend(&args,
+           find_file(cxxflag ? passxx0 : pass0, &progdirs, X_OK));
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+#endif
+
+static int
+assemble_input(char *input, char *output)
+{
+       struct strlist args;
+       int retval;
+
+       strlist_init(&args);
+#ifdef PCC_EARLY_AS_ARGS
+       PCC_EARLY_AS_ARGS
+#endif
+       strlist_append_list(&args, &assembler_flags);
+       strlist_append(&args, input);
+       strlist_append(&args, "-o");
+       strlist_append(&args, output);
+       strlist_prepend(&args,
+           find_file(as, &progdirs, X_OK));
+#ifdef PCC_LATE_AS_ARGS
+       PCC_LATE_AS_ARGS
+#endif
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+
+static int
+preprocess_input(char *input, char *output, int dodep)
+{
+       struct strlist args;
+       struct string *s;
+       int retval;
+
+       strlist_init(&args);
+       strlist_append_list(&args, &preprocessor_flags);
+       if (ascpp) {
+               strlist_append(&args, "-A");
+               strlist_append(&args, "-D__ASSEMBLER__"); 
+       }
+       STRLIST_FOREACH(s, &includes) {
+               strlist_append(&args, "-i");
+               strlist_append(&args, s->value);
+       }
+       STRLIST_FOREACH(s, &incdirs) {
+               strlist_append(&args, "-I");
+               strlist_append(&args, s->value);
+       }
+       STRLIST_FOREACH(s, &user_sysincdirs) {
+               strlist_append(&args, "-S");
+               strlist_append(&args, s->value);
+       }
+       if (!nostdinc) {
+               STRLIST_FOREACH(s, &sysincdirs) {
+                       strlist_append(&args, "-S");
+                       strlist_append(&args, s->value);
+               }
+       }
+       STRLIST_FOREACH(s, &dirafterdirs) {
+               strlist_append(&args, "-S");
+               strlist_append(&args, s->value);
+       }
+       if (dodep)
+               strlist_append_list(&args, &depflags);
+       strlist_append(&args, input);
+       if (output)
+               strlist_append(&args, output);
+
+       strlist_prepend(&args, find_file(passp, &progdirs, X_OK));
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+
+static int
+run_linker(void)
+{
+       struct strlist linker_flags;
+       int retval;
+
+       if (outfile) {
+               strlist_prepend(&early_linker_flags, outfile);
+               strlist_prepend(&early_linker_flags, "-o");
+       }
+       strlist_init(&linker_flags);
+       strlist_append_list(&linker_flags, &early_linker_flags);
+       strlist_append_list(&linker_flags, &middle_linker_flags);
+       strlist_append_list(&linker_flags, &late_linker_flags);
+       strlist_prepend(&linker_flags, find_file(ld, &progdirs, X_OK));
+
+       retval = strlist_exec(&linker_flags);
+
+       strlist_free(&linker_flags);
+       return retval;
+}
+
+static char *cxxt[] = { "cc", "cp", "cxx", "cpp", "CPP", "c++", "C" };
+int
+cxxsuf(char *s)
+{
+       unsigned i;
+       for (i = 0; i < sizeof(cxxt)/sizeof(cxxt[0]); i++)
+               if (strcmp(s, cxxt[i]) == 0)
+                       return 1;
+       return 0;
+}
+
+char *
+getsufp(char *s)
+{
+       register char *p;
+
+       if ((p = strrchr(s, '.')) && p[1] != '\0')
+               return &p[1];
+       return "";
+}
+
+int
+getsuf(char *s)
+{
+       register char *p;
+
+       if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0')
+               return p[1];
+       return(0);
+}
+
+/*
+ * Get basename of string s, copy it and change its suffix to ch.
+ */
+char *
+setsuf(char *s, char ch)
+{
+       char *e, *p, *rp;
+
+       e = NULL;
+       for (p = s; *p; p++) {
+               if (*p == '/')
+                       s = p + 1;
+               if (*p == '.')
+                       e = p;
+       }
+       if (s > e)
+               e = p;
+
+       rp = p = xmalloc(e - s + 3);
+       while (s < e)
+               *p++ = *s++;
+
+       *p++ = '.';
+       *p++ = ch;
+       *p = '\0';
+       return rp;
+}
+
+#ifdef _WIN32
+
+static int
+strlist_exec(struct strlist *l)
+{
+       char *cmd;
+       STARTUPINFO si;
+       PROCESS_INFORMATION pi;
+       DWORD exitCode;
+       BOOL ok;
+
+       cmd = win32commandline(l);
+       if (vflag)
+               printf("%s\n", cmd);
+       if (noexec)
+               return 0;
+
+       ZeroMemory(&si, sizeof(STARTUPINFO));
+       si.cb = sizeof(STARTUPINFO);
+       ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+       ok = CreateProcess(NULL,  // the executable program
+               cmd,   // the command line arguments
+               NULL,       // ignored
+               NULL,       // ignored
+               TRUE,       // inherit handles
+               HIGH_PRIORITY_CLASS,
+               NULL,       // ignored
+               NULL,       // ignored
+               &si,
+               &pi);
+
+       if (!ok)
+               errorx(100, "Can't find %s\n", STRLIST_FIRST(l)->value);
+
+       WaitForSingleObject(pi.hProcess, INFINITE);
+       GetExitCodeProcess(pi.hProcess, &exitCode);
+       CloseHandle(pi.hProcess);
+       CloseHandle(pi.hThread);
+
+       return (exitCode != 0);
+}
+
+#else
+
+static int
+strlist_exec(struct strlist *l)
+{
+       sig_atomic_t exit_now = 0;
+       sig_atomic_t child;
+       char **argv;
+       size_t argc;
+       int result;
+
+       strlist_make_array(l, &argv, &argc);
+       if (vflag) {
+               printf("Calling ");
+               strlist_print(l, stdout, noexec);
+               printf("\n");
+       }
+       if (noexec)
+               return 0;
+
+       switch ((child = fork())) {
+       case 0:
+               execvp(argv[0], argv);
+               result = write(STDERR_FILENO, "Exec of ", 8);
+               result = write(STDERR_FILENO, argv[0], strlen(argv[0]));
+               result = write(STDERR_FILENO, " failed\n", 8);
+               (void)result;
+               _exit(127);
+       case -1:
+               errorx(1, "fork failed");
+       default:
+               while (waitpid(child, &result, 0) == -1 && errno == EINTR)
+                       /* nothing */(void)0;
+               result = WEXITSTATUS(result);
+               if (result)
+                       errorx(1, "%s terminated with status %d", argv[0], result);
+               while (argc-- > 0)
+                       free(argv[argc]);
+               free(argv);
+               break;
+       }
+       return exit_now;
+}
+
+#endif
+
+/*
+ * Catenate two (optional) strings together
+ */
+char *
+cat(const char *a, const char *b)
+{
+       size_t len;
+       char *rv;
+
+       len = (a ? strlen(a) : 0) + (b ? strlen(b) : 0) + 1;
+       rv = xmalloc(len);
+       snprintf(rv, len, "%s%s", (a ? a : ""), (b ? b : ""));
+       return rv;
+}
+
+int
+cunlink(char *f)
+{
+       if (f==0 || Xflag)
+               return(0);
+       return (unlink(f));
+}
+
+#ifdef _WIN32
+char *
+gettmp(void)
+{
+       DWORD pathSize;
+       char pathBuffer[MAX_PATH + 1];
+       char tempFilename[MAX_PATH];
+       UINT uniqueNum;
+
+       pathSize = GetTempPath(sizeof(pathBuffer), pathBuffer);
+       if (pathSize == 0 || pathSize > sizeof(pathBuffer))
+               pathBuffer[0] = '\0';
+       uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename);
+       if (uniqueNum == 0)
+               errorx(8, "GetTempFileName failed: path \"%s\"", pathBuffer);
+
+       return xstrdup(tempFilename);
+}
+
+#else
+
+char *
+gettmp(void)
+{
+       char *sfn = xstrdup("/tmp/ctm.XXXXXX");
+       int fd = -1;
+
+       if ((fd = mkstemp(sfn)) == -1)
+               errorx(8, "%s: %s\n", sfn, strerror(errno));
+       close(fd);
+       return sfn;
+}
+#endif
+
+static void
+expand_sysroot(void)
+{
+       struct string *s;
+       struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs,
+           &user_sysincdirs, &libdirs, &progdirs, &dirafterdirs, NULL };
+       const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot,
+           sysroot, sysroot, isysroot, NULL };
+       size_t i, sysroot_len, value_len;
+       char *path;
+
+       assert(sizeof(lists) / sizeof(lists[0]) ==
+              sizeof(sysroots) / sizeof(sysroots[0]));
+
+       for (i = 0; lists[i] != NULL; ++i) {
+               STRLIST_FOREACH(s, lists[i]) {
+                       if (s->value[0] != '=')
+                               continue;
+                       sysroot_len = strlen(sysroots[i]);
+                       /* Skipped '=' compensates additional space for '\0' */
+                       value_len = strlen(s->value);
+                       path = xmalloc(sysroot_len + value_len);
+                       memcpy(path, sysroots[i], sysroot_len);
+                       memcpy(path + sysroot_len, s->value + 1, value_len);
+                       free(s->value);
+                       s->value = path;
+               }
+       }
+}
+
+void
+oerror(char *s)
+{
+       errorx(8, "unknown option '%s'", s);
+}
+
+/*
+ * See if m matches the beginning of string str, if it does return the
+ * remaining of str, otherwise NULL.
+ */
+char *
+argnxt(char *str, char *m)
+{
+       if (strncmp(str, m, strlen(m)))
+               return NULL; /* No match */
+       return str + strlen(m);
+}
+
+/*
+ * Return next argument to option, or complain.
+ */
+char *
+nxtopt(char *o)
+{
+       int l;
+
+       if (o != NULL) {
+               l = strlen(o);
+               if (lav[0][l] != 0)
+                       return &lav[0][l];
+       }
+       if (lac == 1)
+               errorx(8, "missing argument to '%s'", o);
+       lav++;
+       lac--;
+       return lav[0];
+}
+
+struct flgcheck {
+       int *flag;
+       int set;
+       char *def;
+} cppflgcheck[] = {
+       { &vflag, 1, "-v" },
+       { &c99defs, 1, "-D__STDC_VERSION__=199901L" },
+       { &c11defs, 1, "-D__STDC_VERSION__=201112L" },
+       { &c89defs, 1, "-D__STDC__=1" },
+       { &freestanding, 1, "-D__STDC_HOSTED__=0" },
+       { &freestanding, 0, "-D__STDC_HOSTED__=1" },
+       { &cxxflag, 1, "-D__cplusplus" },
+       { &xuchar, 1, "-D__CHAR_UNSIGNED__" },
+       { &sspflag, 1, "-D__SSP__" },
+       { &pthreads, 1, "-D_PTHREADS" },
+       { &Oflag, 1, "-D__OPTIMIZE__" },
+       { &tflag, 1, "-t" },
+       { &kflag, 1, "-D__PIC__" },
+       { 0 },
+};
+
+static void
+cksetflags(struct flgcheck *fs, struct strlist *sl, int which)
+{
+       void (*fn)(struct strlist *, const char *);
+
+       fn = which == 'p' ? strlist_prepend : strlist_append;
+       for (; fs->flag; fs++) {
+               if (fs->set && *fs->flag)
+                       fn(sl, fs->def);
+               if (!fs->set && !*fs->flag)
+                       fn(sl, fs->def);
+       }
+}
+
+#ifndef TARGET_LE
+#define TARGET_LE       1
+#define TARGET_BE       2
+#define TARGET_PDP      3
+#define TARGET_ANY      4
+#endif
+
+static char *defflags[] = {
+       "-D__PCC__=" MKS(PCC_MAJOR),
+       "-D__PCC_MINOR__=" MKS(PCC_MINOR),
+       "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR),
+       "-D__VERSION__=" MKS(VERSSTR),
+       "-D__SCHAR_MAX__=" MKS(MAX_CHAR),
+       "-D__SHRT_MAX__=" MKS(MAX_SHORT),
+       "-D__INT_MAX__=" MKS(MAX_INT),
+       "-D__LONG_MAX__=" MKS(MAX_LONG),
+       "-D__LONG_LONG_MAX__=" MKS(MAX_LONGLONG),
+
+       "-D__STDC_ISO_10646__=200009L",
+       "-D__WCHAR_TYPE__=" WCT,
+       "-D__SIZEOF_WCHAR_T__=" MKS(WCHAR_SIZE),
+       "-D__WCHAR_MAX__=" WCM,
+       "-D__WINT_TYPE__=" PCC_WINT_TYPE,
+       "-D__SIZE_TYPE__=" PCC_SIZE_TYPE,
+       "-D__PTRDIFF_TYPE__=" PCC_PTRDIFF_TYPE,
+       "-D__SIZEOF_WINT_T__=4",
+       "-D__ORDER_LITTLE_ENDIAN__=1234",
+       "-D__ORDER_BIG_ENDIAN__=4321",
+       "-D__ORDER_PDP_ENDIAN__=3412",
+#ifndef NO_C11
+       "-D__STDC_UTF_16__=1",
+       "-D__STDC_UTF_32__=1",
+       "-D__STDC_NO_ATOMICS__=1",
+       "-D__STDC_NO_THREADS__=1",
+#endif
+
+/*
+ * These should probably be changeable during runtime...
+ */
+#if TARGET_ENDIAN == TARGET_BE
+       "-D__FLOAT_WORD_ORDER__=__ORDER_BIG_ENDIAN__",
+       "-D__BYTE_ORDER__=__ORDER_BIG_ENDIAN__",
+#elif TARGET_ENDIAN == TARGET_PDP
+       "-D__FLOAT_WORD_ORDER__=__ORDER_PDP_ENDIAN__",
+       "-D__BYTE_ORDER__=__ORDER_PDP_ENDIAN__",
+#elif TARGET_ENDIAN == TARGET_LE
+       "-D__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__",
+       "-D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__",
+#else
+#error Unknown endian...
+#endif
+};
+
+static char *gcppflags[] = {
+#ifndef os_win32
+#ifdef GCC_COMPAT
+       "-D__GNUC__=4",
+       "-D__GNUC_MINOR__=3",
+       "-D__GNUC_PATCHLEVEL__=1",
+       "-D__REGISTER_PREFIX__=" REGISTER_PREFIX,
+       "-D__USER_LABEL_PREFIX__=" USER_LABEL_PREFIX,
+#if SZLONG == 64
+       "-D__SIZEOF_LONG__=8",
+#elif SZLONG == 32
+       "-D__SIZEOF_LONG__=4",
+#endif
+#if SZPOINT(CHAR) == 64
+       "-D__SIZEOF_POINTER__=8",
+#elif SZPOINT(CHAR) == 32
+       "-D__SIZEOF_POINTER__=4",
+#endif
+#endif
+#endif
+       NULL
+};
+
+/* These should _not_ be defined here */
+static char *fpflags[] = {
+#ifdef TARGET_FLT_EVAL_METHOD
+       "-D__FLT_EVAL_METHOD__=" MKS(TARGET_FLT_EVAL_METHOD),
+#endif
+#if defined(os_darwin) || defined(os_netbsd) || defined(os_minix)
+       "-D__FLT_RADIX__=2",
+#if defined(mach_vax)
+       "-D__FLT_DIG__=6",
+       "-D__FLT_EPSILON__=1.19209290e-07F",
+       "-D__FLT_MANT_DIG__=24",
+       "-D__FLT_MAX_10_EXP__=38",
+       "-D__FLT_MAX_EXP__=127",
+       "-D__FLT_MAX__=1.70141173e+38F",
+       "-D__FLT_MIN_10_EXP__=(-38)",
+       "-D__FLT_MIN_EXP__=(-127)",
+       "-D__FLT_MIN__=2.93873588e-39F",
+       "-D__DBL_DIG__=16",
+       "-D__DBL_EPSILON__=2.77555756156289135e-17",
+       "-D__DBL_MANT_DIG__=56",
+       "-D__DBL_MAX_10_EXP__=38",
+       "-D__DBL_MAX_EXP__=127",
+       "-D__DBL_MAX__=1.701411834604692294e+38",
+       "-D__DBL_MIN_10_EXP__=(-38)",
+       "-D__DBL_MIN_EXP__=(-127)",
+       "-D__DBL_MIN__=2.938735877055718770e-39",
+#else
+       "-D__FLT_DIG__=6",
+       "-D__FLT_EPSILON__=1.19209290e-07F",
+       "-D__FLT_MANT_DIG__=24",
+       "-D__FLT_MAX_10_EXP__=38",
+       "-D__FLT_MAX_EXP__=128",
+       "-D__FLT_MAX__=3.40282347e+38F",
+       "-D__FLT_MIN_10_EXP__=(-37)",
+       "-D__FLT_MIN_EXP__=(-125)",
+       "-D__FLT_MIN__=1.17549435e-38F",
+       "-D__DBL_DIG__=15",
+       "-D__DBL_EPSILON__=2.2204460492503131e-16",
+       "-D__DBL_MANT_DIG__=53",
+       "-D__DBL_MAX_10_EXP__=308",
+       "-D__DBL_MAX_EXP__=1024",
+       "-D__DBL_MAX__=1.7976931348623157e+308",
+       "-D__DBL_MIN_10_EXP__=(-307)",
+       "-D__DBL_MIN_EXP__=(-1021)",
+       "-D__DBL_MIN__=2.2250738585072014e-308",
+#endif
+#if defined(mach_i386) || defined(mach_amd64)
+       "-D__LDBL_DIG__=18",
+       "-D__LDBL_EPSILON__=1.08420217248550443401e-19L",
+       "-D__LDBL_MANT_DIG__=64",
+       "-D__LDBL_MAX_10_EXP__=4932",
+       "-D__LDBL_MAX_EXP__=16384",
+       "-D__LDBL_MAX__=1.18973149535723176502e+4932L",
+       "-D__LDBL_MIN_10_EXP__=(-4931)",
+       "-D__LDBL_MIN_EXP__=(-16381)",
+       "-D__LDBL_MIN__=3.36210314311209350626e-4932L",
+#elif defined(mach_vax)
+       "-D__LDBL_DIG__=16",
+       "-D__LDBL_EPSILON__=2.77555756156289135e-17",
+       "-D__LDBL_MANT_DIG__=56",
+       "-D__LDBL_MAX_10_EXP__=38",
+       "-D__LDBL_MAX_EXP__=127",
+       "-D__LDBL_MAX__=1.701411834604692294e+38",
+       "-D__LDBL_MIN_10_EXP__=(-38)",
+       "-D__LDBL_MIN_EXP__=(-127)",
+       "-D__LDBL_MIN__=2.938735877055718770e-39",
+#else
+       "-D__LDBL_DIG__=15",
+       "-D__LDBL_EPSILON__=2.2204460492503131e-16",
+       "-D__LDBL_MANT_DIG__=53",
+       "-D__LDBL_MAX_10_EXP__=308",
+       "-D__LDBL_MAX_EXP__=1024",
+       "-D__LDBL_MAX__=1.7976931348623157e+308",
+       "-D__LDBL_MIN_10_EXP__=(-307)",
+       "-D__LDBL_MIN_EXP__=(-1021)",
+       "-D__LDBL_MIN__=2.2250738585072014e-308",
+#endif
+#endif
+       NULL
+};
+
+/*
+ * Configure the standard cpp flags.
+ */
+void
+setup_cpp_flags(void)
+{
+       int i;
+
+       /* a bunch of misc defines */
+       for (i = 0; i < (int)sizeof(defflags)/(int)sizeof(char *); i++)
+               strlist_prepend(&preprocessor_flags, defflags[i]);
+
+       for (i = 0; gcppflags[i]; i++)
+               strlist_prepend(&preprocessor_flags, gcppflags[i]);
+       strlist_prepend(&preprocessor_flags, xgnu89 ?
+           "-D__GNUC_GNU_INLINE__" : "-D__GNUC_STDC_INLINE__");
+
+       cksetflags(cppflgcheck, &preprocessor_flags, 'p');
+
+       /* Create time and date defines */
+       if (tflag == 0) {
+               char buf[100]; /* larger than needed */
+               time_t t = time(NULL);
+               char *n = ctime(&t);
+       
+               n[19] = 0;
+               snprintf(buf, sizeof buf, "-D__TIME__=\"%s\"", n+11);
+               strlist_prepend(&preprocessor_flags, xstrdup(buf));
+
+               n[24] = n[11] = 0;
+               snprintf(buf, sizeof buf, "-D__DATE__=\"%s%s\"", n+4, n+20);
+               strlist_prepend(&preprocessor_flags, xstrdup(buf));
+       }
+
+       for (i = 0; fpflags[i]; i++)
+               strlist_prepend(&preprocessor_flags, fpflags[i]);
+
+       for (i = 0; cppadd[i]; i++)
+               strlist_prepend(&preprocessor_flags, cppadd[i]);
+       for (i = 0; cppmdadd[i]; i++)
+               strlist_prepend(&preprocessor_flags, cppmdadd[i]);
+
+       /* Include dirs */
+       strlist_append(&sysincdirs, "=" INCLUDEDIR "pcc/");
+#ifdef STDINC_MA
+       strlist_append(&sysincdirs, "=" STDINC_MA);
+#endif
+       strlist_append(&sysincdirs, "=" STDINC);
+#ifdef PCCINCDIR
+       if (cxxflag)
+               strlist_append(&sysincdirs, "=" PCCINCDIR "/c++");
+       strlist_append(&sysincdirs, "=" PCCINCDIR);
+#endif
+}
+
+struct flgcheck ccomflgcheck[] = {
+       { &Oflag, 1, "-xtemps" },
+       { &Oflag, 1, "-xdeljumps" },
+       { &Oflag, 1, "-xinline" },
+       { &Oflag, 1, "-xdce" },
+#ifdef notyet
+       { &Oflag, 1, "-xssa" },
+#endif
+       { &freestanding, 1, "-ffreestanding" },
+       { &pgflag, 1, "-p" },
+       { &gflag, 1, "-g" },
+       { &xgnu89, 1, "-xgnu89" },
+       { &xgnu99, 1, "-xgnu99" },
+       { &xuchar, 1, "-xuchar" },
+#if !defined(os_sunos) && !defined(mach_i386)
+       { &vflag, 1, "-v" },
+#endif
+#ifdef os_darwin
+       { &Bstatic, 0, "-k" },
+#elif defined(os_sunos) && defined(mach_i386)
+       { &kflag, 1, "-K" },
+       { &kflag, 1, "pic" },
+#else
+       { &kflag, 1, "-k" },
+#endif
+       { &sspflag, 1, "-fstack-protector" },
+       { 0 }
+};
+
+void
+setup_ccom_flags(void)
+{
+
+       cksetflags(ccomflgcheck, &compiler_flags, 'a');
+}
+
+static int one = 1;
+
+struct flgcheck asflgcheck[] = {
+#if defined(USE_YASM)
+       { &one, 1, "-p" },
+       { &one, 1, "gnu" },
+       { &one, 1, "-f" },
+#if defined(os_win32)
+       { &one, 1, "win32" },
+#elif defined(os_darwin)
+       { &one, 1, "macho" },
+#else
+       { &one, 1, "elf" },
+#endif
+#endif
+#if defined(os_sunos) && defined(mach_sparc64)
+       { &one, 1, "-m64" },
+#endif
+#if defined(os_darwin)
+       { &Bstatic, 1, "-static" },
+#endif
+#if !defined(USE_YASM)
+       { &vflag, 1, "-v" },
+#endif
+       { &kflag, 1, "-k" },
+#ifdef os_darwin
+       { &one, 1, "-arch" },
+#if mach_amd64
+       { &amd64_i386, 1, "i386" },
+       { &amd64_i386, 0, "x86_64" },
+#else
+       { &one, 1, "i386" },
+#endif
+#else
+#ifdef mach_amd64
+       { &amd64_i386, 1, "--32" },
+#endif
+#endif
+       { 0 }
+};
+void
+setup_as_flags(void)
+{
+       one = one;
+#ifdef PCC_SETUP_AS_ARGS
+       PCC_SETUP_AS_ARGS
+#endif
+       cksetflags(asflgcheck, &assembler_flags, 'a');
+}
+
+struct flgcheck ldflgcheck[] = {
+#ifndef MSLINKER
+       { &vflag, 1, "-v" },
+#endif
+#ifdef os_darwin
+       { &shared, 1, "-dylib" },
+#elif defined(os_win32)
+       { &shared, 1, "-Bdynamic" },
+#else
+       { &shared, 1, "-shared" },
+#endif
+#if !defined(os_sunos) && !defined(os_win32)
+#ifndef os_darwin
+       { &shared, 0, "-d" },
+#endif
+#endif
+#ifdef os_darwin
+       { &Bstatic, 1, "-static" },
+#else
+       { &Bstatic, 1, "-Bstatic" },
+#endif
+#if !defined(os_darwin) && !defined(os_sunos)
+       { &gflag, 1, "-g" },
+#endif
+       { &pthreads, 1, "-lpthread" },
+       { 0 },
+};
+
+static void
+strap(struct strlist *sh, struct strlist *cd, char *n, int where)
+{
+       void (*fn)(struct strlist *, const char *);
+       char *fil;
+
+       if (n == 0)
+               return; /* no crtfile */
+
+       fn = where == 'p' ? strlist_prepend : strlist_append;
+       fil = find_file(n, cd, R_OK);
+       (*fn)(sh, fil);
+}
+
+void
+setup_ld_flags(void)
+{
+       char *b, *e;
+       int i;
+
+#ifdef PCC_SETUP_LD_ARGS
+       PCC_SETUP_LD_ARGS
+#endif
+
+       cksetflags(ldflgcheck, &early_linker_flags, 'a');
+       if (Bstatic == 0 && shared == 0 && rflag == 0) {
+               if (dynlinklib) {
+                       strlist_append(&early_linker_flags, dynlinkarg);
+                       strlist_append(&early_linker_flags, dynlinklib);
+               }
+               strlist_append(&early_linker_flags, "-e");
+               strlist_append(&early_linker_flags, STARTLABEL);
+       }
+       if (shared == 0 && rflag)
+               strlist_append(&early_linker_flags, "-r");
+#ifdef STARTLABEL_S
+       if (shared == 1) {
+               strlist_append(&early_linker_flags, "-e");
+               strlist_append(&early_linker_flags, STARTLABEL_S);
+       }
+#endif
+       if (sysroot && *sysroot)
+               strlist_append(&early_linker_flags, cat("--sysroot=", sysroot));
+       if (!nostdlib) {
+               /* library search paths */
+               if (pcclibdir)
+                       strlist_append(&late_linker_flags,
+                           cat("-L", pcclibdir));
+               for (i = 0; deflibdirs[i]; i++)
+                       strlist_append(&late_linker_flags,
+                           cat("-L", deflibdirs[i]));
+               /* standard libraries */
+               if (pgflag) {
+                       for (i = 0; defproflibs[i]; i++)
+                               strlist_append(&late_linker_flags,
+                                    defproflibs[i]);
+               } else if (cxxflag) {
+                       for (i = 0; defcxxlibs[i]; i++)
+                               strlist_append(&late_linker_flags,
+                                   defcxxlibs[i]);
+               } else {
+                       for (i = 0; deflibs[i]; i++)
+                               strlist_append(&late_linker_flags, deflibs[i]);
+               }
+       }
+       if (!nostartfiles) {
+               if (Bstatic) {
+                       b = CRTBEGIN_T;
+                       e = CRTEND_T;
+               } else if (shared /* || pieflag */) {
+                       b = CRTBEGIN_S;
+                       e = CRTEND_S;
+               }  else {
+                       b = CRTBEGIN;
+                       e = CRTEND;
+               }
+               strap(&middle_linker_flags, &crtdirs, b, 'p');
+               strap(&late_linker_flags, &crtdirs, e, 'a');
+               strap(&middle_linker_flags, &crtdirs, CRTI, 'p');
+               strap(&late_linker_flags, &crtdirs, CRTN, 'a');
+#ifdef os_win32
+               /*
+                * On Win32 Cygwin/MinGW runtimes, the profiling code gcrtN.o
+                * comes in addition to crtN.o or dllcrtN.o
+                */
+               if (pgflag)
+                       strap(&middle_linker_flags, &crtdirs, GCRT0, 'p');
+               if (shared == 0)
+                       b = CRT0;
+               else
+                       b = CRT0_S;     /* dllcrtN.o */
+               strap(&middle_linker_flags, &crtdirs, b, 'p');
+#else
+               if (shared == 0) {
+                       if (pgflag)
+                               b = GCRT0;
+#ifdef notyet
+                       else if (pieflag)
+                               b = SCRT0;
+#endif
+                       else
+                               b = CRT0;
+                       strap(&middle_linker_flags, &crtdirs, b, 'p');
+               }
+#endif
+       }
+}
+
+#ifdef _WIN32
+char *
+win32pathsubst(char *s)
+{
+       char env[1024];
+       DWORD len;
+
+       len = ExpandEnvironmentStrings(s, env, sizeof(env));
+       if (len == 0 || len > sizeof(env))
+               errorx(8, "ExpandEnvironmentStrings failed, len %lu", len);
+
+       len--;  /* skip nil */
+       while (len-- > 0 && (env[len] == '/' || env[len] == '\\'))
+               env[len] = '\0';
+
+       return xstrdup(env);
+}
+
+char *
+win32commandline(struct strlist *l)
+{
+       const struct string *s;
+       char *cmd;
+       char *p;
+       int len;
+       int j, k;
+
+       len = 0;
+       STRLIST_FOREACH(s, l) {
+               len++;
+               for (j = 0; s->value[j] != '\0'; j++) {
+                       if (s->value[j] == '\"') {
+                               for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
+                                       len++;
+                               len++;
+                       }
+                       len++;
+               }
+               for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
+                       len++;
+               len++;
+               len++;
+       }
+
+       p = cmd = xmalloc(len);
+
+       STRLIST_FOREACH(s, l) {
+               *p++ = '\"';
+               for (j = 0; s->value[j] != '\0'; j++) {
+                       if (s->value[j] == '\"') {
+                               for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
+                                       *p++ = '\\';
+                               *p++ = '\\';
+                       }
+                       *p++ = s->value[j];
+               }
+               for (k = j-1; k >= 0 && s->value[k] == '\\'; k--)
+                       *p++ = '\\';
+               *p++ = '\"';
+               *p++ = ' ';
+       }
+       p[-1] = '\0';
+
+       return cmd;
+}
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/Makefile.in b/lang/pcc/pcc/cc/ccom/Makefile.in
new file mode 100644 (file)
index 0000000..eb1214a
--- /dev/null
@@ -0,0 +1,219 @@
+#      $Id: Makefile.in,v 1.49 2016/03/08 18:42:13 ragge Exp $
+#
+# Makefile.in for ccom
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+CC = @CC@
+EXEEXT = @EXEEXT@
+BINPREFIX = @BINPREFIX@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -D_ISOC99_SOURCE \
+       -Dos_$(TARGOS) -Dmach_$(TARGMACH) \
+       -I$(srcdir) -I$(builddir) -I$(top_builddir) -I$(MIPDIR) -I$(MDIR) \
+       -I$(top_srcdir)/os/$(TARGOS) -I$(COMMONDIR)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LFLAGS =
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+TARGOS = @targos@
+TARGOSVER = @targosver@
+TARGMACH = @targmach@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+CCOM=$(BINPREFIX)ccom$(EXEEXT)
+CC0=$(BINPREFIX)cc0$(EXEEXT)
+CC1=$(BINPREFIX)cc1$(EXEEXT)
+CF0=@CF0@
+CF1=@CF1@
+
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+MIPDIR=$(top_srcdir)/mip
+COMMONDIR=$(top_srcdir)/common
+
+DEST=@CCNAMES@
+MANPAGE=$(BINPREFIX)ccom
+MKEXT=mkext$(EXEEXT)
+
+all: $(DEST)
+
+OBJS=  builtins.o cgram.o code.o common.o compat.o dwarf.o external.o  \
+       gcc_compat.o init.o inline.o local.o local2.o main.o            \
+       match.o optim.o optim2.o order.o pftn.o reader.o                \
+       regs.o scan.o stabs.o symtabs.o table.o trees.o unicode.o
+
+OBJS0=  builtins.o cgram.o code.o common.o compat.o dwarf.o external.o \
+       gcc_compat.o init.o inline.o local.o main.o                     \
+       optim.o pftn.o                                                  \
+       scan.o stabs.o symtabs.o trees.o unicode.o
+
+OBJS1=  common2.o compat.o external.o                                  \
+       local2.o main2.o                                                \
+       match.o optim2.o order.o reader.o                               \
+       regs.o table.o
+
+
+LOBJS= mkext.lo common.lo table.lo
+
+HDRS=  $(srcdir)/pass1.h $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h        \
+       $(MDIR)/macdefs.h $(MIPDIR)/node.h $(COMMONDIR)/compat.h        \
+       $(COMMONDIR)/unicode.h
+
+#
+# round 1: generate external.[ch], cgram.[ch] & scan.c
+#
+
+$(LOBJS): $(HDRS)
+
+mkext.lo: $(MIPDIR)/mkext.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c
+
+common.lo: $(MIPDIR)/common.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c
+
+table.lo: $(MDIR)/table.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c
+
+$(MKEXT): $(LOBJS)
+       $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS)
+
+external.c: $(MKEXT)
+       $(builddir)/$(MKEXT)
+
+cgram.c: $(srcdir)/cgram.y
+       $(YACC) $(YFLAGS) -d $(srcdir)/cgram.y
+       mv -f y.tab.c cgram.c
+       mv -f y.tab.h cgram.h
+
+scan.c: $(srcdir)/scan.l
+       $(LEX) $(LFLAGS) $(srcdir)/scan.l
+       mv -f $(LEX_OUTPUT_ROOT).c scan.c
+
+#
+# round 2: compile $(OBJS)
+#
+
+$(OBJS): $(HDRS) external.c cgram.c
+
+builtins.o: $(srcdir)/builtins.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/builtins.c
+
+cgram.o: cgram.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ cgram.c
+
+code.o: $(MDIR)/code.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/code.c
+
+common.o: $(MIPDIR)/common.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c
+
+common2.o: $(MIPDIR)/common.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c
+
+compat.o: $(COMMONDIR)/compat.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c
+
+dwarf.o: $(srcdir)/dwarf.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/dwarf.c
+
+external.o: external.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c
+
+gcc_compat.o: $(srcdir)/gcc_compat.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/gcc_compat.c
+
+init.o: $(srcdir)/init.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c
+
+inline.o: $(srcdir)/inline.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/inline.c
+
+local.o: $(MDIR)/local.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local.c
+
+local2.o: $(MDIR)/local2.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c
+
+main.o: $(srcdir)/main.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c
+
+main2.o: $(srcdir)/main.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c
+
+match.o: $(MIPDIR)/match.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c
+
+optim.o: $(srcdir)/optim.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/optim.c
+
+optim2.o: $(MIPDIR)/optim2.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c
+
+order.o: $(MDIR)/order.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c
+
+pftn.o: $(srcdir)/pftn.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/pftn.c
+
+reader.o: $(MIPDIR)/reader.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c
+
+regs.o: $(MIPDIR)/regs.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c
+
+scan.o: scan.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ scan.c
+
+stabs.o: $(srcdir)/stabs.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/stabs.c
+
+symtabs.o: $(srcdir)/symtabs.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/symtabs.c
+
+table.o: $(MDIR)/table.c
+       $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c
+
+trees.o: $(srcdir)/trees.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/trees.c
+
+unicode.o: $(COMMONDIR)/unicode.c
+       $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/unicode.c
+
+#
+# round 3: build $(DEST)
+#
+
+$(CCOM): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+$(CC0):        $(OBJS0)
+       $(CC) $(LDFLAGS) $(OBJS0) -o $@ $(LIBS)
+
+$(CC1):        $(OBJS1)
+       $(CC) $(LDFLAGS) $(OBJS1) -o $@ $(LIBS)
+
+install: $(DEST)
+       test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)"
+       $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir)
+       test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1"
+       $(INSTALL_DATA) $(srcdir)/ccom.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1
+
+clean:
+       rm -f $(DEST) $(OBJS0) $(OBJS1) $(MKEXT) $(LOBJS) \
+       $(LEX_OUTPUT_ROOT).c scan.c y.tab.[ch] cgram.[ch] external.[ch]
+
+distclean: clean
+       rm -f Makefile
diff --git a/lang/pcc/pcc/cc/ccom/builtins.c b/lang/pcc/pcc/cc/ccom/builtins.c
new file mode 100644 (file)
index 0000000..e5b393e
--- /dev/null
@@ -0,0 +1,1057 @@
+/*     $Id: builtins.c,v 1.67 2016/03/05 15:31:24 ragge Exp $  */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+#define        ccopy p1tcopy
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef NO_C_BUILTINS
+
+extern int dimfuncnt;
+/*
+ * replace an alloca function with direct allocation on stack.
+ * return a destination temp node.
+ */
+static P1ND *
+builtin_alloca(const struct bitable *bt, P1ND *a)
+{
+       P1ND *t, *u;
+
+#ifdef notyet
+       if (xnobuiltins)
+               return NULL;
+#endif
+
+       t = tempnode(0, VOID|PTR, 0, 0);
+       u = tempnode(regno(t), VOID|PTR, 0, 0);
+       spalloc(t, a, SZCHAR);
+       return u;
+}
+
+/*
+ * Determine if a value is known to be constant at compile-time and
+ * hence that PCC can perform constant-folding on expressions involving
+ * that value.
+ */
+static P1ND *
+builtin_constant_p(const struct bitable *bt, P1ND *a)
+{
+       P1ND *f;
+       int isconst;
+
+       p1walkf(a, putjops, 0);
+       for (f = a; f->n_op == COMOP; f = f->n_right)
+               ;
+       isconst = nncon(f);
+       p1tfree(a);
+       return bcon(isconst);
+}
+
+/*
+ * Hint to the compiler whether this expression will evaluate true or false.
+ * Just ignored for now.
+ */
+static P1ND *
+builtin_expect(const struct bitable *bt, P1ND *a)
+{
+       P1ND *f;
+
+       if (a && a->n_op == CM) {
+               p1tfree(a->n_right);
+               f = a->n_left;
+               p1nfree(a);
+               a = f;
+       }
+
+       return a;
+}
+
+/*
+ * Take integer absolute value.
+ * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1)))
+ */
+static P1ND *
+builtin_abs(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p, *q, *r, *t, *t2, *t3;
+       int tmp1, tmp2, shift;
+
+       if (a->n_type != INT)
+               a = cast(a, INT, 0);
+
+       if (a->n_op == ICON) {
+               if (glval(a) < 0)
+                       slval(a, -glval(a));
+               p = a;
+       } else {
+               t = tempnode(0, a->n_type, a->n_df, a->n_ap);
+               tmp1 = regno(t);
+               p = buildtree(ASSIGN, t, a);
+
+               t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
+               shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1;
+               q = buildtree(RS, t, bcon(shift));
+
+               t2 = tempnode(0, a->n_type, a->n_df, a->n_ap);
+               tmp2 = regno(t2);
+               q = buildtree(ASSIGN, t2, q);
+
+               t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
+               t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
+               t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
+               r = buildtree(MINUS, buildtree(ER, t, t2), t3);
+
+               p = buildtree(COMOP, p, buildtree(COMOP, q, r));
+       }
+
+       return p;
+}
+
+#define        cmop(x,y) buildtree(COMOP, x, y)
+#define        lblnod(l) nlabel(l)
+
+#ifndef TARGET_BSWAP
+static P1ND *
+builtin_bswap16(const struct bitable *bt, P1ND *a)
+{
+       P1ND *f, *t1, *t2;
+
+       t1 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255)), bcon(8));
+       t2 = buildtree(AND, buildtree(RS, a, bcon(8)), bcon(255));
+       f = buildtree(OR, t1, t2);
+       return f;
+}
+
+static P1ND *
+builtin_bswap32(const struct bitable *bt, P1ND *a)
+{
+       P1ND *f, *t1, *t2, *t3, *t4;
+
+       t1 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255)), bcon(24));
+       t2 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255 << 8)), bcon(8));
+       t3 = buildtree(AND, buildtree(RS, ccopy(a), bcon(8)), bcon(255 << 8));
+       t4 = buildtree(AND, buildtree(RS, a, bcon(24)), bcon(255));
+       f = buildtree(OR, buildtree(OR, t1, t2), buildtree(OR, t3, t4));
+       return f;
+}
+
+static P1ND *
+builtin_bswap64(const struct bitable *bt, P1ND *a)
+{
+       P1ND *f, *t1, *t2, *t3, *t4, *t5, *t6, *t7, *t8;
+
+#define        X(x) xbcon(x, NULL, ctype(ULONGLONG))
+       t1 = buildtree(LS, buildtree(AND, ccopy(a), X(255)), bcon(56));
+       t2 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 8)), bcon(40));
+       t3 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 16)), bcon(24));
+       t4 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 24)), bcon(8));
+       t5 = buildtree(AND, buildtree(RS, ccopy(a), bcon(8)), X(255 << 24));
+       t6 = buildtree(AND, buildtree(RS, ccopy(a), bcon(24)), X(255 << 16));
+       t7 = buildtree(AND, buildtree(RS, ccopy(a), bcon(40)), X(255 << 8));
+       t8 = buildtree(AND, buildtree(RS, a, bcon(56)), X(255));
+       f = buildtree(OR,
+           buildtree(OR, buildtree(OR, t1, t2), buildtree(OR, t3, t4)),
+           buildtree(OR, buildtree(OR, t5, t6), buildtree(OR, t7, t8)));
+       return f;
+#undef X
+}
+
+#endif
+
+#ifndef TARGET_CXZ
+/*
+ * Find number of beginning 0's in a word of type t.
+ * t should be deunsigned.
+ */
+static P1ND *
+builtin_cxz(P1ND *a, TWORD t, int isclz)
+{
+       P1ND *t101, *t102;
+       P1ND *rn, *p;
+       int l15, l16, l17;
+       int sz;
+
+       t = ctype(t);
+       sz = (int)tsize(t, 0, 0);
+
+       t101 = tempnode(0, INT, 0, 0);
+       t102 = tempnode(0, t, 0, 0);
+       l15 = getlab();
+       l16 = getlab();
+       l17 = getlab();
+       rn = buildtree(ASSIGN, ccopy(t102), a);
+       rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0)));
+       rn = cmop(rn, lblnod(l16));
+
+       p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15));
+       rn = cmop(rn, p);
+       if (isclz) {
+               p = buildtree(CBRANCH,
+                   buildtree(GE, ccopy(t102), bcon(0)), bcon(l17));
+       } else {
+               p = buildtree(CBRANCH,
+                   buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)),
+                   bcon(0)), bcon(l17));
+       }
+       rn = cmop(rn, p);
+
+       rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0));
+
+       rn = cmop(rn, lblnod(l17));
+       rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1)));
+
+       rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1)));
+
+       rn = cmop(rn, block(GOTO, bcon(l16), NULL, INT, 0, 0));
+       rn = cmop(rn, lblnod(l15));
+       return cmop(rn, t101);
+}
+
+static P1ND *
+builtin_clz(const struct bitable *bt, P1ND *a)
+{
+       return builtin_cxz(a, INT, 1);
+}
+
+static P1ND *
+builtin_clzl(const struct bitable *bt, P1ND *a)
+{
+       return builtin_cxz(a, LONG, 1);
+}
+
+static P1ND *
+builtin_clzll(const struct bitable *bt, P1ND *a)
+{
+       return builtin_cxz(a, LONGLONG, 1);
+}
+
+static P1ND *
+builtin_ctz(const struct bitable *bt, P1ND *a)
+{
+       return builtin_cxz(a, INT, 0);
+}
+
+static P1ND *
+builtin_ctzl(const struct bitable *bt, P1ND *a)
+{
+       return builtin_cxz(a, LONG, 0);
+}
+
+static P1ND *
+builtin_ctzll(const struct bitable *bt, P1ND *a)
+{
+       return builtin_cxz(a, LONGLONG, 0);
+}
+#endif
+
+#ifndef TARGET_ERA
+static P1ND *
+builtin_era(const struct bitable *bt, P1ND *a)
+{
+       return a;       /* Just pass through */
+}
+#endif
+
+#ifndef TARGET_FFS
+/*
+ * Find number of beginning 0's in a word of type t.
+ * t should be deunsigned.
+ */
+static P1ND *
+builtin_ff(P1ND *a, TWORD t)
+{
+       P1ND *t101, *t102;
+       P1ND *rn, *p;
+       int l15, l16, l17;
+       int sz;
+
+       t = ctype(t);
+       sz = (int)tsize(t, 0, 0)+1;
+
+       t101 = tempnode(0, INT, 0, 0);
+       t102 = tempnode(0, t, 0, 0);
+       l15 = getlab();
+       l16 = getlab();
+       l17 = getlab();
+       rn = buildtree(ASSIGN, ccopy(t101), bcon(0));
+       rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a));
+
+       p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15));
+       rn = cmop(rn, p);
+
+       rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1)));
+
+       rn = cmop(rn, lblnod(l16));
+
+       p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15));
+       rn = cmop(rn, p);
+
+       p = buildtree(CBRANCH,
+           buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)),
+           bcon(0)), bcon(l17));
+       rn = cmop(rn, p);
+
+       rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0));
+
+       rn = cmop(rn, lblnod(l17));
+       rn = cmop(rn, buildtree(RSEQ, t102, bcon(1)));
+
+       rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1)));
+
+       rn = cmop(rn, block(GOTO, bcon(l16), NULL, INT, 0, 0));
+       rn = cmop(rn, lblnod(l15));
+       return cmop(rn, t101);
+}
+
+static P1ND *
+builtin_ffs(const struct bitable *bt, P1ND *a)
+{
+       return builtin_ff(a, INT);
+}
+
+static P1ND *
+builtin_ffsl(const struct bitable *bt, P1ND *a)
+{
+       return builtin_ff(a, LONG);
+}
+
+static P1ND *
+builtin_ffsll(const struct bitable *bt, P1ND *a)
+{
+       return builtin_ff(a, LONGLONG);
+}
+#endif
+
+/*
+ * Get size of object, if possible.
+ * 0 = whole object, 1 == closest object.  Return -1 if not available.
+ * 2 == max of rem object, 3 == min of rem obj.  Return 0 if not available.
+ */
+static P1ND *
+builtin_object_size(const struct bitable *bt, P1ND *a)
+{
+       CONSZ v = icons(a->n_right);
+       int r;
+
+       if (v < 0 || v > 3)
+               uerror("arg2 must be between 0 and 3");
+       r = v < 2 ? -1 : 0;
+
+       a = p1nfree(a);
+#ifdef notyet
+       if (ISPTR(a->n_type)) {
+               a = buildtree(UMUL, a, 0);
+               a = optloop(a);
+               a = doszof(a);
+       }
+#else
+       p1walkf(a, putjops, 0); /* if ?: exists */
+       p1tfree(a);
+#endif
+       return xbcon(r, NULL, bt->rt);
+}
+
+#ifndef TARGET_STDARGS
+static P1ND *
+builtin_stdarg_start(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p, *q;
+       int sz;
+
+       /* must first deal with argument size; use int size */
+       p = a->n_right;
+       if (p->n_type < INT) {
+               sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap));
+       } else
+               sz = 1;
+
+       /* do the real job */
+       p = buildtree(ADDROF, p, NULL); /* address of last arg */
+#ifdef BACKAUTO
+       p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */
+#else
+       p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */
+#endif
+       q = block(NAME, NULL, NULL, PTR+VOID, 0, 0); /* create cast node */
+       q = buildtree(CAST, q, p); /* cast to void * (for assignment) */
+       p = q->n_right;
+       p1nfree(q->n_left);
+       p1nfree(q);
+       p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */
+       p1nfree(a);
+       return p;
+}
+
+static P1ND *
+builtin_va_arg(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p, *q, *r, *rv;
+       int sz, nodnum;
+
+       /* create a copy to a temp node of current ap */
+       p = ccopy(a->n_left);
+       q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+       nodnum = regno(q);
+       rv = buildtree(ASSIGN, q, p);
+
+       r = a->n_right;
+       sz = (int)tsize(r->n_type, r->n_df, r->n_ap);
+#ifdef MYVAARGSZ
+       SETOFF(sz, MYVAARGSZ);
+#endif
+       sz /= SZCHAR;
+       /* add one to ap */
+#ifdef BACKAUTO
+       rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz)));
+#else
+#error fix wrong eval order in builtin_va_arg
+       ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz)));
+#endif
+
+       p1nfree(a->n_right);
+       p1nfree(a);
+       r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap);
+       return buildtree(COMOP, rv, buildtree(UMUL, r, NULL));
+
+}
+
+static P1ND *
+builtin_va_end(const struct bitable *bt, P1ND *a)
+{
+       return a; /* may have side effects */
+}
+
+static P1ND *
+builtin_va_copy(const struct bitable *bt, P1ND *a)
+{
+       P1ND *f;
+
+       f = buildtree(ASSIGN, a->n_left, a->n_right);
+       p1nfree(a);
+       return f;
+}
+#endif /* TARGET_STDARGS */
+
+/*
+ * For unimplemented "builtin" functions, try to invoke the
+ * non-builtin name
+ */
+static P1ND *
+binhelp(P1ND *a, TWORD rt, char *n)
+{
+       P1ND *f = block(NAME, NULL, NULL, INT, 0, 0);
+       int oblvl = blevel;
+
+       blevel = 0;
+       f->n_sp = lookup(addname(n), SNORMAL);
+       blevel = oblvl;
+       if (f->n_sp->sclass == SNULL) {
+               f->n_sp->sclass = EXTERN;
+               f->n_sp->stype = INCREF(rt)+(FTN-PTR);
+               f->n_sp->sdf = permalloc(sizeof(union dimfun));
+               dimfuncnt++;
+               f->n_sp->sdf->dfun = NULL;
+       }
+       f->n_type = f->n_sp->stype;
+       f = clocal(f);
+       return buildtree(CALL, f, a);
+}
+
+static P1ND *
+builtin_unimp(const struct bitable *bt, P1ND *a)
+{
+       return binhelp(a, bt->rt, &bt->name[10]);
+}
+
+#if 0
+static P1ND *
+builtin_unimp_f(P1ND *f, P1ND *a, TWORD rt)
+{
+       return binhelp(f, a, rt, f->n_sp->sname);
+}
+#endif
+
+#ifndef TARGET_PREFETCH
+static P1ND *
+builtin_prefetch(const struct bitable *bt, P1ND *a)
+{
+       p1tfree(a);
+       return bcon(0);
+}
+#endif
+
+/*
+ * check if compatible types.
+ * XXX - all enum are considered equal types
+ */
+static P1ND *
+builtin_tc(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p;
+
+       if (a == NULL || a->n_op != CM ||
+           a->n_left->n_op != TYPE || a->n_right->n_op != TYPE)
+               uerror("bad %s arg", bt->name);
+       
+       p = bcon(a->n_left->n_type == a->n_right->n_type);
+       p1nfree(a->n_left);
+       p1nfree(a->n_right);
+       p1nfree(a);
+       return p;
+}
+
+static void
+putinlbl(P1ND *p, void *arg)
+{
+       if (p->n_op == COMOP && p->n_left->n_op == GOTO) {
+               int v = (int)glval(p->n_left->n_left);
+               send_passt(IP_DEFLAB, v+1);
+       }
+}
+
+/*
+ * Similar to ?:
+ */
+static P1ND *
+builtin_ce(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p;
+
+       if (a == NULL || a->n_op != CM ||
+           a->n_left->n_op != CM || a->n_left->n_left->n_op == CM)
+               uerror("bad %s arg", bt->name);
+       if (nncon(a->n_left->n_left) == 0)
+               uerror("arg not constant");
+       if (glval(a)) {
+               p = a->n_left->n_right;
+               a->n_left->n_op = UMUL; /* for p1tfree() */
+               p1walkf(a->n_right, putinlbl, 0);
+       } else {
+               p = a->n_right;
+               a->n_op = UMUL; /* for p1tfree() */
+               p1walkf(a->n_left->n_right, putinlbl, 0);
+       }
+       p1tfree(a);
+       return p;
+       
+}
+
+static P1ND *
+builtin_classify_type(const struct bitable *bt, P1ND *a)
+{
+       TWORD t = a->n_type;
+       int rv;
+
+       if (t == BOOL)
+               rv = 4;
+       else if (t == CHAR || t == UCHAR)
+               rv = 2;
+       else if (t <= ULONGLONG)
+               rv = 1;
+       else if (t == STRTY)
+               rv = 12;
+       else if (t == UNIONTY)
+               rv = 13;
+       else if (ISPTR(t))
+               rv = 5;
+       else if (ISFTY(t))
+               rv = 8;
+       else if (ISFTN(t))
+               rv = 10;
+       else if (ISCTY(t))
+               rv = 9;
+       else
+               rv = -1;
+
+       p1tfree(a);
+       return bcon(rv);
+}
+
+
+#ifndef TARGET_ISMATH
+/*
+ * Handle the builtin macros for the math functions is*
+ * To get something that is be somewhat generic assume that 
+ * isnan() is a real function and that cast of a NaN type 
+ * to double will still be a NaN.
+ */
+static P1ND *
+mtisnan(P1ND *p)
+{
+
+       return binhelp(cast(ccopy(p), DOUBLE, 0), INT, "isnan");
+}
+
+static TWORD
+mtcheck(P1ND *p)
+{
+       TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type;
+
+       if ((t1 >= FLOAT && t1 <= LDOUBLE) ||
+           (t2 >= FLOAT && t2 <= LDOUBLE))
+               return MAX(t1, t2);
+       return 0;
+}
+
+static P1ND *
+builtin_isunordered(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p;
+
+       if (mtcheck(a) == 0)
+               return bcon(0);
+
+       p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+       p1tfree(a);
+       return p;
+}
+static P1ND *
+builtin_isany(P1ND *a, TWORD rt, int cmpt)
+{
+       P1ND *p, *q;
+       TWORD t;
+
+       if ((t = mtcheck(a)) == 0)
+               return bcon(0);
+       p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+       p = buildtree(NOT, p, NULL);
+       q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0),
+           cast(ccopy(a->n_right), t, 0));
+       p = buildtree(ANDAND, p, q);
+       p1tfree(a);
+       return p;
+}
+static P1ND *
+builtin_isgreater(const struct bitable *bt, P1ND *a)
+{
+       return builtin_isany(a, bt->rt, GT);
+}
+static P1ND *
+builtin_isgreaterequal(const struct bitable *bt, P1ND *a)
+{
+       return builtin_isany(a, bt->rt, GE);
+}
+static P1ND *
+builtin_isless(const struct bitable *bt, P1ND *a)
+{
+       return builtin_isany(a, bt->rt, LT);
+}
+static P1ND *
+builtin_islessequal(const struct bitable *bt, P1ND *a)
+{
+       return builtin_isany(a, bt->rt, LE);
+}
+static P1ND *
+builtin_islessgreater(const struct bitable *bt, P1ND *a)
+{
+       P1ND *p, *q, *r;
+       TWORD t;
+
+       if ((t = mtcheck(a)) == 0)
+               return bcon(0);
+       p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+       p = buildtree(NOT, p, NULL);
+       q = buildtree(GT, cast(ccopy(a->n_left), t, 0),
+           cast(ccopy(a->n_right), t, 0));
+       r = buildtree(LT, cast(ccopy(a->n_left), t, 0),
+           cast(ccopy(a->n_right), t, 0));
+       q = buildtree(OROR, q, r);
+       p = buildtree(ANDAND, p, q);
+       p1tfree(a);
+       return p;
+}
+#endif
+
+/*
+ * Math-specific builtins that expands to constants.
+ * Versions here are for IEEE FP, vax needs its own versions.
+ */
+#if TARGET_ENDIAN == TARGET_LE
+static const unsigned char vFLOAT[] = { 0, 0, 0x80, 0x7f };
+static const unsigned char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
+#ifdef LDBL_128
+static const unsigned char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
+#else /* LDBL_80 */
+static const unsigned char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f,0,0,0,0,0,0 };
+#endif
+static const unsigned char nFLOAT[] = { 0, 0, 0xc0, 0x7f };
+static const unsigned char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
+#ifdef LDBL_128
+static const unsigned char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f };
+#else /* LDBL_80 */
+static const unsigned char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f,0,0,0,0,0,0 };
+#endif
+#else
+static const unsigned char vFLOAT[] = { 0x7f, 0x80, 0, 0 };
+static const unsigned char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
+#ifdef LDBL_128
+static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#else /* LDBL_80 */
+static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#endif
+static const unsigned char nFLOAT[] = { 0x7f, 0xc0, 0, 0 };
+static const unsigned char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
+#ifdef LDBL_128
+static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#else /* LDBL_80 */
+static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#endif
+#endif
+
+#define VALX(typ,TYP) {                                                \
+       typ d;                                                  \
+       int x;                                                  \
+       P1ND *f;                                                \
+       x = MIN(sizeof(n ## TYP), sizeof(d));                   \
+       memcpy(&d, v ## TYP, x);                                \
+       f = block(FCON, NULL, NULL, TYP, NULL, 0);              \
+       f->n_dcon = stmtalloc(sizeof(FLT));                     \
+       f->n_dcon->fp = d;                                      \
+       return f;                                               \
+}
+
+static P1ND *
+builtin_huge_valf(const struct bitable *bt, P1ND *a) VALX(float,FLOAT)
+static P1ND *
+builtin_huge_val(const struct bitable *bt, P1ND *a) VALX(double,DOUBLE)
+static P1ND *
+builtin_huge_vall(const struct bitable *bt, P1ND *a) VALX(long double,LDOUBLE)
+
+#define        builtin_inff    builtin_huge_valf
+#define        builtin_inf     builtin_huge_val
+#define        builtin_infl    builtin_huge_vall
+
+/*
+ * Return NANs, if reasonable.
+ */
+static P1ND *
+builtin_nanx(const struct bitable *bt, P1ND *a)
+{
+
+       if (a == NULL || a->n_op == CM) {
+               uerror("%s bad argument", bt->name);
+               a = bcon(0);
+       } else if (a->n_op == STRING && *a->n_name == '\0') {
+               a->n_op = FCON;
+               a->n_type = bt->rt;
+               if (sizeof(nLDOUBLE) < sizeof(long double))
+                       cerror("nLDOUBLE too small");
+               a->n_dcon = stmtalloc(sizeof(FLT));
+               memcpy(&a->n_dcon->fp, nLDOUBLE, sizeof(long double));
+       } else
+               a = binhelp(eve(a), bt->rt, &bt->name[10]);
+       return a;
+}
+
+#ifndef NO_COMPLEX
+static P1ND *
+builtin_cir(const struct bitable *bt, P1ND *a)
+{
+       char *n;
+
+       if (a == NULL || a->n_op == CM) {
+               uerror("wrong argument count to %s", bt->name);
+               return bcon(0);
+       }
+
+       n = addname(bt->name[1] == 'r' ? "__real" : "__imag");
+       return cast(structref(a, DOT, n), bt->rt, 0);
+}
+
+#endif
+
+/*
+ * Target defines, to implement target versions of the generic builtins
+ */
+#ifndef TARGET_MEMCMP
+#define        builtin_memcmp builtin_unimp
+#endif
+#ifndef TARGET_MEMCPY
+#define        builtin_memcpy builtin_unimp
+#endif
+#ifndef TARGET_MEMPCPY
+#define        builtin_mempcpy builtin_unimp
+#endif
+#ifndef TARGET_MEMSET
+#define        builtin_memset builtin_unimp
+#endif
+
+/* Reasonable type of size_t */
+#ifndef SIZET
+#if SZINT == SZSHORT
+#define        SIZET UNSIGNED
+#elif SZLONG > SZINT
+#define SIZET ULONG
+#else
+#define SIZET UNSIGNED
+#endif
+#endif
+
+static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT };
+static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT };
+static TWORD allocat[] = { SIZET };
+static TWORD expectt[] = { LONG, LONG };
+static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT };
+static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT };
+static TWORD strchrt[] = { CHAR|PTR, INT };
+static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD nant[] = { CHAR|PTR };
+static TWORD bitt[] = { UNSIGNED };
+static TWORD bsw16t[] = { USHORT };
+static TWORD bitlt[] = { ULONG };
+static TWORD bitllt[] = { ULONGLONG };
+static TWORD abst[] = { INT };
+static TWORD fmaxft[] = { FLOAT, FLOAT };
+static TWORD fmaxt[] = { DOUBLE, DOUBLE };
+static TWORD fmaxlt[] = { LDOUBLE, LDOUBLE };
+static TWORD scalbnft[] = { FLOAT, INT };
+static TWORD scalbnt[] = { DOUBLE, INT };
+static TWORD scalbnlt[] = { LDOUBLE, INT };
+
+static const struct bitable bitable[] = {
+       /* gnu universe only */
+       { "alloca", builtin_alloca, BTGNUONLY, 1, allocat, VOID|PTR },
+
+#ifndef NO_COMPLEX
+       /* builtins for complex operations */
+       { "crealf", builtin_cir, BTNOPROTO, 1, 0, FLOAT },
+       { "creal", builtin_cir, BTNOPROTO, 1, 0, DOUBLE },
+       { "creall", builtin_cir, BTNOPROTO, 1, 0, LDOUBLE },
+       { "cimagf", builtin_cir, BTNOPROTO, 1, 0, FLOAT },
+       { "cimag", builtin_cir, BTNOPROTO, 1, 0, DOUBLE },
+       { "cimagl", builtin_cir, BTNOPROTO, 1, 0, LDOUBLE },
+#endif
+       /* always existing builtins */
+       { "__builtin___memcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR },
+       { "__builtin___mempcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR },
+       { "__builtin___memmove_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR },
+       { "__builtin___memset_chk", builtin_unimp, 0, 4, memsett, VOID|PTR },
+
+       { "__builtin___strcat_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR },
+       { "__builtin___strcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR },
+       { "__builtin___stpcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR },
+       { "__builtin___strncat_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR },
+       { "__builtin___strncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR },
+       { "__builtin___stpncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR },
+
+       { "__builtin___printf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___fprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___sprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___snprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vfprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vsprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vsnprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+
+       { "__builtin_alloca", builtin_alloca, 0, 1, allocat, VOID|PTR },
+       { "__builtin_abs", builtin_abs, 0, 1, abst, INT },
+       { "__builtin_bswap16", builtin_bswap16, 0, 1, bsw16t, USHORT },
+       { "__builtin_bswap32", builtin_bswap32, 0, 1, bitt, UNSIGNED },
+       { "__builtin_bswap64", builtin_bswap64, 0, 1, bitllt, ULONGLONG },
+       { "__builtin_choose_expr", builtin_ce, BTNOPROTO|BTNORVAL, 0, 0, 0 },
+       { "__builtin_clz", builtin_clz, 0, 1, bitt, INT },
+       { "__builtin_clzl", builtin_clzl, 0, 1, bitlt, INT },
+       { "__builtin_clzll", builtin_clzll, 0, 1, bitllt, INT },
+       { "__builtin_ctz", builtin_ctz, 0, 1, bitt, INT },
+       { "__builtin_ctzl", builtin_ctzl, 0, 1, bitlt, INT },
+       { "__builtin_ctzll", builtin_ctzll, 0, 1, bitllt, INT },
+       { "__builtin_extract_return_addr", builtin_era, 0, 1, memcpyt, VOID|PTR },
+       { "__builtin_ffs", builtin_ffs, 0, 1, bitt, INT },
+       { "__builtin_ffsl", builtin_ffsl, 0, 1, bitlt, INT },
+       { "__builtin_ffsll", builtin_ffsll, 0, 1, bitllt, INT },
+       { "__builtin_popcount", builtin_unimp, 0, 1, bitt, UNSIGNED },
+       { "__builtin_popcountl", builtin_unimp, 0, 1, bitlt, ULONG },
+       { "__builtin_popcountll", builtin_unimp, 0, 1, bitllt, ULONGLONG },
+
+       { "__builtin_classify_type", builtin_classify_type, 0, 1, 0, INT },
+       { "__builtin_constant_p", builtin_constant_p, 0, 1, 0, INT },
+       { "__builtin_copysignf", builtin_unimp, 0, 2, fmaxft, FLOAT },
+       { "__builtin_copysign", builtin_unimp, 0, 2, fmaxt, DOUBLE },
+       { "__builtin_copysignl", builtin_unimp, 0, 2, fmaxlt, LDOUBLE },
+       { "__builtin_expect", builtin_expect, 0, 2, expectt, LONG },
+       { "__builtin_memcmp", builtin_memcmp, 0, 3, memcpyt, INT },
+       { "__builtin_memcpy", builtin_memcpy, 0, 3, memcpyt, VOID|PTR },
+       { "__builtin_mempcpy", builtin_mempcpy, 0, 3, memcpyt, VOID|PTR },
+       { "__builtin_memset", builtin_memset, 0, 3, memsett, VOID|PTR },
+       { "__builtin_fabsf", builtin_unimp, 0, 1, fmaxft, FLOAT },
+       { "__builtin_fabs", builtin_unimp, 0, 1, fmaxt, DOUBLE },
+       { "__builtin_fabsl", builtin_unimp, 0, 1, fmaxlt, LDOUBLE },
+       { "__builtin_fmaxf", builtin_unimp, 0, 2, fmaxft, FLOAT },
+       { "__builtin_fmax", builtin_unimp, 0, 2, fmaxt, DOUBLE },
+       { "__builtin_fmaxl", builtin_unimp, 0, 2, fmaxlt, LDOUBLE },
+       { "__builtin_huge_valf", builtin_huge_valf, 0, 0, 0, FLOAT },
+       { "__builtin_huge_val", builtin_huge_val, 0, 0, 0, DOUBLE },
+       { "__builtin_huge_vall", builtin_huge_vall, 0, 0, 0, LDOUBLE },
+       { "__builtin_inff", builtin_inff, 0, 0, 0, FLOAT },
+       { "__builtin_inf", builtin_inf, 0, 0, 0, DOUBLE },
+       { "__builtin_infl", builtin_infl, 0, 0, 0, LDOUBLE },
+       { "__builtin_isgreater", builtin_isgreater, 0, 2, NULL, INT },
+       { "__builtin_isgreaterequal", builtin_isgreaterequal, 0, 2, NULL, INT },
+       { "__builtin_isinff", builtin_unimp, 0, 1, fmaxft, INT },
+       { "__builtin_isinf", builtin_unimp, 0, 1, fmaxt, INT },
+       { "__builtin_isinfl", builtin_unimp, 0, 1, fmaxlt, INT },
+       { "__builtin_isless", builtin_isless, 0, 2, NULL, INT },
+       { "__builtin_islessequal", builtin_islessequal, 0, 2, NULL, INT },
+       { "__builtin_islessgreater", builtin_islessgreater, 0, 2, NULL, INT },
+       { "__builtin_isnanf", builtin_unimp, 0, 1, fmaxft, INT },
+       { "__builtin_isnan", builtin_unimp, 0, 1, fmaxt, INT },
+       { "__builtin_isnanl", builtin_unimp, 0, 1, fmaxlt, INT },
+       { "__builtin_isunordered", builtin_isunordered, 0, 2, NULL, INT },
+       { "__builtin_logbf", builtin_unimp, 0, 1, fmaxft, FLOAT },
+       { "__builtin_logb", builtin_unimp, 0, 1, fmaxt, DOUBLE },
+       { "__builtin_logbl", builtin_unimp, 0, 1, fmaxlt, LDOUBLE },
+       { "__builtin_nanf", builtin_nanx, BTNOEVE, 1, nant, FLOAT },
+       { "__builtin_nan", builtin_nanx, BTNOEVE, 1, nant, DOUBLE },
+       { "__builtin_nanl", builtin_nanx, BTNOEVE, 1, nant, LDOUBLE },
+       { "__builtin_object_size", builtin_object_size, BTNOPROTO, 2, memsett, SIZET },
+       { "__builtin_prefetch", builtin_prefetch, 0, 1, memsett, VOID },
+       { "__builtin_scalbnf", builtin_unimp, 0, 2, scalbnft, FLOAT },
+       { "__builtin_scalbn", builtin_unimp, 0, 2, scalbnt, DOUBLE },
+       { "__builtin_scalbnl", builtin_unimp, 0, 2, scalbnlt, LDOUBLE },
+       { "__builtin_strcmp", builtin_unimp, 0, 2, strcmpt, INT },
+       { "__builtin_strcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR },
+       { "__builtin_stpcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR },
+       { "__builtin_strchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR },
+       { "__builtin_strlen", builtin_unimp, 0, 1, strcmpt, SIZET },
+       { "__builtin_strrchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR },
+       { "__builtin_strncpy", builtin_unimp, 0, 3, strncpyt, CHAR|PTR },
+       { "__builtin_strncat", builtin_unimp, 0, 3, strncpyt, CHAR|PTR },
+       { "__builtin_strcspn", builtin_unimp, 0, 2, strcspnt, SIZET },
+       { "__builtin_strspn", builtin_unimp, 0, 2, strspnt, SIZET },
+       { "__builtin_strstr", builtin_unimp, 0, 2, strcmpt, CHAR|PTR },
+       { "__builtin_strpbrk", builtin_unimp, 0, 2, strpbrkt, CHAR|PTR },
+       { "__builtin_types_compatible_p", builtin_tc, BTNOPROTO, 2, 0, INT },
+#ifndef TARGET_STDARGS
+       { "__builtin_stdarg_start", builtin_stdarg_start, 0, 2, 0, VOID },
+       { "__builtin_va_start", builtin_stdarg_start, 0, 2, 0, VOID },
+       { "__builtin_va_arg", builtin_va_arg, BTNORVAL|BTNOPROTO, 2, 0, 0 },
+       { "__builtin_va_end", builtin_va_end, 0, 1, 0, VOID },
+       { "__builtin_va_copy", builtin_va_copy, 0, 2, 0, VOID },
+#endif
+       { "__builtin_dwarf_cfa", builtin_cfa, 0, 0, 0, VOID|PTR },
+       { "__builtin_frame_address",
+           builtin_frame_address, 0, 1, bitt, VOID|PTR },
+       { "__builtin_return_address",
+           builtin_return_address, 0, 1, bitt, VOID|PTR },
+#ifdef TARGET_BUILTINS
+       TARGET_BUILTINS
+#endif
+};
+
+/*
+ * Check and cast arguments for builtins.
+ */
+static int
+acnt(P1ND *a, int narg, TWORD *tp)
+{
+       P1ND *q;
+       TWORD t;
+
+       if (a == NULL)
+               return narg;
+       for (; a->n_op == CM; a = a->n_left, narg--) {
+               if (tp == NULL)
+                       continue;
+               q = a->n_right;
+               t = ctype(tp[narg-1]);
+               if (q->n_type == t)
+                       continue;
+               a->n_right = ccast(q, t, 0, NULL, 0);
+       }
+
+       /* Last arg is ugly to deal with */
+       if (narg == 1 && tp != NULL && a->n_type != tp[0]) {
+               q = p1alloc();
+               *q = *a;
+               q = ccast(q, ctype(tp[0]), 0, NULL, 0);
+               *a = *q;
+               p1nfree(q);
+       }
+       return narg != 1;
+}
+
+P1ND *
+builtin_check(struct symtab *sp, P1ND *a)
+{
+       const struct bitable *bt;
+
+       if (sp->soffset < 0 ||
+           sp->soffset >= (int)(sizeof(bitable)/sizeof(bitable[0])))
+               cerror("builtin_check");
+
+       bt = &bitable[sp->soffset];
+       if ((bt->flags & BTNOEVE) == 0 && a != NULL)
+               a = eve(a);
+       if (((bt->flags & BTNOPROTO) == 0) && acnt(a, bt->narg, bt->tp)) {
+               uerror("wrong argument count to %s", bt->name);
+               return bcon(0);
+       }
+       return (*bt->fun)(bt, a);
+}
+
+/*
+ * Put all builtin functions into the global symbol table.
+ */
+void
+builtin_init()
+{
+       const struct bitable *bt;
+       P1ND *p = block(TYPE, 0, 0, 0, 0, 0);
+       struct symtab *sp;
+       int i, d_debug;
+
+       d_debug = ddebug;
+       ddebug = 0;
+       for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) {
+               bt = &bitable[i];
+               if ((bt->flags & BTGNUONLY) && xgnu99 == 0 && xgnu89 == 0)
+                       continue; /* not in c99 universe, at least for now */
+               sp = lookup(addname(bt->name), 0);
+               if (bt->rt == 0 && (bt->flags & BTNORVAL) == 0)
+                       cerror("function '%s' has no return type", bt->name);
+               p->n_type = INCREF(bt->rt) + (FTN-PTR);
+               p->n_df = memset(permalloc(sizeof(union dimfun)), 0,
+                   sizeof(union dimfun));
+               dimfuncnt++;
+               p->n_sp = sp;
+               defid(p, EXTERN);
+               sp->soffset = i;
+               sp->sflags |= SBUILTIN;
+       }
+       p1nfree(p);
+       ddebug = d_debug;
+}
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/ccom.1 b/lang/pcc/pcc/cc/ccom/ccom.1
new file mode 100644 (file)
index 0000000..1aafa96
--- /dev/null
@@ -0,0 +1,465 @@
+.\"    $Id: ccom.1,v 1.31 2014/06/06 14:59:46 plunky Exp $
+.\"
+.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
+.\"
+.\" Permission to use, copy, modify, and/or distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
+.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
+.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+.\" THIS SOFTWARE.
+.\"
+.Dd March 22, 2012
+.Dt CCOM 1
+.Os
+.Sh NAME
+.Nm ccom
+.Nd C compiler
+.Sh SYNOPSIS
+.Nm
+.Op Fl gkpsv
+.Op Fl f Ar features
+.Op Fl m Ar options
+.Op Fl W Ar warnings
+.Op Fl X Ar flags
+.Op Fl x Ar settings
+.Op Fl Z Ar flags
+.Op infile
+.Op outfile
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a C compiler.
+The frontend is usually
+.Xr pcc 1 .
+It is
+.Em not
+intended to be run directly.
+.Nm
+reads the C source from
+.Ar infile
+or standard input and writes the assembler source
+to
+.Ar outfile
+or to standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f Ar feature
+Enable language features.
+Multiple
+.Fl f
+options can be given, the following features are supported:
+.Bl -tag -width Ds
+.It Sy stack-protector
+Enable stack smashing protection.
+Currently the same as
+.Sy stack-protector-all .
+.It Sy stack-protector-all
+Enable stack smashing protection for all functions.
+.It Sy pack-struct Ns Oo = Ns Ar n Oc
+Specify maximum alignment for structure members, similar to a #pragma pack
+statement at the start of the file.
+If no value is given, the default is 1.
+.It Sy freestanding
+Emit code for a freestanding environment.
+Currently not implemented.
+.El
+.It Fl g
+Include debugging information in the output code for use by
+symbolic and source-level debuggers.
+Currently this uses the
+.Sy stabs
+format, encoding information in
+.Em s Ns ymbol Em tab Ns le entrie Ns Em s.
+.It Fl k
+Generate PIC code.
+.It Fl m Ar option
+Target-specific options, used in machine-dependent code.
+Multiple
+.Fl m
+options can be given, the following options are supported:
+.Bl -tag -width PowerPC
+.It AMD64
+.It ARM
+.Sy little-endian ,
+.Sy big-endian ,
+.Sy fpe=fpa ,
+.Sy fpe=vpf ,
+.Sy soft-float ,
+.Sy arch=armv1 ,
+.Sy arch=armv2 ,
+.Sy arch=armv2a ,
+.Sy arch=armv3 ,
+.Sy arch=armv4 ,
+.Sy arch=armv4t ,
+.Sy arch=armv4tej ,
+.Sy arch=armv5 ,
+.Sy arch=armv5te ,
+.Sy arch=armv5tej ,
+.Sy arch=armv6 ,
+.Sy arch=armv6t2 ,
+.Sy arch=armv6kz ,
+.Sy arch=armv6k No \*(Am
+.Sy arch=armv7 .
+.It HPPA
+.It i386
+.It M16C
+.It MIPS
+.Sy little-endian No \*(Am
+.Sy big-endian .
+.It NOVA
+.It PDP-10
+.It PDP-11
+.It PowerPC
+.Sy little-endian ,
+.Sy big-endian ,
+.Sy soft-float No \*(Am
+.Sy hard-float .
+.It Sparc64
+.It VAX
+.El
+.It Fl p
+Generate profiling code.
+.It Fl s
+Print statistics to standard error when complete.
+This includes:
+name table entries, name string size, permanent allocated memory,
+temporary allocated memory, lost memory, argument list unions,
+dimension/function unions, struct/union/enum blocks, inline node count,
+inline control blocks, and permanent symtab entries.
+.\" TODO: explain units for above?
+.It Fl v
+Display version.
+.It Fl W Ar warning
+Do some basic checks and emit warnings about possible coding problems.
+Multiple
+.Fl W
+options can be given, the following warnings are supported:
+.Bl -tag -width Ds
+.It Sy error Ns Oo = Ns Ar warning Oc
+Enable
+.Ar warning ,
+and treat it as an error condition.
+If a specific warning is not given, producing any warning will cause an error.
+.It Sy deprecated-declarations
+Report whenever a symbol marked with the
+.Sq deprecated
+attribute is used.
+This warning is enabled by default.
+.It Sy implicit-function-declaration
+(TODO) Require explicit prototypes for all called functions.
+.It Sy implicit-int
+(TODO) Warn when a function declaration lacks a type.
+.It Sy missing-prototypes
+Require explicit prototypes for all global function definitions.
+.It Sy pointer-sign
+Warn when pointer operations are done with mismatched signed and unsigned values.
+.It Sy sign-compare
+(TODO) Warn about comparisons between signed and unsigned values.
+.It Sy strict-prototypes
+(TODO) Require that function prototypes are strictly C99.
+.It Sy shadow
+Report when a local variable shadows something from a higher scope.
+.It Sy truncate
+Report when integer values may be implicitly truncated to fit a smaller type.
+.It Sy unknown-pragmas
+Report unhandled pragma statements.
+.It Sy unreachable-code
+Report statements that cannot be executed.
+.El
+.Pp
+Any of the above may be prefixed with
+.Dq no-
+in order to disable the effect.
+.\"
+.It Fl X Ar flags
+C specific debugging where
+.Ar flags
+is one or more of the following:
+.Pp
+.Bl -tag -compact -width Ds
+.It Sy b
+Building of parse trees
+.It Sy d
+Declarations (using multiple
+.Sy d
+flags gives more output)
+.It Sy e
+Pass1 trees at exit
+.It Sy i
+Initializations
+.It Sy n
+Memory allocations
+.It Sy o
+Turn off optimisations
+.It Sy p
+Prototypes
+.It Sy s
+Inlining
+.It Sy t
+Type conversions
+.It Sy x
+Target-specific flag, used in machine-dependent code
+.El
+.\"
+.It Fl x Ar setting
+Enable
+.Ar setting
+in the compiler.
+Multiple
+.Fl x
+options can be given, the following settings are supported:
+.Bl -tag -width Ds
+.It Sy ccp
+Apply sparse conditional constant propagation techniques for optimization.
+Currently not implemented.
+.It Sy dce
+Do dead code elimination.
+.It Sy deljumps
+Delete redundant jumps and dead code.
+.It Sy gnu89
+.It Sy gnu99
+Use GNU C semantics rather than C99 for some things.
+Currently only inline.
+.It Sy inline
+Replace calls to functions marked with an inline specifier with a copy
+of the actual function.
+.It Sy ssa
+Convert statements into static single assignment form for optimization.
+Not yet finished.
+.It Sy tailcall
+Enable optimization of tail-recursion functions.
+Currently not implemented.
+.It Sy temps
+Locate automatic variables into registers where possible, for further
+optimization by the register allocator.
+.It Sy uchar
+Treat character constants as unsigned values.
+.El
+.\"
+.It Fl Z Ar flags
+Code generator (pass2) specific debugging where
+.Ar flags
+is one or more of the following:
+.Pp
+.Bl -tag -compact -width Ds
+.It Sy b
+Basic block and SSA building
+.It Sy c
+Code printout
+.It Sy e
+Trees when entering pass2
+.It Sy f
+Instruction matcher, may provide much output
+.It Sy g
+Print flow graphs
+.It Sy n
+Memory allocation
+.It Sy o
+Instruction generator
+.It Sy r
+Register allocator
+.It Sy s
+Shape matching in instruction generator
+.It Sy t
+Type matching in instruction generator
+.It Sy u
+Sethi-Ullman computations
+.It Sy x
+Target-specific flag, used in machine-dependent code
+.El
+.El
+.Sh PRAGMAS
+Input lines starting with a
+.Dq #pragma
+directive can be used to modify behaviour of
+.Nm
+during compilation.
+All tokens up to the first unescaped newline are considered part
+of the pragma command, with the following operations being recognized:
+.Bl -tag -width Ds
+.It Sy STDC
+Standard C99 operator follows.
+Currently no C99 operations are implemented, and any directives starting
+with this token will be silently ignored.
+.It Sy GCC diagnostic Ar effect Qq Ar option
+GNU C compatibility.
+Alter the effects of compiler diagnostics.
+The required
+.Ar effect
+should be stated as
+.Sy warning ,
+.Sy error
+or
+.Sy ignored ,
+followed by the compiler diagnostic
+.Ar option
+in double quotes.
+For example, to force unknown pragmas to always generate an error,
+a standard header might include
+.Bd -literal -offset 2n
+#pragma GCC diagnostic error "-Wunknown-pragmas"
+.Ed
+.It Sy GCC poison Ar identifier ...
+GNU C compatibility.
+Cause an error if any of the following
+.Ar identifier Ns s
+subsequently appear in the code
+.Pq but not in any macro expansions .
+Currently not implemented.
+.It Sy GCC system_header
+GNU C compatibility.
+Currently not implemented.
+.It Sy GCC visibility
+GNU C compatibility.
+Currently not implemented.
+.It Sy pack Ns Pq Op Ar n
+Set the default maximum alignment for structures and unions, such that
+members will have their natural alignment requirements clamped at this
+value and may be stored misaligned.
+If
+.Ar n
+is not given, the alignment is reset to the target default.
+.It Sy pack Ns Pq Sy push Ns Op , Ar n
+Push the current pack setting onto an internal stack then, if
+.Ar n
+is given, change the default alignment for structures and unions.
+Currently not implemented.
+.It Sy pack Ns Pq Sy pop
+Change the pack setting to the most recently pushed value, and remove
+that setting from the stack.
+Currently not implemented.
+.It Sy packed Op Ar n
+Set the maximum alignment for the structure or union defined
+in the current statement.
+If
+.Ar n
+is not given, the default value of 1 is used.
+.Pq Currently this works except Ar n is not used
+.It Sy aligned Op Ar n
+Set the minimum alignment for the structure or union defined
+in the current statement.
+.It Sy rename Ar name
+Provide an alternative
+.Ar name
+which will be used to reference the object declared in the current statement.
+.It Sy weak Ar name Ns Op = Ns Ar alias
+Mark
+.Ar name
+as a weak rather than a global symbol, to allow its definition to be
+overridden at link time.
+If an
+.Ar alias
+is given, this will be used as the default value of
+.Ar name .
+.It Sy ident
+Currently not implemented.
+.El
+.Lp
+and the following target-specific operations are handled by
+machine-dependent code:
+.Bl -tag -width Ds
+.It Sy tls
+For AMD64 and i386 targets, the variable declared in the current statement
+will be referenced via the
+.Dq thread-local storage
+mechanism.
+.It Sy init
+For AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a
+function declaration, generate a reference in the
+.Sy .ctors
+section, enabling library code to call the function prior to entering
+.Fn main .
+.It Sy fini
+For AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a
+function declaration, generate a reference in the
+.Sy .dtors
+section, enabling library code to call the function when
+.Fn main
+returns or the
+.Fn exit
+function is called.
+.It Sy section Ar name
+For AMD64, ARM, HPPA and i386 targets, place the subsequent code in the named
+section.
+.Pq This is currently broken .
+.It Sy alias Ar name
+For AMD64, HPPA and i386 targets, emit assembler instructions providing an
+alias for the symbol defined by the current statement.
+.It Sy stdcall
+For i386 targets, enable
+.Dq stdcall
+semantics during code generation, where function arguments are passed on
+the stack in right-to-left order, and the callee is responsible for adjusting
+the stack pointer before returning.
+Any function result is passed in the EAX register.
+On win32, the function name is postfixed with an
+.Dq @
+and the size of the stack adjustment.
+.It Sy cdecl
+For i386 targets, enable
+.Dq cdecl
+semantics during code generation, where function arguments are passed on
+the stack in right-to-left order, and the caller is responsible for cleaning
+up the stack after the function returns.
+Any function result is passed in the EAX register.
+This is the default.
+.It Sy fastcall
+For i386-win32 targets, enable
+.Dq fastcall
+semantics during code generation.
+.Po
+Currently this is equivalent to
+.Sy stdcall ,
+which is likely wrong
+.Pc .
+.It Sy dllimport
+For i386-win32 targets, references to the external symbol defined by
+the current statement will be made via indirect access through a
+location identified by the symbol name prefixed with
+.Dq __imp_ .
+.It Sy dllexport
+For i386-win32 targets, the external symbol declared by the current
+statement will be exported as an indirect reference to be
+accessed with
+.Sy dllimport .
+The global locator will be the symbol name prefixed with
+.Dq __imp_ .
+Currently this is not completely implemented.
+.El
+.Pp
+Any unknown
+.Dq #pragma
+directives will be ignored unless the
+.Fl Wunknown-pragmas
+diagnostic is in effect.
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr cpp 1 ,
+.Xr pcc 1
+.Sh HISTORY
+The
+.Nm
+compiler is based on the original Portable C Compiler by
+.An "S. C. Johnson" ,
+written in the late 70's.
+Even though much of the compiler has been rewritten
+.Pq about 50% of the frontend code and 80% of the backend ,
+some of the basics still remain.
+Most is written by
+.An "Anders Magnusson" ,
+with the exception of the data-flow analysis part and
+the SSA conversion code which is written by
+.An "Peter A Jonsson" ,
+and the Mips port that were written as part of a project
+by undergraduate students at Lulea University of Technology.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
diff --git a/lang/pcc/pcc/cc/ccom/cgram.y b/lang/pcc/pcc/cc/ccom/cgram.y
new file mode 100644 (file)
index 0000000..86ae5b6
--- /dev/null
@@ -0,0 +1,2629 @@
+/*     $Id: cgram.y,v 1.414 2016/03/05 15:31:24 ragge Exp $    */
+
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Comments for this grammar file. Ragge 021123
+ *
+ * ANSI support required rewrite of the function header and declaration
+ * rules almost totally.
+ *
+ * The lex/yacc shared keywords are now split from the keywords used
+ * in the rest of the compiler, to simplify use of other frontends.
+ */
+
+/*
+ * At last count, there were 5 shift/reduce and no reduce/reduce conflicts
+ * All are accounted for;
+ * One is "dangling else"
+ * Two is in attribute parsing
+ * Two is in ({ }) parsing
+ */
+
+/*
+ * Token used in C lex/yacc communications.
+ */
+%token C_STRING        /* a string constant */
+%token C_ICON          /* an integer constant */
+%token C_FCON          /* a floating point constant */
+%token C_NAME          /* an identifier */
+%token C_TYPENAME      /* a typedef'd name */
+%token C_ANDAND        /* && */
+%token C_OROR          /* || */
+%token C_GOTO          /* unconditional goto */
+%token C_RETURN        /* return from function */
+%token C_TYPE          /* a type */
+%token C_CLASS         /* a storage class */
+%token C_ASOP          /* assignment ops */
+%token C_RELOP         /* <=, <, >=, > */
+%token C_EQUOP         /* ==, != */
+%token C_DIVOP         /* /, % */
+%token C_SHIFTOP       /* <<, >> */
+%token C_INCOP         /* ++, -- */
+%token C_UNOP          /* !, ~ */
+%token C_STROP         /* ., -> */
+%token C_STRUCT
+%token C_IF
+%token C_ELSE
+%token C_SWITCH
+%token C_BREAK
+%token C_CONTINUE
+%token C_WHILE 
+%token C_DO
+%token C_FOR
+%token C_DEFAULT
+%token C_CASE
+%token C_SIZEOF
+%token C_ENUM
+%token C_ELLIPSIS
+%token C_QUALIFIER
+%token C_FUNSPEC
+%token C_ASM
+%token NOMATCH
+%token C_TYPEOF        /* COMPAT_GCC */
+%token C_ATTRIBUTE     /* COMPAT_GCC */
+%token PCC_OFFSETOF
+%token GCC_DESIG
+
+/* C11 keywords */
+%token C_STATICASSERT
+%token C_ALIGNAS
+%token C_ALIGNOF
+%token C_GENERIC
+%token C_ATOMIC
+
+/*
+ * Precedence
+ */
+%left ','
+%right '=' C_ASOP
+%right '?' ':'
+%left C_OROR
+%left C_ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left C_EQUOP
+%left C_RELOP
+%left C_SHIFTOP
+%left '+' '-'
+%left '*' C_DIVOP
+%right C_UNOP
+%right C_INCOP C_SIZEOF
+%left '[' '(' C_STROP
+%{
+# include "pass1.h"
+# include <stdarg.h>
+# include <string.h>
+# include <stdlib.h>
+
+int fun_inline;        /* Reading an inline function */
+int oldstyle;  /* Current function being defined */
+static struct symtab *xnf;
+extern int enummer, tvaloff, inattr;
+extern struct rstack *rpole;
+static int alwinl;
+P1ND *cftnod;
+static int attrwarn = 1;
+
+#define        NORETYP SNOCREAT /* no return type, save in unused field in symtab */
+
+struct genlist {
+       struct genlist *next;
+       P1ND *p;
+       TWORD t;
+};
+
+       P1ND *bdty(int op, ...);
+static void fend(void);
+static void fundef(P1ND *tp, P1ND *p);
+static void olddecl(P1ND *p, P1ND *a);
+static struct symtab *init_declarator(P1ND *tn, P1ND *p, int assign, P1ND *a,
+       char *as);
+static void resetbc(int mask);
+static void swend(void);
+static void addcase(P1ND *p);
+#ifdef GCC_COMPAT
+static void gcccase(P1ND *p, P1ND *);
+#endif
+static struct attr *gcc_attr_wrapper(P1ND *p);
+static void adddef(void);
+static void savebc(void);
+static void swstart(int, TWORD);
+static void genswitch(int, TWORD, struct swents **, int);
+static char *mkpstr(char *str);
+static struct symtab *clbrace(P1ND *);
+static P1ND *cmop(P1ND *l, P1ND *r);
+static P1ND *xcmop(P1ND *out, P1ND *in, P1ND *str);
+static void mkxasm(char *str, P1ND *p);
+static P1ND *xasmop(char *str, P1ND *p);
+static P1ND *biop(int op, P1ND *l, P1ND *r);
+static void flend(void);
+static P1ND *gccexpr(int bn, P1ND *q);
+static char * simname(char *s);
+static P1ND *tyof(P1ND *);     /* COMPAT_GCC */
+static P1ND *voidcon(void);
+static P1ND *funargs(P1ND *p);
+static void oldargs(P1ND *p);
+static void uawarn(P1ND *p, char *s);
+static int con_e(P1ND *p);
+static void dainit(P1ND *d, P1ND *a);
+static P1ND *tymfix(P1ND *p);
+static P1ND *namekill(P1ND *p, int clr);
+static P1ND *aryfix(P1ND *p);
+static P1ND *dogen(struct genlist *g, P1ND *e);
+static struct genlist *newgen(P1ND *p, P1ND *q);
+static struct genlist *addgen(struct genlist *g, struct genlist *h);
+
+static void savlab(int);
+static void xcbranch(P1ND *, int);
+extern int *mkclabs(void);
+
+#define        TYMFIX(inp) { \
+       P1ND *pp = inp; \
+       inp = tymerge(pp->n_left, pp->n_right); \
+       p1nfree(pp->n_left); p1nfree(pp); }
+
+struct xalloc;
+extern struct xalloc *bkpole, *sapole;
+extern int cbkp, cstp;
+extern int usdnodes;
+struct bks {
+       struct xalloc *ptr;
+       int off;
+};
+
+/*
+ * State for saving current switch state (when nested switches).
+ */
+struct savbc {
+       struct savbc *next;
+       int brklab;
+       int contlab;
+       int flostat;
+       int swx;
+       struct xalloc *bkptr;
+       int bkoff;
+       struct xalloc *stptr;
+       int stoff;
+       int numnode;
+} *savbc, *savctx;
+
+%}
+
+%union {
+       TWORD type;
+       int intval;
+       P1ND *nodep;
+       struct symtab *symp;
+       struct rstack *rp;
+       char *strp;
+       struct bks *bkp;
+       FLT *flt;
+       struct genlist *g;
+}
+
+       /* define types */
+%start ext_def_list
+
+%type <intval> ifelprefix ifprefix whprefix forprefix doprefix switchpart
+               xbegin
+%type <nodep> e .e term enum_dcl struct_dcl cast_type declarator
+               elist type_sq cf_spec merge_attribs e2 ecq
+               parameter_declaration abstract_declarator initializer
+               parameter_type_list parameter_list
+               declaration_specifiers designation
+               specifier_qualifier_list merge_specifiers
+               identifier_list arg_param_list type_qualifier_list
+               designator_list designator xasm oplist oper cnstr funtype
+               typeof attribute attribute_specifier /* COMPAT_GCC */
+               attribute_list attr_spec_list attr_var /* COMPAT_GCC */
+
+%type <g>      gen_ass_list gen_assoc
+%type <strp>   string C_STRING GCC_DESIG svstr
+%type <rp>     str_head
+%type <symp>   xnfdeclarator clbrace enum_head
+
+%type <intval>  C_STRUCT C_RELOP C_DIVOP C_SHIFTOP
+               C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP
+
+%type <type>   C_TYPE C_QUALIFIER C_CLASS C_FUNSPEC
+
+%type <nodep>   C_ICON
+
+%type <flt>    C_FCON 
+
+%type <strp>   C_NAME C_TYPENAME
+%%
+
+ext_def_list:     ext_def_list external_def
+               | { ftnend(); }
+               ;
+
+external_def:     funtype kr_args compoundstmt { fend(); }
+               |  declaration  { blevel = 0; symclear(0); }
+               |  asmstatement ';'
+               |  ';'
+               |  error { blevel = 0; }
+               ;
+
+funtype:         /* no type given */ declarator {
+                   fundef(mkty(INT, 0, 0), $1);
+                   cftnsp->sflags |= NORETYP;
+               }
+               | declaration_specifiers declarator { fundef($1,$2); }
+               ;
+
+kr_args:         /* empty */
+               | arg_dcl_list
+               ;
+
+/*
+ * Returns a node pointer or NULL, if no types at all given.
+ * Type trees are checked for correctness and merged into one
+ * type node in typenode().
+ */
+declaration_specifiers:
+                  merge_attribs { $$ = typenode($1); }
+               ;
+
+merge_attribs:    type_sq { $$ = $1; }
+               |  type_sq merge_attribs { $$ = cmop($2, $1); }
+               |  cf_spec { $$ = $1; }
+               |  cf_spec merge_attribs { $$ = cmop($2, $1); }
+               ;
+
+type_sq:          C_TYPE { $$ = mkty($1, 0, 0); }
+               |  C_TYPENAME { 
+                       struct symtab *sp = lookup($1, 0);
+                       if (sp->stype == ENUMTY) {
+                               sp->stype = strmemb(sp->sap)->stype;
+                       }
+                       $$ = mkty(sp->stype, sp->sdf, sp->sap);
+                       $$->n_sp = sp;
+               }
+               |  struct_dcl { $$ = $1; }
+               |  enum_dcl { $$ = $1; }
+               |  C_QUALIFIER { $$ = block(QUALIFIER, NULL, NULL, 0, 0, 0); $$->n_qual = $1; }
+               |  attribute_specifier { $$ = biop(ATTRIB, $1, 0); }
+               |  C_ALIGNAS '(' e ')' { 
+                       $$ = biop(ALIGN, NULL, NULL);
+                       slval($$, con_e($3));
+               }
+               |  C_ALIGNAS '(' cast_type ')' {
+                       TYMFIX($3);
+                       $$ = biop(ALIGN, NULL, NULL);
+                       slval($$, talign($3->n_type, $3->n_ap)/SZCHAR);
+                       p1tfree($3);
+               }
+               |  C_ATOMIC { uerror("_Atomic not supported"); $$ = bcon(0); }
+               |  C_ATOMIC '(' cast_type ')' {
+                       uerror("_Atomic not supported"); $$ = $3;
+               }
+               |  typeof { $$ = $1; }
+               ;
+
+cf_spec:          C_CLASS { $$ = block(CLASS, NULL, NULL, $1, 0, 0); }
+               |  C_FUNSPEC { $$ = block(FUNSPEC, NULL, NULL, $1, 0, 0); }
+               ;
+
+typeof:                   C_TYPEOF '(' e ')' { $$ = tyof(eve($3)); }
+               |  C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); }
+               ;
+
+attribute_specifier :
+                  C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; }
+ /*COMPAT_GCC*/        ;
+
+attribute_list:           attribute
+               |  attribute ',' attribute_list { $$ = cmop($3, $1); }
+               ;
+
+attribute:        {
+#ifdef GCC_COMPAT
+                        $$ = voidcon();
+#endif
+               }
+               |  C_NAME { $$ = bdty(NAME, $1); }
+               |  C_NAME '(' elist ')' {
+                       $$ = bdty($3 == NULL ? UCALL : CALL, bdty(NAME, $1), $3);
+               }
+               ;
+
+/*
+ * Adds a pointer list to front of the declarators.
+ */
+declarator:       '*' declarator { $$ = bdty(UMUL, $2); }
+               |  '*' type_qualifier_list declarator {
+                       $$ = $2;
+                       $$->n_left = $3;
+               }
+               |  C_NAME { $$ = bdty(NAME, $1); }
+               |  '(' attr_spec_list declarator ')' {
+                       $$ = $3;
+                       $$->n_ap = attr_add($$->n_ap, gcc_attr_wrapper($2));
+               }
+               |  '(' declarator ')' { $$ = $2; }
+               |  declarator '[' ecq ']' { $$ = biop(LB, $1, $3); }
+               |  declarator '(' parameter_type_list ')' {
+                       $$ = bdty(CALL, $1, $3);
+               }
+               |  declarator '(' identifier_list ')' {
+                       $$ = bdty(CALL, $1, $3);
+                       oldstyle = 1;
+               }
+               |  declarator '(' ')' { $$ = bdty(UCALL, $1); }
+               ;
+
+ecq:              maybe_r { $$ = bcon(NOOFFSET); }
+               |  e  { $$ = $1; }
+               |  r e { $$ = $2; }
+               |  c maybe_r e { $$ = $3; }
+               |  r c e { $$ = $3; }
+               |  '*' { $$ = bcon(NOOFFSET); }
+               |  r '*' { $$ = bcon(NOOFFSET); }
+               ;
+
+r:               C_QUALIFIER {
+                       if ($1 != 0)
+                               uerror("bad qualifier");
+               }
+               ;
+
+c:               C_CLASS {
+                       if ($1 != STATIC)
+                               uerror("bad class keyword");
+               }
+               ;
+
+type_qualifier_list:
+                  C_QUALIFIER { $$ = biop(UMUL, 0, 0); $$->n_qual = $1; }
+               |  type_qualifier_list C_QUALIFIER {
+                       $$ = $1;
+                       $$->n_qual |= $2;
+               }
+               |  attribute_specifier {
+                       $$ = block(UMUL, NULL, NULL, 0, 0, gcc_attr_wrapper($1));
+               }
+               |  type_qualifier_list attribute_specifier {
+                       $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($2));
+               }
+               ;
+
+identifier_list:   C_NAME { $$ = bdty(NAME, $1); oldargs($$); }
+               |  identifier_list ',' C_NAME {
+                       $$ = cmop($1, bdty(NAME, $3));
+                       oldargs($$->n_right);
+               }
+               ;
+
+/*
+ * Returns as parameter_list, but can add an additional ELLIPSIS node.
+ */
+parameter_type_list:
+                  parameter_list { $$ = $1; }
+               |  parameter_list ',' C_ELLIPSIS {
+                       $$ = cmop($1, biop(ELLIPSIS, NULL, NULL));
+               }
+               ;
+
+/*
+ * Returns a linked lists of nodes of op CM with parameters on
+ * its right and additional CM nodes of its left pointer.
+ * No CM nodes if only one parameter.
+ */
+parameter_list:           parameter_declaration { $$ = $1; }
+               |  parameter_list ',' parameter_declaration {
+                       $$ = cmop($1, $3);
+               }
+               ;
+
+/*
+ * Returns a node pointer to the declaration.
+ */
+parameter_declaration:
+                  declaration_specifiers declarator attr_var {
+                       if (glval($1) != SNULL && glval($1) != REGISTER)
+                               uerror("illegal parameter class");
+                       $$ = block(TYMERGE, $1, $2, INT, 0,
+                           gcc_attr_wrapper($3));
+               }
+               |  declaration_specifiers abstract_declarator { 
+                       $1->n_ap = attr_add($1->n_ap, $2->n_ap);
+                       $$ = block(TYMERGE, $1, $2, INT, 0, 0);
+               }
+               |  declaration_specifiers {
+                       $$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0);
+               }
+               ;
+
+abstract_declarator:
+                  '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); }
+               |  '*' type_qualifier_list {
+                       $$ = $2;
+                       $$->n_left = bdty(NAME, NULL);
+               }
+               |  '*' abstract_declarator { $$ = bdty(UMUL, $2); }
+               |  '*' type_qualifier_list abstract_declarator {
+                       $$ = $2;
+                       $$->n_left = $3;
+               }
+               |  '(' abstract_declarator ')' { $$ = $2; }
+               |  '[' maybe_r ']' attr_var {
+                       $$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET),
+                           INT, 0, gcc_attr_wrapper($4));
+               }
+               |  '[' e ']' attr_var {
+                       $$ = block(LB, bdty(NAME, NULL), $2,
+                           INT, 0, gcc_attr_wrapper($4));
+               }
+               |  abstract_declarator '[' maybe_r ']' attr_var {
+                       $$ = block(LB, $1, bcon(NOOFFSET),
+                           INT, 0, gcc_attr_wrapper($5));
+               }
+               |  abstract_declarator '[' e ']' attr_var {
+                       $$ = block(LB, $1, $3, INT, 0, gcc_attr_wrapper($5));
+               }
+               |  '(' ')' attr_var {
+                       $$ = bdty(UCALL, bdty(NAME, NULL));
+                       $$->n_ap = gcc_attr_wrapper($3);
+               }
+               |  '(' ib2 parameter_type_list ')' attr_var {
+                       $$ = block(CALL, bdty(NAME, NULL), $3, INT, 0,
+                           gcc_attr_wrapper($5));
+               }
+               |  abstract_declarator '(' ')' attr_var {
+                       $$ = block(UCALL, $1, NULL, INT, 0, gcc_attr_wrapper($4));
+               }
+               |  abstract_declarator '(' ib2 parameter_type_list ')' attr_var {
+                       $$ = block(CALL, $1, $4, INT, 0, gcc_attr_wrapper($6));
+               }
+               ;
+
+ib2:              { }
+               ;
+
+maybe_r:          { }
+               |  C_QUALIFIER { }
+               ;
+
+/*
+ * K&R arg declaration, between ) and {
+ */
+arg_dcl_list:     arg_declaration
+               |  arg_dcl_list arg_declaration
+               ;
+
+
+arg_declaration:   declaration_specifiers arg_param_list ';' {
+                       p1nfree($1);
+               }
+               ;
+
+arg_param_list:           declarator attr_var {
+                       olddecl(block(TYMERGE, p1tcopy($<nodep>0), $1,
+                           INT, 0, 0), $2);
+               }
+               |  arg_param_list ',' declarator attr_var {
+                       olddecl(block(TYMERGE, p1tcopy($<nodep>0), $3,
+                           INT, 0, 0), $4);
+               }
+               ;
+
+/*
+ * Declarations in beginning of blocks.
+ */
+block_item_list:   block_item
+               |  block_item_list block_item
+               ;
+
+block_item:       declaration
+               |  statement { stmtfree(); }
+               ;
+
+/*
+ * Here starts the old YACC code.
+ */
+
+/*
+ * Variables are declared in init_declarator.
+ */
+declaration:      declaration_specifiers ';' { p1tfree($1); fun_inline = 0; }
+               |  declaration_specifiers init_declarator_list ';' {
+                       p1tfree($1);
+                       fun_inline = 0;
+               }
+               |  C_STATICASSERT '(' e ',' string ')' ';' {
+                       int r = con_e($3);
+                       if (r == 0) /* false */
+                               uerror($5);
+               }
+               ;
+
+/*
+ * Normal declaration of variables. curtype contains the current type node.
+ * Returns nothing, variables are declared in init_declarator.
+ */
+init_declarator_list:
+                  init_declarator { symclear(blevel); }
+               |  init_declarator_list ',' attr_var { $<nodep>$ = $<nodep>0; } init_declarator {
+                       uawarn($3, "init_declarator");
+                       symclear(blevel);
+               }
+               ;
+
+enum_dcl:         enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); }
+               |  C_ENUM C_NAME {  $$ = enumref($2); }
+               ;
+
+enum_head:        C_ENUM { $$ = enumhd(NULL); }
+               |  C_ENUM C_NAME {  $$ = enumhd($2); }
+               ;
+
+moe_list:         moe
+               |  moe_list ',' moe
+               ;
+
+moe:              C_NAME {  moedef($1); }
+               |  C_TYPENAME {  moedef($1); }
+               |  C_NAME '=' e { enummer = con_e($3); moedef($1); }
+               |  C_TYPENAME '=' e { enummer = con_e($3); moedef($1); }
+               ;
+
+struct_dcl:       str_head '{' struct_dcl_list '}' {
+                       P1ND *p;
+
+                       $$ = dclstruct($1);
+                       if (pragma_allpacked) {
+                               p = bdty(CALL, bdty(NAME, "packed"),
+                                   bcon(pragma_allpacked));
+                               $$->n_ap = attr_add($$->n_ap,gcc_attr_wrapper(p)); }
+               }
+               |  C_STRUCT attr_var C_NAME { 
+                       $$ = rstruct($3,$1);
+                       uawarn($2, "struct_dcl");
+               }
+ /*COMPAT_GCC*/        |  str_head '{' '}' { $$ = dclstruct($1); }
+               ;
+
+attr_var:         {    
+                       P1ND *q, *p;
+
+                       p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"),
+                           bcon(pragma_aligned)) : NULL;
+                       if (pragma_packed) {
+                               q = bdty(NAME, "packed");
+                               p = (p == NULL ? q : cmop(p, q));
+                       }
+                       pragma_aligned = pragma_packed = 0;
+                       $$ = p;
+               }
+ /*COMPAT_GCC*/        |  attr_spec_list
+               ;
+
+attr_spec_list:           attribute_specifier 
+               |  attr_spec_list attribute_specifier { $$ = cmop($1, $2); }
+               ;
+
+str_head:         C_STRUCT attr_var {  $$ = bstruct(NULL, $1, $2);  }
+               |  C_STRUCT attr_var C_NAME {  $$ = bstruct($3, $1, $2);  }
+               ;
+
+struct_dcl_list:   struct_declaration
+               |  struct_dcl_list struct_declaration
+               ;
+
+struct_declaration:
+                  specifier_qualifier_list struct_declarator_list optsemi {
+                       p1tfree($1);
+               }
+               ;
+
+optsemi:          ';' { }
+               |  optsemi ';' { werror("extra ; in struct"); }
+               ;
+
+specifier_qualifier_list:
+                  merge_specifiers { $$ = typenode($1); }
+               ;
+
+merge_specifiers:  type_sq merge_specifiers { $$ = cmop($2, $1); }
+               |  type_sq { $$ = $1; }
+               ;
+
+struct_declarator_list:
+                  struct_declarator { symclear(blevel); }
+               |  struct_declarator_list ',' { $<nodep>$=$<nodep>0; } 
+                       struct_declarator { symclear(blevel); }
+               ;
+
+struct_declarator: declarator attr_var {
+                       P1ND *p;
+
+                       $1 = aryfix($1);
+                       p = tymerge($<nodep>0, tymfix($1));
+                       if ($2)
+                               p->n_ap = attr_add(p->n_ap, gcc_attr_wrapper($2));
+                       soumemb(p, (char *)$1->n_sp, 0);
+                       p1tfree(p);
+               }
+               |  ':' e {
+                       int ie = con_e($2);
+                       if (fldchk(ie))
+                               ie = 1;
+                       falloc(NULL, ie, $<nodep>0);
+               }
+               |  declarator ':' e {
+                       int ie = con_e($3);
+                       if (fldchk(ie))
+                               ie = 1;
+                       if ($1->n_op == NAME) {
+                               /* XXX - tymfix() may alter $1 */
+                               tymerge($<nodep>0, tymfix($1));
+                               soumemb($1, (char *)$1->n_sp, FIELD | ie);
+                               p1nfree($1);
+                       } else
+                               uerror("illegal declarator");
+               }
+               |  declarator ':' e attr_spec_list {
+                       int ie = con_e($3);
+                       if (fldchk(ie))
+                               ie = 1;
+                       if ($1->n_op == NAME) {
+                               /* XXX - tymfix() may alter $1 */
+                               tymerge($<nodep>0, tymfix($1));
+                               if ($4)
+                                       $1->n_ap = attr_add($1->n_ap,
+                                           gcc_attr_wrapper($4));
+                               soumemb($1, (char *)$1->n_sp, FIELD | ie);
+                               p1nfree($1);
+                       } else
+                               uerror("illegal declarator");
+               }
+               | /* unnamed member */ {
+                       P1ND *p = $<nodep>0;
+                       char *c = permalloc(10);
+
+                       if (p->n_type != STRTY && p->n_type != UNIONTY)
+                               uerror("bad unnamed member type");
+                       snprintf(c, 10, "*%dFAKE", getlab());
+                       soumemb(p, c, 0);
+               }
+               ;
+
+               /* always preceeded by attributes */
+xnfdeclarator:    declarator attr_var {
+                       $$ = xnf = init_declarator($<nodep>0, $1, 1, $2, 0);
+               }
+               |  declarator C_ASM '(' svstr ')' {
+                       $$ = xnf = init_declarator($<nodep>0, $1, 1, NULL, $4);
+               }
+               ;
+
+/*
+ * Handles declarations and assignments.
+ * Returns nothing.
+ */
+init_declarator:   declarator attr_var {
+                       init_declarator($<nodep>0, $1, 0, $2, 0);
+               }
+               |  declarator C_ASM '(' svstr ')' attr_var {
+                       init_declarator($<nodep>0, $1, 0, $6, $4);
+               }
+               |  xnfdeclarator '=' e { 
+                       if ($1->sclass == STATIC || $1->sclass == EXTDEF)
+                               statinit++;
+                       simpleinit($1, eve($3));
+                       if ($1->sclass == STATIC || $1->sclass == EXTDEF)
+                               statinit--;
+                       xnf = NULL;
+               }
+               |  xnfdeclarator '=' begbr init_list optcomma '}' {
+                       endinit(0);
+                       xnf = NULL;
+               }
+ /*COMPAT_GCC*/        |  xnfdeclarator '=' begbr '}' { endinit(0); xnf = NULL; }
+               ;
+
+begbr:            '{' { beginit($<symp>-1); }
+               ;
+
+initializer:      e %prec ',' {  $$ = eve($1); }
+               |  ibrace init_list optcomma '}' { $$ = NULL; }
+               |  ibrace '}' { asginit(bcon(0)); $$ = NULL; }
+               ;
+
+init_list:        designation initializer { dainit($1, $2); }
+               |  init_list ','  designation initializer { dainit($3, $4); }
+               ;
+
+designation:      designator_list '=' { desinit($1); $$ = NULL; }
+               |  GCC_DESIG { desinit(bdty(NAME, $1)); $$ = NULL; }
+               |  '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); }
+               |  { $$ = NULL; }
+               ;
+
+designator_list:   designator { $$ = $1; }
+               |  designator_list designator { $$ = $2; $$->n_left = $1; }
+               ;
+
+designator:       '[' e ']' {
+                       int ie = con_e($2);
+                       if (ie < 0) {
+                               uerror("designator must be non-negative");
+                               ie = 0;
+                       }
+                       $$ = biop(LB, NULL, bcon(ie));
+               }
+               |  C_STROP C_TYPENAME {
+                       if ($1 != DOT)
+                               uerror("invalid designator");
+                       $$ = bdty(NAME, $2);
+               }
+               |  C_STROP C_NAME {
+                       if ($1 != DOT)
+                               uerror("invalid designator");
+                       $$ = bdty(NAME, $2);
+               }
+               ;
+
+optcomma       :       /* VOID */
+               |  ','
+               ;
+
+ibrace:                   '{' {  ilbrace(); }
+               ;
+
+/*     STATEMENTS      */
+
+compoundstmt:     begin block_item_list '}' { flend(); }
+               |  begin '}' { flend(); }
+               ;
+
+begin:           '{' {
+                       struct savbc *bc = malloc(sizeof(struct savbc));
+                       if (blevel == 1) {
+#ifdef STABS
+                               if (gflag)
+                                       stabs_line(lineno);
+#endif
+                               dclargs();
+                       }
+#ifdef STABS
+                       if (gflag && blevel > 1)
+                               stabs_lbrac(blevel+1);
+#endif
+                       ++blevel;
+                       oldstyle = 0;
+                       bc->contlab = autooff;
+                       bc->next = savctx;
+                       bc->bkptr = bkpole;
+                       bc->bkoff = cbkp;
+                       bc->stptr = sapole;
+                       bc->stoff = cstp;
+                       bc->numnode = usdnodes;
+                       usdnodes = 0;
+                       bkpole = sapole = NULL;
+                       cbkp = cstp = 0;
+                       savctx = bc;
+                       if (!isinlining && sspflag && blevel == 2)
+                               sspstart();
+               }
+               ;
+
+statement:        e ';' { ecomp(eve($1)); symclear(blevel); }
+               |  compoundstmt
+               |  ifprefix statement { plabel($1); reached = 1; }
+               |  ifelprefix statement {
+                       if ($1 != NOLAB) {
+                               plabel( $1);
+                               reached = 1;
+                       }
+               }
+               |  whprefix statement {
+                       branch(contlab);
+                       plabel( brklab );
+                       if( (flostat&FBRK) || !(flostat&FLOOP))
+                               reached = 1;
+                       else
+                               reached = 0;
+                       resetbc(0);
+               }
+               |  doprefix statement C_WHILE '(' e ')' ';' {
+                       plabel(contlab);
+                       if (flostat & FCONT)
+                               reached = 1;
+                       if (reached)
+                               cbranch(buildtree(NE, eve($5), bcon(0)),
+                                   bcon($1));
+                       else
+                               p1tfree(eve($5));
+                       plabel( brklab);
+                       reached = 1;
+                       resetbc(0);
+               }
+               |  forprefix .e ')' statement
+                       {  plabel( contlab );
+                           if( flostat&FCONT ) reached = 1;
+                           if( $2 ) ecomp( $2 );
+                           branch($1);
+                           plabel( brklab );
+                           if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1;
+                           else reached = 0;
+                           resetbc(0);
+                           blevel--;
+                           symclear(blevel);
+                           }
+               | switchpart statement
+                       { if( reached ) branch( brklab );
+                           plabel( $1 );
+                           swend();
+                           plabel( brklab);
+                           if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1;
+                           resetbc(FCONT);
+                           }
+               |  C_BREAK  ';' {
+                       if (brklab == NOLAB)
+                               uerror("illegal break");
+                       else if (reached)
+                               branch(brklab);
+                       flostat |= FBRK;
+                       reached = 0;
+               }
+               |  C_CONTINUE  ';' {
+                       if (contlab == NOLAB)
+                               uerror("illegal continue");
+                       else
+                               branch(contlab);
+                       flostat |= FCONT;
+                       goto rch;
+               }
+               |  C_RETURN  ';' {
+                       branch(retlab);
+                       if (cftnsp->stype != VOID && 
+                           (cftnsp->sflags & NORETYP) == 0 &&
+                           cftnsp->stype != VOID+FTN)
+                               uerror("return value required");
+                       rch:
+                       if (!reached)
+                               warner(Wunreachable_code);
+                       reached = 0;
+               }
+               |  C_RETURN e  ';' {
+                       P1ND *p, *q;
+
+                       p = nametree(cftnsp);
+                       p->n_type = DECREF(p->n_type);
+                       q = eve($2);
+#ifdef TARGET_TIMODE  
+                       P1ND *r;
+                       if ((r = gcc_eval_ticast(RETURN, p, q)) != NULL)
+                               q = r;
+#endif
+#ifndef NO_COMPLEX
+                       if (ANYCX(q) || ANYCX(p))
+                               q = cxret(q, p);
+                       else if (ISITY(p->n_type) || ISITY(q->n_type)) {
+                               q = imret(q, p);
+                               if (ISITY(p->n_type))
+                                       p->n_type -= (FIMAG-FLOAT);
+                               if (ISITY(q->n_type))
+                                       q->n_type -= (FIMAG-FLOAT);
+                       }
+#endif
+                       p = buildtree(RETURN, p, q);
+                       if (p->n_type == VOID) {
+                               ecomp(p->n_right);
+                       } else {
+                               if (cftnod == NULL) {
+                                       P1ND *r = tempnode(0, p->n_type,
+                                           p->n_df, p->n_ap);
+                                       cftnod = tmpalloc(sizeof(P1ND));
+                                       *cftnod = *r;
+                                       p1tfree(r);
+                               }
+                               ecomp(buildtree(ASSIGN,
+                                   p1tcopy(cftnod), p->n_right));
+                       }
+                       p1tfree(p->n_left);
+                       p1nfree(p);
+                       branch(retlab);
+                       reached = 0;
+               }
+               |  C_GOTO C_NAME ';' { gotolabel($2); goto rch; }
+               |  C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NULL)); }
+               |  asmstatement ';'
+               |   ';'
+               |  error  ';'
+               |  error '}'
+               |  label statement
+               ;
+
+asmstatement:     C_ASM mvol '(' svstr ')' { send_passt(IP_ASM, mkpstr($4)); }
+               |  C_ASM mvol '(' svstr xasm ')' { mkxasm($4, $5); }
+               ;
+
+svstr:           string { $$ = addstring($1); }
+               ;
+
+mvol:             /* empty */
+               |  C_QUALIFIER { }
+               ;
+
+xasm:             ':' oplist { $$ = xcmop($2, NULL, NULL); }
+               |  ':' oplist ':' oplist { $$ = xcmop($2, $4, NULL); }
+               |  ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); }
+               ;
+
+oplist:                   /* nothing */ { $$ = NULL; }
+               |  oper { $$ = $1; }
+               ;
+
+oper:             svstr '(' e ')' { $$ = xasmop($1, pconvert(eve($3))); }
+               |  oper ',' svstr '(' e ')' {
+                       $$ = cmop($1, xasmop($3, pconvert(eve($5))));
+               }
+               ;
+
+cnstr:            svstr { $$ = xasmop($1, bcon(0)); }
+               |  cnstr ',' svstr { $$ = cmop($1, xasmop($3, bcon(0))); }
+                ;
+
+label:            C_NAME ':' attr_var { deflabel($1, $3); reached = 1; }
+               |  C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; }
+               |  C_CASE e ':' { addcase(eve($2)); reached = 1; }
+/* COMPAT_GCC */|  C_CASE e C_ELLIPSIS e ':' {
+#ifdef GCC_COMPAT
+                       gcccase(eve($2), eve($4)); reached = 1;
+#endif
+               }
+               |  C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; }
+               ;
+
+doprefix:      C_DO {
+                       savebc();
+                       brklab = getlab();
+                       contlab = getlab();
+                       plabel(  $$ = getlab());
+                       reached = 1;
+               }
+               ;
+ifprefix:      C_IF '(' e ')' {
+                       xcbranch(eve($3), $$ = getlab());
+                       reached = 1;
+               }
+               ;
+ifelprefix:      ifprefix statement C_ELSE {
+                       if (reached)
+                               branch($$ = getlab());
+                       else
+                               $$ = NOLAB;
+                       plabel( $1);
+                       reached = 1;
+               }
+               ;
+
+whprefix:        C_WHILE  '('  e  ')' {
+                       savebc();
+                       $3 = eve($3);
+                       if ($3->n_op == ICON && glval($3) != 0)
+                               flostat = FLOOP;
+                       plabel( contlab = getlab());
+                       reached = 1;
+                       brklab = getlab();
+                       if (flostat == FLOOP)
+                               p1tfree($3);
+                       else
+                               xcbranch($3, brklab);
+               }
+               ;
+forprefix:       C_FOR  '('  .e  ';' .e  ';' {
+                       ++blevel;
+                       if ($3)
+                               ecomp($3);
+                       savebc();
+                       contlab = getlab();
+                       brklab = getlab();
+                       plabel( $$ = getlab());
+                       reached = 1;
+                       if ($5)
+                               xcbranch($5, brklab);
+                       else
+                               flostat |= FLOOP;
+               }
+               |  C_FOR '(' { ++blevel; } declaration .e ';' {
+                       savebc();
+                       contlab = getlab();
+                       brklab = getlab();
+                       plabel( $$ = getlab());
+                       reached = 1;
+                       if ($5)
+                               xcbranch($5, brklab);
+                       else
+                               flostat |= FLOOP;
+               }
+               ;
+
+switchpart:       C_SWITCH  '('  e ')' {
+                       P1ND *p;
+                       int num;
+                       TWORD t;
+
+                       savebc();
+                       brklab = getlab();
+                       $3 = eve($3);
+                       if (!ISINTEGER($3->n_type)) {
+                               uerror("switch expression must have integer "
+                                      "type");
+                               t = INT;
+                       } else {
+                               $3 = intprom($3);
+                               t = $3->n_type;
+                       }
+                       p = tempnode(0, t, 0, 0);
+                       num = regno(p);
+                       ecomp(buildtree(ASSIGN, p, $3));
+                       branch( $$ = getlab());
+                       swstart(num, t);
+                       reached = 0;
+               }
+               ;
+/*     EXPRESSIONS     */
+.e:               e { $$ = eve($1); }
+               |       { $$=0; }
+               ;
+
+elist:            { $$ = NULL; }
+               |  e2 { $$ = $1; }
+               ;
+
+e2:               e %prec ','
+               |  e2  ','  e { $$ = biop(CM, $1, $3); }
+               |  e2  ','  cast_type { /* hack for stdarg */
+                       TYMFIX($3);
+                       $3->n_op = TYPE;
+                       $$ = biop(CM, $1, $3);
+               }
+               |  cast_type { TYMFIX($1); $1->n_op = TYPE; $$ = $1; }
+               ;
+
+/*
+ * Precedence order of operators.
+ */
+e:                e ',' e { $$ = biop(COMOP, $1, $3); }
+               |  e '=' e {  $$ = biop(ASSIGN, $1, $3); }
+               |  e C_ASOP e {  $$ = biop($2, $1, $3); }
+               |  e '?' e ':' e { $$=biop(QUEST, $1, biop(COLON, $3, $5)); }
+/* COMPAT_GCC */|  e '?' ':' e { $$ = biop(BIQUEST, $1, $4); }
+               |  e C_OROR e { $$ = biop($2, $1, $3); }
+               |  e C_ANDAND e { $$ = biop($2, $1, $3); }
+               |  e '|' e { $$ = biop(OR, $1, $3); }
+               |  e '^' e { $$ = biop(ER, $1, $3); }
+               |  e '&' e { $$ = biop(AND, $1, $3); }
+               |  e C_EQUOP  e { $$ = biop($2, $1, $3); }
+               |  e C_RELOP e { $$ = biop($2, $1, $3); }
+               |  e C_SHIFTOP e { $$ = biop($2, $1, $3); }
+               |  e '+' e { $$ = biop(PLUS, $1, $3); }
+               |  e '-' e { $$ = biop(MINUS, $1, $3); }
+               |  e C_DIVOP e { $$ = biop($2, $1, $3); }
+               |  e '*' e { $$ = biop(MUL, $1, $3); }
+               |  term
+               ;
+
+xbegin:                   begin {
+                       $$ = getlab(); getlab(); getlab();
+                       branch($$); plabel(($$)+2);
+               }
+               ;
+
+term:             term C_INCOP {  $$ = biop($2, $1, bcon(1)); }
+               |  '*' term { $$ = biop(UMUL, $2, NULL); }
+               |  '&' term { $$ = biop(ADDROF, $2, NULL); }
+               |  '-' term { $$ = biop(UMINUS, $2, NULL ); }
+               |  '+' term { $$ = biop(UPLUS, $2, NULL ); }
+               |  C_UNOP term { $$ = biop($1, $2, NULL); }
+               |  C_INCOP term {
+                       $$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1));
+               }
+               |  C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $<intval>2; }
+               |  '(' cast_type ')' term  %prec C_INCOP {
+                       TYMFIX($2);
+                       $$ = biop(CAST, $2, $4);
+               }
+               |  C_SIZEOF xa '(' cast_type ')'  %prec C_SIZEOF {
+                       $$ = biop(SZOF, $4, bcon(1));
+                       inattr = $<intval>2;
+               }
+               |  C_ALIGNOF xa '(' cast_type ')' {
+                       int al;
+                       TYMFIX($4);
+                       al = talign($4->n_type, $4->n_ap);
+                       $$ = bcon(al/SZCHAR);
+                       inattr = $<intval>2;
+                       p1tfree($4);
+               }
+               | '(' cast_type ')' clbrace init_list optcomma '}' {
+                       endinit(0);
+                       $$ = bdty(NAME, $4);
+                       $$->n_op = CLOP;
+               }
+               | '(' cast_type ')' clbrace '}' {
+                       endinit(0);
+                       $$ = bdty(NAME, $4);
+                       $$->n_op = CLOP;
+               }
+               |  term '[' e ']' { $$ = biop(LB, $1, $3); }
+               |  C_NAME  '(' elist ')' {
+                       $$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3);
+               }
+               |  term  '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); }
+               |  term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); }
+               |  term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));}
+               |  C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); }
+               |  PCC_OFFSETOF  '(' cast_type ',' term ')' {
+                       TYMFIX($3);
+                       $3->n_type = INCREF($3->n_type);
+                       $3 = biop(CAST, $3, bcon(0));
+                       if ($5->n_op == NAME) {
+                               $$ = biop(STREF, $3, $5);
+                       } else {
+                               P1ND *p = $5;
+                               while (p->n_left->n_op != NAME)
+                                       p = p->n_left;
+                               p->n_left = biop(STREF, $3, p->n_left);
+                               $$ = $5;
+                       }
+                       $$ = biop(ADDROF, $$, NULL);
+                       $3 = block(NAME, NULL, NULL, ENUNSIGN(INTPTR), 0, 0);
+                       $$ = biop(CAST, $3, $$);
+               }
+               |  C_ICON { $$ = $1; }
+               |  C_FCON { $$ = bdty(FCON, $1); }
+               |  svstr { $$ = bdty(STRING, $1, styp()); }
+               |  '(' e ')' { $$=$2; }
+               |  '(' xbegin e ';' '}' ')' { $$ = gccexpr($2, eve($3)); }
+               |  '(' xbegin block_item_list e ';' '}' ')' {
+                       $$ = gccexpr($2, eve($4));
+               }
+               |  '(' xbegin block_item_list '}' ')' { 
+                       $$ = gccexpr($2, voidcon());
+               }
+               | C_ANDAND C_NAME {
+                       struct symtab *s = lookup($2, SLBLNAME|STEMP);
+                       if (s->soffset == 0) {
+                               s->soffset = -getlab();
+                               s->sclass = STATIC;
+                       }
+                       savlab(s->soffset);
+                       $$ = biop(ADDROF, bdty(GOTO, $2), NULL);
+               }
+               | C_GENERIC '(' e ',' gen_ass_list ')' { $$ = dogen($5, $3); }
+               ;
+
+gen_ass_list:    gen_assoc { $$ = $1; }
+               | gen_ass_list ',' gen_assoc { $$ = addgen($1, $3); }
+               ;
+
+gen_assoc:       cast_type ':' e { TYMFIX($1); $$ = newgen($1, $3); }
+               | C_DEFAULT ':' e { $$ = newgen(0, $3); }
+               ;
+
+xa:              { $<intval>$ = inattr; inattr = 0; }
+               ;
+
+clbrace:          '{'  { P1ND *q = $<nodep>-1; TYMFIX(q); $$ = clbrace(q); }
+               ;
+
+string:                   C_STRING { $$ = stradd(NULL, $1); }
+               |  string C_STRING { $$ = stradd($1, $2); }
+               ;
+
+cast_type:        specifier_qualifier_list {
+                       $$ = biop(TYMERGE, $1, bdty(NAME, NULL));
+               }
+               |  specifier_qualifier_list abstract_declarator {
+                       $$ = biop(TYMERGE, $1, aryfix($2));
+               }
+               ;
+
+%%
+
+P1ND *
+mkty(TWORD t, union dimfun *d, struct attr *sue)
+{
+       return block(TYPE, NULL, NULL, t, d, sue);
+}
+
+P1ND *
+bdty(int op, ...)
+{
+       CONSZ c;
+       va_list ap;
+       int val;
+       register P1ND *q;
+
+       va_start(ap, op);
+       q = biop(op, NULL, NULL);
+
+       switch (op) {
+       case UMUL:
+       case UCALL:
+               q->n_left = va_arg(ap, P1ND *);
+               q->n_rval = 0;
+               break;
+
+       case FCON:
+               q->n_dcon = va_arg(ap, FLT *);
+               q->n_type = q->n_dcon->t;
+               break;
+
+       case CALL:
+               q->n_left = va_arg(ap, P1ND *);
+               q->n_right = va_arg(ap, P1ND *);
+               break;
+
+       case LB:
+               q->n_left = va_arg(ap, P1ND *);
+               if ((val = va_arg(ap, int)) <= 0) {
+                       uerror("array size must be positive");
+                       val = 1;
+               }
+               q->n_right = bcon(val);
+               break;
+
+       case GOTO: /* for named labels */
+               q->n_ap = attr_add(q->n_ap, attr_new(ATTR_P1LABELS, 1));
+               /* FALLTHROUGH */
+       case NAME:
+               q->n_op = NAME;
+               q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */
+               break;
+
+       case STRING:
+               q->n_type = PTR|CHAR;
+               q->n_name = va_arg(ap, char *);
+               c = va_arg(ap, TWORD);
+               slval(q, c);
+               break;
+
+       default:
+               cerror("bad bdty");
+       }
+       va_end(ap);
+
+       return q;
+}
+
+static void
+flend(void)
+{
+       struct savbc *sc;
+
+       if (!isinlining && sspflag && blevel == 2)
+               sspend();
+#ifdef STABS
+       if (gflag && blevel > 2)
+               stabs_rbrac(blevel);
+#endif
+       --blevel;
+       if( blevel == 1 )
+               blevel = 0;
+       symclear(blevel); /* Clean ut the symbol table */
+       if (autooff > maxautooff)
+               maxautooff = autooff;
+       autooff = savctx->contlab;
+       blkfree();
+       stmtfree();
+       bkpole = savctx->bkptr;
+       cbkp = savctx->bkoff;
+       sapole = savctx->stptr;
+       cstp = savctx->stoff;
+       usdnodes = savctx->numnode;
+       sc = savctx->next;
+       free(savctx);
+       savctx = sc;
+}
+
+/*
+ * XXX workaround routines for block level cleansing in gcc compat mode.
+ * Temporary should be re reserved for this value before.
+ */
+static P1ND *
+p1mcopy(P1ND *p)
+{
+       P1ND *q;
+
+       q = xmalloc(sizeof(P1ND));
+       *q = *p;
+
+       switch (coptype(q->n_op)) {
+       case BITYPE:
+               q->n_right = p1mcopy(p->n_right);
+               /* FALLTHROUGH */
+       case UTYPE: 
+               q->n_left = p1mcopy(p->n_left);
+       }
+
+       return(q);
+}
+
+static void
+p1mfree(P1ND *p)
+{
+       int o = coptype(p->n_op);
+       if (o == BITYPE)
+               p1mfree(p->n_right);
+       if (o != LTYPE)
+               p1mfree(p->n_left);
+       free(p);
+}
+
+
+static P1ND *
+gccexpr(int bn, P1ND *q)
+{
+       P1ND *r, *p, *s;
+
+       branch(bn+4);
+       plabel(bn);
+       r = buildtree(COMOP, biop(GOTO, bcon(bn+2), NULL), q);
+       /* XXX hack to survive flend() */
+       s = p1mcopy(r);
+       p1tfree(r);
+       flend();
+       r = p1tcopy(s);
+       p1mfree(s);
+       q = r->n_right;
+       /* XXX end hack */
+       if (!(q->n_op == ICON && q->n_type == STRTY) && (r->n_type != VOID)) {
+               p = tempnode(0, q->n_type, q->n_df, q->n_ap);
+               r = buildtree(ASSIGN, p1tcopy(p), r);
+               r = buildtree(COMOP, r, p);
+       }
+       return r;
+}
+
+static void
+savebc(void)
+{
+       struct savbc *bc = malloc(sizeof(struct savbc));
+
+       bc->brklab = brklab;
+       bc->contlab = contlab;
+       bc->flostat = flostat;
+       bc->next = savbc;
+       savbc = bc;
+       flostat = 0;
+}
+
+static void
+resetbc(int mask)
+{
+       struct savbc *bc;
+
+       flostat = savbc->flostat | (flostat&mask);
+       contlab = savbc->contlab;
+       brklab = savbc->brklab;
+       bc = savbc->next;
+       free(savbc);
+       savbc = bc;
+}
+
+struct swdef {
+       struct swdef *next;     /* Next in list */
+       int deflbl;             /* Label for "default" */
+       struct swents *ents;    /* Linked sorted list of case entries */
+       int nents;              /* # of entries in list */
+       int num;                /* Node value will end up in */
+       TWORD type;             /* Type of switch expression */
+} *swpole;
+
+/*
+ * add case to switch
+ */
+static void
+addcase(P1ND *p)
+{
+       struct swents **put, *w, *sw = malloc(sizeof(struct swents));
+       CONSZ val;
+
+       p = optloop(p);  /* change enum to ints */
+       if (p->n_op != ICON || p->n_sp != NULL) {
+               uerror( "non-constant case expression");
+               return;
+       }
+       if (swpole == NULL) {
+               uerror("case not in switch");
+               return;
+       }
+
+       if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) {
+               val = glval(p);
+               p = makety(p, swpole->type, 0, 0, 0);
+               if (p->n_op != ICON)
+                       cerror("could not cast case value to type of switch "
+                              "expression");
+               if (glval(p) != val)
+                       werror("case expression truncated");
+       }
+       sw->sval = glval(p);
+       p1tfree(p);
+       put = &swpole->ents;
+       if (ISUNSIGNED(swpole->type)) {
+               for (w = swpole->ents;
+                    w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval;
+                    w = w->next)
+                       put = &w->next;
+       } else {
+               for (w = swpole->ents; w != NULL && w->sval < sw->sval;
+                    w = w->next)
+                       put = &w->next;
+       }
+       if (w != NULL && w->sval == sw->sval) {
+               uerror("duplicate case in switch");
+               return;
+       }
+       plabel(sw->slab = getlab());
+       *put = sw;
+       sw->next = w;
+       swpole->nents++;
+}
+
+#ifdef GCC_COMPAT
+void
+gcccase(P1ND *ln, P1ND *hn)
+{
+       CONSZ i, l, h;
+
+       l = icons(optim(ln));
+       h = icons(optim(hn));
+
+       if (h < l)
+               i = l, l = h, h = i;
+
+       for (i = l; i <= h; i++)
+               addcase(xbcon(i, NULL, hn->n_type));
+}
+#endif
+
+/*
+ * add default case to switch
+ */
+static void
+adddef(void)
+{
+       if (swpole == NULL)
+               uerror("default not inside switch");
+       else if (swpole->deflbl != 0)
+               uerror("duplicate default in switch");
+       else
+               plabel( swpole->deflbl = getlab());
+}
+
+static void
+swstart(int num, TWORD type)
+{
+       struct swdef *sw = malloc(sizeof(struct swdef));
+
+       sw->deflbl = sw->nents = 0;
+       sw->ents = NULL;
+       sw->next = swpole;
+       sw->num = num;
+       sw->type = type;
+       swpole = sw;
+}
+
+/*
+ * end a switch block
+ */
+static void
+swend(void)
+{
+       struct swents *sw, **swp;
+       struct swdef *sp;
+       int i;
+
+       sw = FUNALLO(sizeof(struct swents));
+       swp = FUNALLO(sizeof(struct swents *) * (swpole->nents+1));
+
+       sw->slab = swpole->deflbl;
+       swp[0] = sw;
+
+       for (i = 1; i <= swpole->nents; i++) {
+               swp[i] = swpole->ents;
+               swpole->ents = swpole->ents->next;
+       }
+       genswitch(swpole->num, swpole->type, swp, swpole->nents);
+
+       FUNFREE(sw);
+       FUNFREE(swp);
+       while (swpole->ents) {
+               sw = swpole->ents;
+               swpole->ents = sw->next;
+               free(sw);
+       }
+       sp = swpole->next;
+       free(swpole);
+       swpole = sp;
+}
+
+/*
+ * num: tempnode the value of the switch expression is in
+ * type: type of the switch expression
+ *
+ * p points to an array of structures, each consisting
+ * of a constant value and a label.
+ * The first is >=0 if there is a default label;
+ * its value is the label number
+ * The entries p[1] to p[n] are the nontrivial cases
+ * n is the number of case statements (length of list)
+ */
+static void
+genswitch(int num, TWORD type, struct swents **p, int n)
+{
+       P1ND *r, *q;
+       int i;
+
+       if (mygenswitch(num, type, p, n))
+               return;
+
+       /* simple switch code */
+       for (i = 1; i <= n; ++i) {
+               /* already in 1 */
+               r = tempnode(num, type, 0, 0);
+               q = xbcon(p[i]->sval, NULL, type);
+               r = buildtree(NE, r, clocal(q));
+               xcbranch(r, p[i]->slab);
+       }
+       if (p[0]->slab > 0)
+               branch(p[0]->slab);
+}
+
+/*
+ * Declare a variable or prototype.
+ */
+static struct symtab *
+init_declarator(P1ND *tn, P1ND *p, int assign, P1ND *a, char *as)
+{
+       int class = glval(tn);
+       struct symtab *sp;
+
+       p = aryfix(p);
+       p = tymerge(tn, p);
+       if (a) {
+               struct attr *ap = gcc_attr_wrapper(a);
+               p->n_ap = attr_add(p->n_ap, ap);
+       }
+
+       p->n_sp = sp = lookup((char *)p->n_sp, 0); /* XXX */
+
+       if (fun_inline && ISFTN(p->n_type))
+               sp->sflags |= SINLINE;
+
+       if (!ISFTN(p->n_type)) {
+               if (assign) {
+                       defid2(p, class, as);
+                       sp = p->n_sp;
+                       sp->sflags |= SASG;
+                       if (sp->sflags & SDYNARRAY)
+                               uerror("can't initialize dynamic arrays");
+                       lcommdel(sp);
+               } else
+                       nidcl2(p, class, as);
+       } else {
+               extern P1ND *parlink;
+               if (assign)
+                       uerror("cannot initialise function");
+               defid2(p, uclass(class), as);
+               sp = p->n_sp;
+               if (sp->sdf->dfun == 0 && !issyshdr)
+                       warner(Wstrict_prototypes);
+               if (parlink) {
+                       /* dynamic sized arrays in prototypes */
+                       p1tfree(parlink); /* Free delayed tree */
+                       parlink = NULL;
+               }
+       }
+       p1tfree(p);
+       if (issyshdr)
+               sp->sflags |= SINSYS; /* declared in system header */
+       return sp;
+}
+
+/*
+ * Declare old-stype function arguments.
+ */
+static void
+oldargs(P1ND *p)
+{
+       blevel++;
+       p->n_op = TYPE;
+       p->n_type = FARG;
+       p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+       defid(p, PARAM);
+       blevel--;
+}
+
+/*
+ * Set NAME nodes to a null name and index of LB nodes to NOOFFSET
+ * unless clr is one, in that case preserve variable name.
+ */
+static P1ND *
+namekill(P1ND *p, int clr)
+{
+       P1ND *q;
+       int o = p->n_op;
+
+       switch (coptype(o)) {
+       case LTYPE:
+               if (o == NAME) {
+                       if (clr)
+                               p->n_sp = NULL;
+                       else
+                               p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+               }
+               break;
+
+       case UTYPE:
+               p->n_left = namekill(p->n_left, clr);
+               break;
+
+        case BITYPE:
+                p->n_left = namekill(p->n_left, clr);
+               if (o == LB) {
+                       if (clr) {
+                               p1tfree(p->n_right);
+                               p->n_right = bcon(NOOFFSET);
+                       } else
+                               p->n_right = eve(p->n_right);
+               } else if (o == CALL)
+                       p->n_right = namekill(p->n_right, 1);
+               else
+                       p->n_right = namekill(p->n_right, clr);
+               if (o == TYMERGE) {
+                       q = tymerge(p->n_left, p->n_right);
+                       q->n_ap = attr_add(q->n_ap, p->n_ap);
+                       p1tfree(p->n_left);
+                       p1nfree(p);
+                       p = q;
+               }
+               break;
+       }
+       return p;
+}
+
+/*
+ * Declare function arguments.
+ */
+static P1ND *
+funargs(P1ND *p)
+{
+       extern P1ND *arrstk[10];
+
+       if (p->n_op == ELLIPSIS)
+               return p;
+
+       p = namekill(p, 0);
+       if (ISFTN(p->n_type))
+               p->n_type = INCREF(p->n_type);
+       if (ISARY(p->n_type)) {
+               p->n_type += (PTR-ARY);
+               if (p->n_df->ddim == -1)
+                       p1tfree(arrstk[0]), arrstk[0] = NULL;
+               p->n_df++;
+       }
+       if (p->n_type == VOID && p->n_sp->sname == NULL)
+               return p; /* sanitycheck later */
+       else if (p->n_sp->sname == NULL)
+               uerror("argument missing");
+       else
+               defid(p, PARAM);
+       return p;
+}
+
+static P1ND *
+listfw(P1ND *p, P1ND * (*f)(P1ND *))
+{
+        if (p->n_op == CM) {
+                p->n_left = listfw(p->n_left, f);
+                p->n_right = (*f)(p->n_right);
+        } else
+                p = (*f)(p);
+       return p;
+}
+
+
+/*
+ * Declare a function.
+ */
+static void
+fundef(P1ND *tp, P1ND *p)
+{
+       extern int prolab;
+       struct symtab *s;
+       P1ND *q, *typ;
+       int class = glval(tp), oclass, ctval;
+
+       /*
+        * We discard all names except for those needed for
+        * parameter declaration. While doing that, also change
+        * non-constant array sizes to unknown.
+        */
+       ctval = tvaloff;
+       for (q = p; coptype(q->n_op) != LTYPE &&
+           q->n_left->n_op != NAME; q = q->n_left) {
+               if (q->n_op == CALL)
+                       q->n_right = namekill(q->n_right, 1);
+       }
+       if (q->n_op != CALL && q->n_op != UCALL) {
+               uerror("invalid function definition");
+               p = bdty(UCALL, p);
+       } else if (q->n_op == CALL) {
+               blevel = 1;
+               argoff = ARGINIT;
+               if (oldstyle == 0)
+                       q->n_right = listfw(q->n_right, funargs);
+               ftnarg(q);
+               blevel = 0;
+       }
+
+       p = typ = tymerge(tp, p);
+#ifdef GCC_COMPAT
+       /* gcc seems to discard __builtin_ when declaring functions */
+       if (strncmp("__builtin_", (char *)typ->n_sp, 10) == 0)
+               typ->n_sp = (struct symtab *)((char *)typ->n_sp + 10);
+#endif
+       s = typ->n_sp = lookup((char *)typ->n_sp, 0); /* XXX */
+
+       oclass = s->sclass;
+       if (class == STATIC && oclass == EXTERN)
+               werror("%s was first declared extern, then static", s->sname);
+
+       if (fun_inline) {
+               /* special syntax for inline functions */
+               if (! strcmp(s->sname,"main")) 
+                       uerror("cannot inline main()");
+
+               s->sflags |= SINLINE;
+               inline_start(s, class);
+               if (class == EXTERN)
+                       class = EXTDEF;
+       } else if (class == EXTERN)
+               class = SNULL; /* same result */
+
+       cftnsp = s;
+       defid(p, class);
+       if (s->sdf->dfun == 0 && !issyshdr)
+               warner(Wstrict_prototypes);
+#ifdef GCC_COMPAT
+       if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) {
+               /* Temporary turn on temps to make always_inline work */
+               alwinl = 1;
+               if (xtemps == 0) alwinl |= 2;
+               xtemps = 1;
+       }
+#endif
+       prolab = getlab();
+       send_passt(IP_PROLOG, -1, getexname(cftnsp), cftnsp->stype,
+           cftnsp->sclass == EXTDEF, prolab, ctval);
+       blevel++;
+#ifdef STABS
+       if (gflag)
+               stabs_func(s);
+#endif
+       p1tfree(tp);
+       p1tfree(p);
+
+}
+
+static void
+fend(void)
+{
+       if (blevel)
+               cerror("function level error");
+       ftnend();
+       fun_inline = 0;
+       if (alwinl & 2) xtemps = 0;
+       alwinl = 0;
+       cftnsp = NULL;
+}
+
+P1ND *
+structref(P1ND *p, int f, char *name)
+{
+       P1ND *r;
+
+       if (f == DOT)
+               p = buildtree(ADDROF, p, NULL);
+       r = biop(NAME, NULL, NULL);
+       r->n_name = name;
+       r = buildtree(STREF, p, r);
+       return r;
+}
+
+static void
+olddecl(P1ND *p, P1ND *a)
+{
+       struct symtab *s;
+
+       p = namekill(p, 0);
+       s = p->n_sp;
+       if (s->slevel != 1 || s->stype == UNDEF)
+               uerror("parameter '%s' not defined", s->sname);
+       else if (s->stype != FARG)
+               uerror("parameter '%s' redefined", s->sname);
+
+       s->stype = p->n_type;
+       s->sdf = p->n_df;
+       s->sap = p->n_ap;
+       if (ISARY(s->stype)) {
+               s->stype += (PTR-ARY);
+               s->sdf++;
+       } else if (s->stype == FLOAT)
+               s->stype = DOUBLE;
+       if (a)
+               attr_add(s->sap, gcc_attr_wrapper(a));
+       p1nfree(p);
+}
+
+void
+branch(int lbl)
+{
+       int r = reached++;
+       ecomp(biop(GOTO, bcon(lbl), NULL));
+       reached = r;
+}
+
+/*
+ * Create a printable string based on an encoded string.
+ */
+static char *
+mkpstr(char *str)
+{
+       char *os, *s;
+       int l = strlen(str) + 3; /* \t + \n + \0 */
+
+       os = s = stmtalloc(l);
+       *s++ = '\t';
+       while (*str) {
+               if (*str == '\\')
+                       *s++ = esccon(&str);
+               else
+                       *s++ = *str++;
+       }
+       *s++ = '\n';
+       *s = 0;
+
+       return os;
+}
+
+/*
+ * Fake a symtab entry for compound literals.
+ */
+static struct symtab *
+clbrace(P1ND *p)
+{
+       struct symtab *sp;
+
+       sp = getsymtab(simname("cl"), STEMP);
+       sp->stype = p->n_type;
+       sp->squal = p->n_qual;
+       sp->sdf = p->n_df;
+       sp->sap = p->n_ap;
+       p1tfree(p);
+       if (blevel == 0 && xnf != NULL) {
+               sp->sclass = STATIC;
+               sp->slevel = 2;
+               sp->soffset = getlab();
+       } else {
+               sp->sclass = blevel ? AUTO : STATIC;
+               if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) {
+                       sp->soffset = NOOFFSET;
+                       oalloc(sp, &autooff);
+               }
+       }
+       beginit(sp);
+       return sp;
+}
+
+char *
+simname(char *s)
+{
+       int len = strlen(s) + 10 + 1;
+       char *w = tmpalloc(len); /* uncommon */
+
+       snprintf(w, len, "%s%d", s, getlab());
+       return w;
+}
+
+P1ND *
+biop(int op, P1ND *l, P1ND *r)
+{
+       return block(op, l, r, INT, 0, 0);
+}
+
+static P1ND *
+cmop(P1ND *l, P1ND *r)
+{
+       return biop(CM, l, r);
+}
+
+static P1ND *
+voidcon(void)
+{
+       return block(ICON, NULL, NULL, STRTY, 0, 0);
+}
+
+/* Support for extended assembler a' la' gcc style follows below */
+
+static P1ND *
+xmrg(P1ND *out, P1ND *in)
+{
+       P1ND *p = in;
+
+       if (p->n_op == XARG) {
+               in = cmop(out, p);
+       } else {
+               while (p->n_left->n_op == CM)
+                       p = p->n_left;
+               p->n_left = cmop(out, p->n_left);
+       }
+       return in;
+}
+
+/*
+ * Put together in and out node lists in one list, and balance it with
+ * the constraints on the right side of a CM node.
+ */
+static P1ND *
+xcmop(P1ND *out, P1ND *in, P1ND *str)
+{
+       P1ND *p, *q;
+
+       if (out) {
+               /* D out-list sanity check */
+               for (p = out; p->n_op == CM; p = p->n_left) {
+                       q = p->n_right;
+                       if (q->n_name[0] != '=' && q->n_name[0] != '+')
+                               uerror("output missing =");
+               }
+               if (p->n_name[0] != '=' && p->n_name[0] != '+')
+                       uerror("output missing =");
+               if (in == NULL)
+                       p = out;
+               else
+                       p = xmrg(out, in);
+       } else if (in) {
+               p = in;
+       } else
+               p = voidcon();
+
+       if (str == NULL)
+               str = voidcon();
+       return cmop(p, str);
+}
+
+/*
+ * Generate a XARG node based on a string and an expression.
+ */
+static P1ND *
+xasmop(char *str, P1ND *p)
+{
+
+       p = biop(XARG, p, NULL);
+       p->n_name = str;
+       return p;
+}
+
+/*
+ * Generate a XASM node based on a string and an expression.
+ */
+static void
+mkxasm(char *str, P1ND *p)
+{
+       P1ND *q;
+
+       q = biop(XASM, p->n_left, p->n_right);
+       q->n_name = str;
+       p1nfree(p);
+       ecomp(optloop(q));
+}
+
+static struct attr *
+gcc_attr_wrapper(P1ND *p)
+{
+#ifdef GCC_COMPAT
+       return gcc_attr_parse(p);
+#else
+       if (p != NULL)
+               uerror("gcc attribute used");
+       return NULL;
+#endif
+}
+
+#ifdef GCC_COMPAT
+static P1ND *
+tyof(P1ND *p)
+{
+       static struct symtab spp;
+       P1ND *q = block(TYPE, NULL, NULL, p->n_type, p->n_df, p->n_ap);
+       q->n_qual = p->n_qual;
+       q->n_sp = &spp; /* for typenode */
+       p1walkf(p, putjops, 0);
+       p1tfree(p);
+       return q;
+}
+
+#else
+static P1ND *
+tyof(P1ND *p)
+{
+       uerror("typeof gcc extension");
+       return bcon(0);
+}
+#endif
+
+/*
+ * Traverse an unhandled expression tree bottom-up and call buildtree()
+ * or equivalent as needed.
+ */
+P1ND *
+eve(P1ND *p)
+{
+       struct symtab *sp;
+       P1ND *r, *p1, *p2;
+       int x;
+
+       p1 = p->n_left;
+       p2 = p->n_right;
+       switch (p->n_op) {
+       case NAME:
+               sp = lookup((char *)p->n_sp,
+                   attr_find(p->n_ap, ATTR_P1LABELS) ? SLBLNAME|STEMP : 0);
+               if (sp->sflags & SINLINE)
+                       inline_ref(sp);
+               r = nametree(sp);
+               if (sp->sflags & SDYNARRAY)
+                       r = buildtree(UMUL, r, NULL);
+#ifdef GCC_COMPAT
+               if (attr_find(sp->sap, GCC_ATYP_DEPRECATED))
+                       warner(Wdeprecated_declarations, sp->sname);
+#endif
+               break;
+
+       case DOT:
+       case STREF:
+               r = structref(eve(p1), p->n_op, (char *)p2->n_sp);
+               p1nfree(p2);
+               break;
+
+       case CAST:
+               p2 = eve(p2);
+#ifndef NO_COMPLEX
+               if (ANYCX(p1) || ANYCX(p2)) {
+                       r = cxcast(p1, p2);
+                       break;
+               }
+#endif
+#ifdef TARGET_TIMODE
+               if ((r = gcc_eval_ticast(CAST, p1, p2)) != NULL)
+                       break;
+#endif
+               p1 = buildtree(CAST, p1, p2);
+               p1nfree(p1->n_left);
+               r = p1->n_right;
+               p1nfree(p1);
+               break;
+
+
+       case SZOF:
+               x = xinline; xinline = 0; /* XXX hack */
+               if (glval(p2) == 0)
+                       p1 = eve(p1);
+               else
+                       TYMFIX(p1);
+               p1nfree(p2);
+               r = doszof(p1);
+               xinline = x;
+               break;
+
+       case LB:
+               p1 = eve(p1);
+               p2 = eve(p2);
+#ifdef TARGET_TIMODE
+               if (isti(p2)) {
+                       P1ND *s = block(NAME, NULL, NULL, LONG, 0, 0);
+                       if ((r = gcc_eval_ticast(CAST, s, p2)) != NULL)
+                               p2 = r;
+                       p1nfree(s);
+               }
+#endif
+               r = buildtree(UMUL, buildtree(PLUS, p1, p2), NULL);
+               break;
+
+       case COMPL:
+#ifndef NO_COMPLEX
+               p1 = eve(p1);
+               if (ANYCX(p1))
+                       r = cxconj(p1);
+               else
+                       r = buildtree(COMPL, p1, NULL);
+               break;
+#endif
+       case UPLUS:
+               r = eve(p1);
+               if (r->n_op == FLD || r->n_type < INT)
+                       r = buildtree(PLUS, r, bcon(0)); /* must be size int */
+               break;
+
+       case UMINUS:
+#ifndef NO_COMPLEX
+               p1 = eve(p1);
+               if (ANYCX(p1))
+                       r = cxop(UMINUS, p1, p1);
+               else
+                       r = buildtree(UMINUS, p1, NULL);
+               break;
+#endif
+       case NOT:
+       case UMUL:
+               p1 = eve(p1);
+#ifdef TARGET_TIMODE
+               if ((r = gcc_eval_tiuni(p->n_op, p1)) != NULL)
+                       break;
+#endif
+#ifndef NO_COMPLEX
+               if (p->n_op == NOT && ANYCX(p1))
+                       p1 = cxop(NE, p1, bcon(0));
+#endif
+               r = buildtree(p->n_op, p1, NULL);
+               break;
+
+       case ADDROF:
+               r = eve(p1);
+               if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){
+#ifdef notdef
+                       werror( "& before array or function: ignored" );
+#endif
+               } else
+                       r = buildtree(ADDROF, r, NULL);
+               break;
+
+       case UCALL:
+               p2 = NULL;
+               /* FALLTHROUGH */
+       case CALL:
+               if (p1->n_op == NAME) {
+                       sp = lookup((char *)p1->n_sp, 0);
+#ifndef NO_C_BUILTINS
+                       if (sp->sflags & SBUILTIN) {
+                               p1nfree(p1);
+                               r = builtin_check(sp, p2);
+                               break;
+                       }
+#endif
+                       if (sp->stype == UNDEF) {
+                               p1->n_type = FTN|INT;
+                               p1->n_sp = sp;
+                               p1->n_ap = NULL;
+                               defid(p1, EXTERN);
+                       }
+                       p1nfree(p1);
+#ifdef GCC_COMPAT
+                       if (attr_find(sp->sap, GCC_ATYP_DEPRECATED))
+                               warner(Wdeprecated_declarations, sp->sname);
+#endif
+                       if (p->n_op == CALL)
+                               p2 = eve(p2);
+                       r = doacall(sp, nametree(sp), p2);
+               } else {
+                       if (p->n_op == CALL)
+                               p2 = eve(p2);
+                       r = doacall(NULL, eve(p1), p2);
+               }
+               break;
+
+#ifndef NO_COMPLEX
+       case XREAL:
+       case XIMAG:
+               p1 = eve(p1);
+               r = cxelem(p->n_op, p1);
+               break;
+#endif
+
+       case COLON:
+       case MUL:
+       case DIV:
+       case PLUS:
+       case MINUS:
+       case ASSIGN:
+       case EQ:
+       case NE:
+       case OROR:
+       case ANDAND:
+#ifndef NO_COMPLEX
+               p1 = eve(p1);
+               p2 = eve(p2);
+#ifdef TARGET_TIMODE
+               if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL)
+                       break;
+#endif
+               if (ANYCX(p1) || ANYCX(p2)) {
+                       r = cxop(p->n_op, p1, p2);
+               } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) {
+                       r = imop(p->n_op, p1, p2);
+               } else
+                       r = buildtree(p->n_op, p1, p2);
+               break;
+#endif
+       case MOD:
+       case CM:
+       case GT:
+       case GE:
+       case LT:
+       case LE:
+       case RS:
+       case LS:
+       case RSEQ:
+       case LSEQ:
+       case AND:
+       case OR:
+       case ER:
+       case EREQ:
+       case OREQ:
+       case ANDEQ:
+       case QUEST:
+               p1 = eve(p1);
+               p2 = eve(p2);
+#ifdef TARGET_TIMODE
+               if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL)
+                       break;
+#endif
+               r = buildtree(p->n_op, p1, p2);
+               break;
+
+       case BIQUEST: /* gcc e ?: e op */
+               p1 = eve(p1);
+               r = tempnode(0, p1->n_type, p1->n_df, p1->n_ap);
+               p2 = eve(biop(COLON, p1tcopy(r), p2));
+               r = buildtree(QUEST, buildtree(ASSIGN, r, p1), p2);
+               break;
+
+       case INCR:
+       case DECR:
+       case MODEQ:
+       case MINUSEQ:
+       case PLUSEQ:
+       case MULEQ:
+       case DIVEQ:
+               p1 = eve(p1);
+               p2 = eve(p2);
+#ifdef TARGET_TIMODE
+               if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL)
+                       break;
+#endif
+#ifndef NO_COMPLEX
+               if (ANYCX(p1) || ANYCX(p2)) {
+                       r = cxop(UNASG p->n_op, p1tcopy(p1), p2);
+                       r = cxop(ASSIGN, p1, r);
+                       break;
+               } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) {
+                       r = imop(UNASG p->n_op, p1tcopy(p1), p2);
+                       r = cxop(ASSIGN, p1, r);
+                       break;
+               }
+               /* FALLTHROUGH */
+#endif
+               r = buildtree(p->n_op, p1, p2);
+               break;
+
+       case STRING:
+               r = strend(p->n_name, (TWORD)glval(p));
+               break;
+
+       case COMOP:
+               if (p1->n_op == GOTO) {
+                       /* inside ({ }), eve already called */
+                       r = buildtree(p->n_op, p1, p2);
+               } else {
+                       p1 = eve(p1);
+                       r = buildtree(p->n_op, p1, eve(p2));
+               }
+               break;
+
+       case TYPE:
+       case ICON:
+       case FCON:
+       case TEMP:
+               return p;
+
+       case CLOP:
+               r = nametree(p->n_sp);
+               break;
+
+       default:
+#ifdef PCC_DEBUG
+               p1fwalk(p, eprint, 0);
+#endif
+               cerror("eve");
+               r = NULL;
+       }
+       p1nfree(p);
+       return r;
+}
+
+int
+con_e(P1ND *p)
+{
+       return icons(optloop(eve(p)));
+}
+
+void
+uawarn(P1ND *p, char *s)
+{
+       if (p == 0)
+               return;
+       if (attrwarn)
+               werror("unhandled %s attribute", s);
+       p1tfree(p);
+}
+
+static void
+dainit(P1ND *d, P1ND *a)
+{
+       if (d == NULL) {
+               asginit(a);
+       } else if (d->n_op == CM) {
+               int is = con_e(d->n_left);
+               int ie = con_e(d->n_right);
+               int i;
+
+               p1nfree(d);
+               if (ie < is)
+                       uerror("negative initializer range");
+               desinit(biop(LB, NULL, bcon(is)));
+               for (i = is; i < ie; i++)
+                       asginit(p1tcopy(a));
+               asginit(a);
+       } else {
+               cerror("dainit");
+       }
+}
+
+/*
+ * Traverse down and tymerge() where appropriate.
+ */
+static P1ND *
+tymfix(P1ND *p)
+{
+       P1ND *q;
+       int o = coptype(p->n_op);
+
+       switch (o) {
+       case LTYPE:
+               break;
+       case UTYPE:
+               p->n_left = tymfix(p->n_left);
+               break;
+       case BITYPE:
+               p->n_left = tymfix(p->n_left);
+               p->n_right = tymfix(p->n_right);
+               if (p->n_op == TYMERGE) {
+                       q = tymerge(p->n_left, p->n_right);
+                       q->n_ap = attr_add(q->n_ap, p->n_ap);
+                       p1tfree(p->n_left);
+                       p1nfree(p);
+                       p = q;
+               }
+               break;
+       }
+       return p;
+}
+
+static P1ND *
+aryfix(P1ND *p)
+{
+       P1ND *q;
+
+       for (q = p; q->n_op != NAME; q = q->n_left) {
+               if (q->n_op == LB) {
+                       q->n_right = optloop(eve(q->n_right));
+                       if ((blevel == 0 || rpole != NULL) &&
+                           !nncon(q->n_right))
+                               uerror("array size not constant"); 
+                       /*
+                        * Checks according to 6.7.5.2 clause 1:
+                        * "...the expression shall have an integer type."
+                        * "If the expression is a constant expression,  
+                        * it shall have a value greater than zero."
+                        */
+                       if (!ISINTEGER(q->n_right->n_type))
+                               werror("array size is not an integer");
+                       else if (q->n_right->n_op == ICON &&
+                           glval(q->n_right) < 0 &&
+                           glval(q->n_right) != NOOFFSET) {
+                                       uerror("array size cannot be negative");
+                                       slval(q->n_right, 1);
+                       }
+               } else if (q->n_op == CALL)
+                       q->n_right = namekill(q->n_right, 1);
+       }
+       return p;
+}
+
+struct labs {
+       struct labs *next;
+       int lab;
+} *labp;
+
+static void
+savlab(int lab)
+{
+       struct labs *l = tmpalloc(sizeof(struct labs)); /* uncommon */
+       l->lab = lab < 0 ? -lab : lab;
+       l->next = labp;
+       labp = l;
+}
+
+int *
+mkclabs(void)
+{
+       struct labs *l;
+       int i, *rv;
+
+       for (i = 0, l = labp; l; l = l->next, i++)
+               ;
+       rv = tmpalloc((i+1)*sizeof(int));       /* uncommon */
+       for (i = 0, l = labp; l; l = l->next, i++)
+               rv[i] = l->lab;
+       rv[i] = 0;
+       labp = 0;
+       return rv;
+}
+
+void
+xcbranch(P1ND *p, int lab)
+{
+#ifndef NO_COMPLEX
+       if (ANYCX(p))
+               p = cxop(NE, p, bcon(0));
+#endif
+       cbranch(buildtree(NOT, p, NULL), bcon(lab));
+}
+
+/*
+ * New a case entry to genlist.
+ * tn is type, e is expression.
+ */
+static struct genlist *
+newgen(P1ND *tn, P1ND *e)
+{
+       struct genlist *ng;
+       TWORD t;
+
+       if (tn) {
+               t = tn->n_type;
+               p1tfree(tn);
+       } else
+               t = 0;
+
+       /* add new entry */
+       ng = malloc(sizeof(struct genlist));
+       ng->next = NULL;
+       ng->t = t;
+       ng->p = e;
+       return ng;
+}
+
+/*
+ * Add a case entry to genlist.
+ * g is list, ng is new entry.
+ */
+static struct genlist *
+addgen(struct genlist *g, struct genlist *ng)
+{
+       struct genlist *w;
+
+       /* search for duplicate type */
+       for (w = g; w; w = w->next) {
+               if (w->t == ng->t)
+                       uerror("duplicate type in _Generic");
+       }
+       ng->next = g;
+       return ng;
+}
+
+static P1ND *
+dogen(struct genlist *g, P1ND *e)
+{
+       struct genlist *ng;
+       P1ND *w, *p;
+
+       e = eve(e);
+
+       /* search for direct match */
+       for (ng = g, w = p = NULL; ng; ng = ng->next) {
+               if (ng->t == 0)
+                       p = ng->p; /* save default */
+               if (e->n_type == ng->t)
+                       w = ng->p;
+       }
+
+       /* if no match, use generic */
+       if (w == NULL) {
+               if (p == NULL) {
+                       uerror("_Generic: no default found");
+                       p = bcon(0);
+               }
+               w = p;
+       }
+
+       /* free tree */
+       while (g) {
+               if (g->p != w)
+                       p1tfree(g->p);
+               ng = g->next;
+               free(g);
+               g = ng;
+       }
+
+       p1tfree(e);
+       return w;
+}
diff --git a/lang/pcc/pcc/cc/ccom/dwarf.c b/lang/pcc/pcc/cc/ccom/dwarf.c
new file mode 100644 (file)
index 0000000..faa5aad
--- /dev/null
@@ -0,0 +1,259 @@
+/*      $Id: dwarf.c,v 1.2 2016/03/08 18:17:45 ragge Exp $     */
+
+/*
+ * Copyright (c) 2016 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Expect just ELF for now.
+ */
+#include "pass1.h"
+
+#ifdef DWARF
+
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "dwarf.h"
+
+/*
+ * Basic DWARF definitions, from specification.
+ */
+#define        DVERSION        3       /* dwarf version */
+#define        DLABEL          ".LD%d"
+
+#define        DW64    (SZPOINT(VOID)/SZCHAR == 8)
+
+static int dwseg = -1;
+enum { DINFO, DABBREV, DSTR };
+static char *segn[] = { ".debug_info", ".debug_abbrev", ".debug_str" };
+
+static int debug_info_sz, debug_info_sz_lbl;
+static int debug_abbrev_beg_lbl;
+
+static int dwcfl, dwbtext, dwetext;
+
+static char *dwname;
+
+static int
+dwlab(void)
+{
+       static int dwlbl;
+       return dwlbl++;
+}
+
+static void
+dwarfseg(int seg)
+{
+       if (seg == dwseg)
+               return;
+       /* XXX target code? */
+       printf("\t.section\t%s,\"\",@progbits\n", segn[seg]);
+       lastloc = NOSEG;
+       dwseg = seg;
+}
+
+static void
+dwslab(int seg, int lbl)
+{
+       dwarfseg(seg);
+       printf(PRTPREF DLABEL ":\n", lbl);
+}
+
+static void
+p1b(int v)
+{
+       printf(PRTPREF "%s 0x%x\n", astypnames[CHAR], v);
+}
+
+static void
+p2w(int v)
+{
+       printf(PRTPREF "%s 0x%x\n", astypnames[SHORT], v);
+}
+
+static int
+leb128(int d)
+{
+       if (d > 127)
+               cerror("FIXME: leb128 > 127");
+       p1b(d);
+       return 1;
+}
+
+static void
+al128(int d)
+{
+       dwarfseg(DABBREV);
+       leb128(d);
+}
+
+static void
+apair(int d, int e)
+{
+       dwarfseg(DABBREV);
+       leb128(d);
+       leb128(e);
+}
+
+static void
+strng(char *s)
+{
+       printf(PRTPREF "\t.ascii \"%s\\0\"\n", s); /* XXX common code? */
+}
+
+static void
+istring(char *str)
+{
+       dwarfseg(DINFO);
+       strng(str);
+       debug_info_sz += (strlen(str) + 1);
+}
+
+static void
+dwslabstr(int lbl, char *s)
+{
+       dwslab(DSTR, lbl);
+       strng(s);
+}
+
+static void
+ilbl(int l)
+{
+       dwarfseg(DINFO);
+       printf(PRTPREF "%s " DLABEL "\n", astypnames[LONG], l);
+       debug_info_sz += (DW64 * 4 + 4);
+}
+
+static void
+il128(int d)
+{
+       dwarfseg(DINFO);
+       debug_info_sz += leb128(d);
+}
+
+static void
+p412l(int lbl)
+{
+       if (DW64)
+               printf(PRTPREF "%s 0xffffff00\n", astypnames[INT]);
+       printf(PRTPREF "%s " DLABEL "\n", astypnames[LONG], lbl);
+}
+
+static void
+info1b(int v)
+{
+       dwarfseg(DINFO);
+       p1b(v);
+       debug_info_sz++;
+}
+
+static void
+info2w(int v)
+{
+       dwarfseg(DINFO);
+       p2w(v);
+       debug_info_sz += 2;
+}
+
+static void
+info412l(int lbl)
+{
+       dwarfseg(DINFO);
+       p412l(lbl);
+       debug_info_sz += (DW64 * 8 + 4);
+}
+
+void
+dwarf_init(char *iname)
+{
+       char buf[MAXPATHLEN];
+       /*
+        * Setup sections.
+        * We'll print out the basic stuff early so that not
+        * so much context must be kept around.
+        */
+       dwname = iname;
+       debug_info_sz_lbl = dwlab();
+       debug_abbrev_beg_lbl = dwlab();
+
+       /* begin with setting up the compilation unit header */
+       info412l(debug_info_sz_lbl); debug_info_sz = 0;
+       info2w(DVERSION);
+       info412l(debug_abbrev_beg_lbl);
+       info1b(SZPOINT(VOID)/SZCHAR);
+
+       /* Define abbrev table */
+       dwslab(DABBREV, debug_abbrev_beg_lbl);
+
+       /* compile unit follows, both in abbrev and info table */
+       /* Recommended stuff here as in the documentation */
+       al128(1); /* always first entry */
+       al128(DW_TAG_compile_unit);
+       al128(DW_CHILDREN_yes);
+
+       apair(DW_AT_name, DW_FORM_strp); /* file name; e.g. foo.c */
+       apair(DW_AT_producer, DW_FORM_string); /* producer; PCC 1.2.3 */
+       apair(DW_AT_comp_dir, DW_FORM_string); /* working directory */
+       apair(DW_AT_language, DW_FORM_data1); /* C99 */
+       apair(DW_AT_low_pc, DW_FORM_addr); /* start text */
+       apair(DW_AT_high_pc, DW_FORM_addr); /* end text */
+       apair(0, 0);
+
+       /* Above in info table */
+       il128(1); /* first entry */
+       ilbl(dwcfl = dwlab());
+       istring(PACKAGE_STRING);
+       istring(getcwd(buf, MAXPATHLEN));
+       il128(DW_LANG_C99);
+       ilbl(dwbtext = dwlab());
+       ilbl(dwetext = dwlab());
+
+       locctr(PROG, NULL);
+       printf(PRTPREF DLABEL ":\n", dwbtext);
+}
+
+void
+dwarf_file(char *fn)
+{
+       /* if first file name, print out as initial and remember */
+       if (dwcfl) {
+               dwslabstr(dwcfl, fn);
+               dwcfl = 0;
+       }
+       /* XXX add more here */
+}
+
+void
+dwarf_end()
+{
+       locctr(PROG, NULL);
+       printf(PRTPREF DLABEL ":\n", dwetext);
+       if (dwcfl)
+               dwslabstr(dwcfl, dwname ? dwname : "<unknown>");
+       printf(PRTPREF "\t.set " DLABEL ",%d\n",
+           debug_info_sz_lbl, debug_info_sz);
+}
+
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/dwarf.h b/lang/pcc/pcc/cc/ccom/dwarf.h
new file mode 100644 (file)
index 0000000..a796b5c
--- /dev/null
@@ -0,0 +1,196 @@
+
+#define DW_TAG_array_type      0x01
+#define DW_TAG_class_type      0x02
+#define DW_TAG_entry_point     0x03
+#define DW_TAG_enumeration_type        0x04
+#define DW_TAG_formal_parameter        0x05
+#define DW_TAG_imported_declaration    0x08
+#define DW_TAG_label           0x0a
+#define DW_TAG_lexical_block   0x0b
+#define DW_TAG_member          0x0d
+#define DW_TAG_pointer_type    0x0f
+#define DW_TAG_reference_type  0x10
+#define DW_TAG_compile_unit    0x11
+#define DW_TAG_string_type     0x12
+#define DW_TAG_structure_type  0x13
+#define DW_TAG_subroutine_type 0x15
+#define DW_TAG_typedef         0x16
+#define DW_TAG_union_type      0x17
+#define DW_TAG_unspecified_parameters  0x18
+#define DW_TAG_variant         0x19
+#define DW_TAG_common_block    0x1a
+#define DW_TAG_common_inclusion        0x1b
+#define DW_TAG_inheritance     0x1c
+#define DW_TAG_inlined_subroutine      0x1d
+#define DW_TAG_module          0x1e
+#define DW_TAG_ptr_to_member_type      0x1f
+#define DW_TAG_set_type                0x20
+#define DW_TAG_subrange_type   0x21
+#define DW_TAG_with_stmt       0x22
+#define DW_TAG_access_declaration      0x23
+#define DW_TAG_base_type       0x24
+#define DW_TAG_catch_block     0x25
+#define DW_TAG_const_type      0x26
+#define DW_TAG_constant                0x27
+#define DW_TAG_enumerator      0x28
+#define DW_TAG_file_type       0x29
+#define DW_TAG_friend          0x2a
+#define DW_TAG_namelist                0x2b
+#define DW_TAG_namelist_item   0x2c
+#define DW_TAG_packed_type     0x2d
+#define DW_TAG_subprogram      0x2e
+#define DW_TAG_template_type_parameter 0x2f
+#define DW_TAG_template_value_parameter        0x30
+#define DW_TAG_thrown_type     0x31
+#define DW_TAG_try_block       0x32
+#define DW_TAG_variant_part    0x33
+#define DW_TAG_variable                0x34
+#define DW_TAG_volatile_type   0x35
+#define DW_TAG_dwarf_procedure 0x36
+#define DW_TAG_restrict_type   0x37
+#define DW_TAG_interface_type  0x38
+#define DW_TAG_namespace       0x39
+#define DW_TAG_imported_module 0x3a
+#define DW_TAG_unspecified_type        0x3b
+#define DW_TAG_partial_unit    0x3c
+#define DW_TAG_imported_unit   0x3d
+#define DW_TAG_condition       0x3f
+#define DW_TAG_shared_type     0x40
+#define DW_TAG_lo_user                 0x4080
+#define DW_TAG_hi_user         0xffff
+
+#define DW_CHILDREN_no         0
+#define DW_CHILDREN_yes                1
+
+#define DW_AT_sibling          0x01 /* reference */
+#define DW_AT_location         0x02 /* block, loclistptr */
+#define DW_AT_name             0x03 /* string */
+#define DW_AT_ordering         0x09 /* constant */
+#define DW_AT_byte_size                0x0b /* block, constant, reference */
+#define DW_AT_bit_offset       0x0c /* block, constant, reference */
+#define DW_AT_bit_size         0x0d /* block, constant, reference */
+#define DW_AT_stmt_list                0x10
+#define DW_AT_low_pc           0x11
+#define DW_AT_high_pc          0x12
+#define DW_AT_language         0x13
+#define DW_AT_discr            0x15
+#define DW_AT_discr_value      0x16
+#define DW_AT_visibility       0x17
+#define DW_AT_import           0x18
+#define DW_AT_string_length    0x19
+#define DW_AT_common_reference 0x1a
+#define DW_AT_comp_dir         0x1b
+#define DW_AT_const_value      0x1c
+#define DW_AT_containing_type  0x1d
+#define DW_AT_default_value    0x1e
+#define DW_AT_inline           0x20
+#define DW_AT_is_optional      0x21
+#define DW_AT_lower_bound      0x22
+#define DW_AT_producer         0x25
+#define DW_AT_prototyped       0x27
+#define DW_AT_return_addr      0x2a
+#define DW_AT_start_scope      0x2c
+#define DW_AT_bit_stride       0x2e
+#define DW_AT_upper_bound      0x2f
+#define DW_AT_abstract_origin  0x31
+#define DW_AT_accessibility    0x32
+#define DW_AT_address_class    0x33
+#define DW_AT_artificial       0x34
+#define DW_AT_base_types       0x35
+#define DW_AT_calling_convention 0x36
+#define DW_AT_count            0x37
+#define DW_AT_data_member_location 0x38
+#define DW_AT_decl_column      0x39
+#define DW_AT_decl_file                0x3a
+#define DW_AT_decl_line                0x3b
+#define DW_AT_declaration      0x3c
+#define DW_AT_discr_list       0x3d
+#define DW_AT_encoding         0x3e
+#define DW_AT_external         0x3f
+#define DW_AT_frame_base       0x40
+#define DW_AT_friend           0x41
+#define DW_AT_identifier_case  0x42
+#define DW_AT_macro_info       0x43
+#define DW_AT_namelist_item    0x44
+#define DW_AT_priority         0x45
+#define DW_AT_segment          0x46
+#define DW_AT_specification    0x47
+#define DW_AT_static_link      0x48
+#define DW_AT_type             0x49
+#define DW_AT_use_location     0x4a
+#define DW_AT_variable_parameter 0x4b
+#define DW_AT_virtuality       0x4c
+#define DW_AT_vtable_elem_location 0x4d
+#define DW_AT_allocated                0x4e
+#define DW_AT_associated       0x4f
+#define DW_AT_data_location    0x50
+#define DW_AT_byte_stride      0x51
+#define DW_AT_entry_pc         0x52
+#define DW_AT_use_UTF8         0x53
+#define DW_AT_extension                0x54
+#define DW_AT_ranges           0x55
+#define DW_AT_trampoline       0x56
+#define DW_AT_call_column      0x57
+#define DW_AT_call_file                0x58
+#define DW_AT_call_line                0x59
+#define DW_AT_description      0x5a
+#define DW_AT_binary_scale     0x5b
+#define DW_AT_decimal_scale    0x5c
+#define DW_AT_small            0x5d
+#define DW_AT_decimal_sign     0x5e
+#define DW_AT_digit_count      0x5f
+#define DW_AT_picture_string   0x60
+#define DW_AT_mutable          0x61
+#define DW_AT_threads_scaled   0x62
+#define DW_AT_explicit         0x63
+#define DW_AT_object_pointer   0x64
+#define DW_AT_endianity                0x65
+#define DW_AT_elemental                0x66
+#define DW_AT_pure             0x67
+#define DW_AT_recursive                0x68 /* flag */
+#define DW_AT_lo_user          0x2000
+#define DW_AT_hi_user          0x3fff
+
+#define DW_FORM_addr           0x01
+#define DW_FORM_block2         0x03
+#define DW_FORM_block4         0x04
+#define DW_FORM_data2          0x05 /* constant */
+#define DW_FORM_data4          0x06 /* constant, lineptr, loclistptr... */
+#define DW_FORM_data8          0x07
+#define DW_FORM_string         0x08
+#define DW_FORM_block          0x09
+#define DW_FORM_block1         0x0a
+#define DW_FORM_data1          0x0b /* constant */
+#define DW_FORM_flag           0x0c
+#define DW_FORM_sdata          0x0d /* constant */
+#define DW_FORM_strp           0x0e
+#define DW_FORM_udata          0x0f
+#define DW_FORM_ref_addr       0x10
+#define DW_FORM_ref1           0x11
+#define DW_FORM_ref2           0x12
+#define DW_FORM_ref4           0x13
+#define DW_FORM_ref8           0x14
+#define DW_FORM_ref_udata      0x15
+#define DW_FORM_indirect       0x16
+
+#define DW_LANG_C89            0x01
+#define DW_LANG_C              0x02
+#define DW_LANG_Ada83          0x03
+#define DW_LANG_C_plus_plus    0x04
+#define DW_LANG_Cobol74        0x05
+#define DW_LANG_Cobol85                0x06
+#define DW_LANG_Fortran77      0x07
+#define DW_LANG_Fortran90      0x08
+#define DW_LANG_Pascal83       0x09
+#define DW_LANG_Modula2                0x0a
+#define        DW_LANG_Java            0x0b
+#define DW_LANG_C99            0x0c
+#define DW_LANG_Ada95          0x0d
+#define DW_LANG_Fortran95      0x0e
+#define DW_LANG_PLI            0x0f
+#define DW_LANG_ObjC           0x10
+#define DW_LANG_ObjC_plus_plus 0x11
+#define DW_LANG_UPC            0x12
+#define DW_LANG_D              0x13
+#define DW_LANG_lo_user                0x8000
+#define DW_LANG_hi_user                0xffff
diff --git a/lang/pcc/pcc/cc/ccom/gcc_compat.c b/lang/pcc/pcc/cc/ccom/gcc_compat.c
new file mode 100644 (file)
index 0000000..374dad4
--- /dev/null
@@ -0,0 +1,1088 @@
+/*      $Id: gcc_compat.c,v 1.119 2015/11/13 17:11:40 ragge Exp $     */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Routines to support some of the gcc extensions to C.
+ */
+#ifdef GCC_COMPAT
+
+#include "pass1.h"
+#include "cgram.h"
+
+#include <string.h>
+
+#define        NODE P1ND
+#define        nfree p1nfree
+#define        tfree p1tfree
+
+static struct kw {
+       char *name, *ptr;
+       int rv;
+} kw[] = {
+/*
+ * Do NOT change the order of these entries unless you know 
+ * what you're doing!
+ */
+/* 0 */        { "__asm", NULL, C_ASM },
+/* 1 */        { "__signed", NULL, 0 },
+/* 2 */        { "__inline", NULL, 0 },
+/* 3 */        { "__const", NULL, 0 },
+/* 4 */        { "__asm__", NULL, C_ASM },
+/* 5 */        { "__inline__", NULL, 0 },
+/* 6 */        { "__thread", NULL, 0 },
+/* 7 */        { "__FUNCTION__", NULL, 0 },
+/* 8 */        { "__volatile", NULL, 0 },
+/* 9 */        { "__volatile__", NULL, 0 },
+/* 10 */{ "__restrict", NULL, -1 },
+/* 11 */{ "__typeof__", NULL, C_TYPEOF },
+/* 12 */{ "typeof", NULL, C_TYPEOF },
+/* 13 */{ "__extension__", NULL, -1 },
+/* 14 */{ "__signed__", NULL, 0 },
+/* 15 */{ "__attribute__", NULL, 0 },
+/* 16 */{ "__attribute", NULL, 0 },
+/* 17 */{ "__real__", NULL, 0 },
+/* 18 */{ "__imag__", NULL, 0 },
+/* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF },
+/* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 },
+/* 21 */{ "__alignof__", NULL, C_ALIGNOF },
+/* 22 */{ "__typeof", NULL, C_TYPEOF },
+/* 23 */{ "__alignof", NULL, C_ALIGNOF },
+/* 24 */{ "__restrict__", NULL, -1 },
+       { NULL, NULL, 0 },
+};
+
+/* g77 stuff */
+#if SZFLOAT == SZLONG
+#define G77_INTEGER LONG
+#define G77_UINTEGER ULONG
+#elif SZFLOAT == SZINT
+#define G77_INTEGER INT
+#define G77_UINTEGER UNSIGNED
+#else
+#error fix g77 stuff
+#endif
+#if SZFLOAT*2 == SZLONG
+#define G77_LONGINT LONG
+#define G77_ULONGINT ULONG
+#elif SZFLOAT*2 == SZLONGLONG
+#define G77_LONGINT LONGLONG
+#define G77_ULONGINT ULONGLONG
+#else
+#error fix g77 long stuff
+#endif
+
+static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT };
+static char *g77n[] = { "__g77_integer", "__g77_uinteger",
+       "__g77_longint", "__g77_ulongint" };
+
+#ifdef TARGET_TIMODE
+static char *loti, *hiti, *TISTR;
+static struct symtab *tisp, *ucmpti2sp, *cmpti2sp, *subvti3sp,
+       *addvti3sp, *mulvti3sp, *divti3sp, *udivti3sp, *modti3sp, *umodti3sp,
+       *ashldi3sp, *ashrdi3sp, *lshrdi3sp, *floatuntixfsp;
+
+static struct symtab *
+addftn(char *n, TWORD t)
+{
+       NODE *p = block(TYPE, 0, 0, 0, 0, 0);
+       struct symtab *sp;
+
+       sp = lookup(addname(n), 0);
+       p->n_type = INCREF(t) + (FTN-PTR);
+       p->n_sp = sp;
+       p->n_df = memset(permalloc(sizeof(union dimfun)), 0,
+           sizeof(union dimfun));
+       defid(p, EXTERN);
+       nfree(p);
+       return sp;
+}
+
+static struct symtab *
+addstr(char *n)
+{
+       NODE *p = block(NAME, NIL, NIL, FLOAT, 0, 0);
+       struct symtab *sp;
+       NODE *q;
+       struct attr *ap;
+       struct rstack *rp;
+       extern struct rstack *rpole;
+
+       p->n_type = ctype(ULONGLONG);
+       rpole = rp = bstruct(NULL, STNAME, NULL);
+       soumemb(p, loti, 0);
+       soumemb(p, hiti, 0);
+       q = dclstruct(rp);
+       sp = q->n_sp = lookup(addname(n), 0);
+       defid(q, TYPEDEF);
+       ap = attr_new(GCC_ATYP_MODE, 3);
+       ap->sarg(0) = addname("TI");
+       ap->iarg(1) = 0;
+       sp->sap = attr_add(sp->sap, ap);
+       nfree(q);
+       nfree(p);
+
+       return sp;
+}
+#endif
+
+void
+gcc_init(void)
+{
+       struct kw *kwp;
+       NODE *p;
+       TWORD t;
+       int i, d_debug;
+
+       d_debug = ddebug;
+       ddebug = 0;
+       for (kwp = kw; kwp->name; kwp++)
+               kwp->ptr = addname(kwp->name);
+
+       for (i = 0; i < 4; i++) {
+               struct symtab *sp;
+               t = ctype(g77t[i]);
+               p = block(NAME, NIL, NIL, t, NULL, 0);
+               sp = lookup(addname(g77n[i]), 0);
+               p->n_sp = sp;
+               defid(p, TYPEDEF);
+               nfree(p);
+       }
+       ddebug = d_debug;
+#ifdef TARGET_TIMODE
+       {
+               struct attr *ap;
+
+               loti = addname("__loti");
+               hiti = addname("__hiti");
+               TISTR = addname("TI");
+
+               tisp = addstr("0ti");
+
+               cmpti2sp = addftn("__cmpti2", INT);
+               ucmpti2sp = addftn("__ucmpti2", INT);
+
+               addvti3sp = addftn("__addvti3", STRTY);
+               addvti3sp->sap = tisp->sap;
+               subvti3sp = addftn("__subvti3", STRTY);
+               subvti3sp->sap = tisp->sap;
+               mulvti3sp = addftn("__mulvti3", STRTY);
+               mulvti3sp->sap = tisp->sap;
+               divti3sp = addftn("__divti3", STRTY);
+               divti3sp->sap = tisp->sap;
+               modti3sp = addftn("__modti3", STRTY);
+               modti3sp->sap = tisp->sap;
+
+               ap = attr_new(GCC_ATYP_MODE, 3);
+               ap->sarg(0) = TISTR;
+               ap->iarg(1) = 1;
+               ap = attr_add(tisp->sap, ap);
+               udivti3sp = addftn("__udivti3", STRTY);
+               udivti3sp->sap = ap;
+               umodti3sp = addftn("__umodti3", STRTY);
+               umodti3sp->sap = ap;
+               ashldi3sp = addftn("__ashldi3", ctype(LONGLONG));
+               ashldi3sp->sap = ap;
+               ashrdi3sp = addftn("__ashrdi3", ctype(LONGLONG));
+               ashrdi3sp->sap = ap;
+               lshrdi3sp = addftn("__lshrdi3", ctype(LONGLONG));
+               lshrdi3sp->sap = ap;
+
+               floatuntixfsp = addftn("__floatuntixf", LDOUBLE);
+       }
+#endif
+}
+
+#define        TS      "\n#pragma tls\n# %d\n"
+#define        TLLEN   sizeof(TS)+10
+/*
+ * See if a string matches a gcc keyword.
+ */
+int
+gcc_keyword(char *str)
+{
+       extern int inattr, parlvl, parbal;
+       char tlbuf[TLLEN], *tw;
+       struct kw *kwp;
+       int i;
+
+       /* XXX hack, should pass everything in expressions */
+       if (str == kw[21].ptr)
+               return kw[21].rv;
+
+       if (inattr)
+               return 0;
+
+       for (i = 0, kwp = kw; kwp->name; kwp++, i++)
+               if (str == kwp->ptr)
+                       break;
+       if (kwp->name == NULL)
+               return 0;
+       if (kwp->rv)
+               return kwp->rv;
+       switch (i) {
+       case 1:  /* __signed */
+       case 14: /* __signed__ */
+               yylval.type = SIGNED;
+               return C_TYPE;
+       case 2: /* __inline */
+       case 5: /* __inline__ */
+               yylval.type = INLINE;
+               return C_FUNSPEC;
+       case 3: /* __const */
+               yylval.type = CON;
+               return C_QUALIFIER;
+       case 6: /* __thread */
+               snprintf(tlbuf, TLLEN, TS, lineno);
+               tw = &tlbuf[strlen(tlbuf)];
+               while (tw > tlbuf)
+                       cunput(*--tw);
+               return -1;
+       case 7: /* __FUNCTION__ */
+       case 20: /* __PRETTY_FUNCTION__ */
+               if (cftnsp == NULL) {
+                       uerror("%s outside function", kwp->name);
+                       yylval.strp = "";
+               } else
+                       yylval.strp = cftnsp->sname; /* XXX - not C99 */
+               return C_STRING;
+       case 8: /* __volatile */
+       case 9: /* __volatile__ */
+               yylval.type = VOL;
+               return C_QUALIFIER;
+       case 15: /* __attribute__ */
+       case 16: /* __attribute */
+               inattr = 1;
+               parlvl = parbal;
+               return C_ATTRIBUTE;
+       case 17: /* __real__ */
+               yylval.intval = XREAL;
+               return C_UNOP;
+       case 18: /* __imag__ */
+               yylval.intval = XIMAG;
+               return C_UNOP;
+       }
+       cerror("gcc_keyword");
+       return 0;
+}
+
+#ifndef TARGET_ATTR
+#define        TARGET_ATTR(p, sue)             0
+#endif
+#ifndef        ALMAX
+#define        ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG)
+#endif
+
+/* allowed number of args */
+#define        A_0ARG  0x01
+#define        A_1ARG  0x02
+#define        A_2ARG  0x04
+#define        A_3ARG  0x08
+/* arg # is a name */
+#define        A1_NAME 0x10
+#define        A2_NAME 0x20
+#define        A3_NAME 0x40
+#define        A_MANY  0x80
+/* arg # is "string" */
+#define        A1_STR  0x100
+#define        A2_STR  0x200
+#define        A3_STR  0x400
+
+#ifdef __MSC__
+#define        CS(x)
+#else
+#define CS(x) [x] =
+#endif
+
+struct atax {
+       int typ;
+       char *name;
+} atax[GCC_ATYP_MAX] = {
+       CS(ATTR_NONE)           { 0, NULL },
+       CS(ATTR_COMPLEX)        { 0, NULL },
+       CS(xxxATTR_BASETYP)     { 0, NULL },
+       CS(ATTR_QUALTYP)        { 0, NULL },
+       CS(ATTR_STRUCT)         { 0, NULL },
+       CS(ATTR_ALIGNED)        { A_0ARG|A_1ARG, "aligned" },
+       CS(ATTR_NORETURN)       { A_0ARG, "noreturn" },
+       CS(ATTR_P1LABELS)       { A_0ARG, "p1labels" },
+       CS(ATTR_SONAME)         { A_1ARG|A1_STR, "soname" },
+       CS(GCC_ATYP_PACKED)     { A_0ARG|A_1ARG, "packed" },
+       CS(GCC_ATYP_SECTION)    { A_1ARG|A1_STR, "section" },
+       CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" },
+       CS(GCC_ATYP_UNUSED)     { A_0ARG, "unused" },
+       CS(GCC_ATYP_DEPRECATED) { A_0ARG, "deprecated" },
+       CS(GCC_ATYP_MAYALIAS)   { A_0ARG, "may_alias" },
+       CS(GCC_ATYP_MODE)       { A_1ARG|A1_NAME, "mode" },
+       CS(GCC_ATYP_FORMAT)     { A_3ARG|A1_NAME, "format" },
+       CS(GCC_ATYP_NONNULL)    { A_MANY, "nonnull" },
+       CS(GCC_ATYP_SENTINEL)   { A_0ARG|A_1ARG, "sentinel" },
+       CS(GCC_ATYP_WEAK)       { A_0ARG, "weak" },
+       CS(GCC_ATYP_FORMATARG)  { A_1ARG, "format_arg" },
+       CS(GCC_ATYP_GNU_INLINE) { A_0ARG, "gnu_inline" },
+       CS(GCC_ATYP_MALLOC)     { A_0ARG, "malloc" },
+       CS(GCC_ATYP_NOTHROW)    { A_0ARG, "nothrow" },
+       CS(GCC_ATYP_CONST)      { A_0ARG, "const" },
+       CS(GCC_ATYP_PURE)       { A_0ARG, "pure" },
+       CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" },
+       CS(GCC_ATYP_DESTRUCTOR) { A_0ARG, "destructor" },
+       CS(GCC_ATYP_VISIBILITY) { A_1ARG|A1_STR, "visibility" },
+       CS(GCC_ATYP_STDCALL)    { A_0ARG, "stdcall" },
+       CS(GCC_ATYP_CDECL)      { A_0ARG, "cdecl" },
+       CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" },
+       CS(GCC_ATYP_USED)       { A_0ARG, "used" },
+       CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" },
+       CS(GCC_ATYP_NOINLINE)   { A_0ARG, "noinline" },
+       CS(GCC_ATYP_ALIAS)      { A_1ARG|A1_STR, "alias" },
+       CS(GCC_ATYP_WEAKREF)    { A_0ARG|A_1ARG|A1_STR, "weakref" },
+       CS(GCC_ATYP_ALLOCSZ)    { A_1ARG|A_2ARG, "alloc_size" },
+       CS(GCC_ATYP_ALW_INL)    { A_0ARG, "always_inline" },
+       CS(GCC_ATYP_TLSMODEL)   { A_1ARG|A1_STR, "tls_model" },
+       CS(GCC_ATYP_ALIASWEAK)  { A_1ARG|A1_STR, "aliasweak" },
+       CS(GCC_ATYP_RETURNS_TWICE) { A_0ARG, "returns_twice" },
+       CS(GCC_ATYP_WARNING)    { A_1ARG|A1_STR, "warning" },
+       CS(GCC_ATYP_NOCLONE)    { A_0ARG, "noclone" },
+       CS(GCC_ATYP_REGPARM)    { A_1ARG, "regparm" },
+       CS(GCC_ATYP_FASTCALL)   { A_0ARG, "fastcall" },
+
+       CS(GCC_ATYP_BOUNDED)    { A_3ARG|A_MANY|A1_NAME, "bounded" },
+
+       CS(GCC_ATYP_WEAKIMPORT) { A_0ARG, "weak_import" },
+};
+
+#if SZPOINT(CHAR) == SZLONGLONG
+#define        GPT     LONGLONG
+#else
+#define        GPT     INT
+#endif
+
+struct atax mods[] = {
+       { 0, NULL },
+       { INT, "SI" },
+       { INT, "word" },
+       { GPT, "pointer" },
+       { CHAR, "byte" },
+       { CHAR, "QI" },
+       { SHORT, "HI" },
+       { LONGLONG, "DI" },
+       { FLOAT, "SF" },
+       { DOUBLE, "DF" },
+       { LDOUBLE, "XF" },
+       { FCOMPLEX, "SC" },
+       { COMPLEX, "DC" },
+       { LCOMPLEX, "XC" },
+       { INT, "libgcc_cmp_return" },
+       { INT, "libgcc_shift_count" },
+       { LONG, "unwind_word" },
+#ifdef TARGET_TIMODE
+       { 800, "TI" },
+#endif
+#ifdef TARGET_MODS
+       TARGET_MODS
+#endif
+};
+#define        ATSZ    (sizeof(mods)/sizeof(mods[0]))
+
+static int
+amatch(char *s, struct atax *at, int mx)
+{
+       int i, len;
+
+       if (s[0] == '_' && s[1] == '_')
+               s += 2;
+       len = strlen(s);
+       if (len > 2 && s[len-1] == '_' && s[len-2] == '_')
+               len -= 2;
+       for (i = 0; i < mx; i++) {
+               char *t = at[i].name;
+               if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0)
+                       return i;
+       }
+       return 0;
+}
+
+static void
+setaarg(int str, union aarg *aa, NODE *p)
+{
+       if (str) {
+               if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) ||
+                   ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME))
+                       uerror("bad arg to attribute");
+               if (p->n_op == STRING) {
+                       aa->sarg = p->n_name; /* saved in cgram.y */
+               } else
+                       aa->sarg = (char *)p->n_sp;
+               nfree(p);
+       } else
+               aa->iarg = (int)icons(eve(p));
+}
+
+/*
+ * Parse attributes from an argument list.
+ */
+static struct attr *
+gcc_attribs(NODE *p)
+{
+       NODE *q, *r;
+       struct attr *ap;
+       char *name = NULL, *c;
+       int cw, attr, narg;
+
+       if (p->n_op == NAME) {
+               name = (char *)p->n_sp;
+       } else if (p->n_op == CALL || p->n_op == UCALL) {
+               name = (char *)p->n_left->n_sp;
+       } else if (p->n_op == ICON && p->n_type == STRTY) {
+               return NULL;
+       } else
+               cerror("bad variable attribute");
+
+       if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) {
+               warner(Wattributes, name);
+               ap = NULL;
+               goto out;
+       }
+       narg = 0;
+       if (p->n_op == CALL)
+               for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left)
+                       narg++;
+
+       cw = atax[attr].typ;
+       if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) {
+               uerror("wrong attribute arg count");
+               return NULL;
+       }
+       ap = attr_new(attr, 3); /* XXX should be narg */
+       q = p->n_right;
+
+       switch (narg) {
+       default:
+               /* XXX */
+               while (narg-- > 3) {
+                       r = q;
+                       q = q->n_left;
+                       tfree(r->n_right);
+                       nfree(r);
+               }
+               /* FALLTHROUGH */
+       case 3:
+               setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right);
+               r = q;
+               q = q->n_left;
+               nfree(r);
+               /* FALLTHROUGH */
+       case 2:
+               setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right);
+               r = q;
+               q = q->n_left;
+               nfree(r);
+               /* FALLTHROUGH */
+       case 1:
+               setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q);
+               p->n_op = UCALL;
+               /* FALLTHROUGH */
+       case 0:
+               break;
+       }
+
+       /* some attributes must be massaged special */
+       switch (attr) {
+       case ATTR_ALIGNED:
+               if (narg == 0)
+                       ap->aa[0].iarg = ALMAX;
+               else
+                       ap->aa[0].iarg *= SZCHAR;
+               break;
+       case GCC_ATYP_PACKED:
+               if (narg == 0)
+                       ap->aa[0].iarg = 1; /* bitwise align */
+               else
+                       ap->aa[0].iarg *= SZCHAR;
+               break;
+
+       case GCC_ATYP_VISIBILITY:
+               c = ap->aa[0].sarg;
+               if (strcmp(c, "default") && strcmp(c, "hidden") &&
+                   strcmp(c, "internal") && strcmp(c, "protected"))
+                       werror("unknown visibility %s", c);
+               break;
+
+       case GCC_ATYP_TLSMODEL:
+               c = ap->aa[0].sarg;
+               if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") &&
+                   strcmp(c, "initial-exec") && strcmp(c, "local-exec"))
+                       werror("unknown tls model %s", c);
+               break;
+
+       default:
+               break;
+       }
+out:
+       return ap;
+}
+
+/*
+ * Extract attributes from a node tree and return attribute entries 
+ * based on its contents.
+ */
+struct attr *
+gcc_attr_parse(NODE *p)
+{
+       struct attr *b, *c;
+
+       if (p == NIL)
+               return NULL;
+
+       if (p->n_op != CM) {
+               b = gcc_attribs(p);
+               tfree(p);
+       } else {
+               b = gcc_attr_parse(p->n_left);
+               c = gcc_attr_parse(p->n_right);
+               nfree(p);
+               b = b ? attr_add(b, c) : c;
+       }
+       return b;
+}
+
+/*
+ * Fixup struct/unions depending on attributes.
+ */
+void
+gcc_tcattrfix(NODE *p)
+{
+       struct symtab *sp;
+       struct attr *ap;
+       int sz, coff, csz, al, oal, mxal;
+
+       if (!ISSOU(p->n_type)) /* only for structs or unions */
+               return;
+       if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL)
+               return; /* nothing to fix */
+
+       al = ap->iarg(0);
+       mxal = 0;
+
+       /* Must repack struct */
+       coff = csz = 0;
+       for (sp = strmemb(ap); sp; sp = sp->snext) {
+               oal = talign(sp->stype, sp->sap);
+               if (oal > al)
+                       oal = al;
+               if (mxal < oal)
+                       mxal = oal;
+               if (sp->sclass & FIELD)
+                       sz = sp->sclass&FLDSIZ;
+               else
+                       sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+               sp->soffset = upoff(sz, oal, &coff);
+               if (coff > csz)
+                       csz = coff;
+               if (p->n_type == UNIONTY)
+                       coff = 0;
+       }
+       if (mxal < ALCHAR)
+               mxal = ALCHAR; /* for bitfields */
+       SETOFF(csz, mxal); /* Roundup to whatever */
+
+       ap = attr_find(p->n_ap, ATTR_STRUCT);
+       ap->amsize = csz;
+       ap = attr_find(p->n_ap, ATTR_ALIGNED);
+       ap->iarg(0) = mxal;
+
+}
+
+/*
+ * gcc-specific pragmas.
+ */
+int
+pragmas_gcc(char *t)
+{
+       char u;
+       extern char *pragstore;
+
+       if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) {
+               int warn, err;
+
+               if (strcmp((t = pragtok(NULL)), "ignored") == 0)
+                       warn = 0, err = 0;
+               else if (strcmp(t, "warning") == 0)
+                       warn = 1, err = 0;
+               else if (strcmp(t, "error") == 0)
+                       warn = 1, err = 1;
+               else
+                       return 1;
+
+               if (eat('\"') || eat('-'))
+                       return 1;
+
+               for (t = pragstore; *t && *t != '\"'; t++)
+                       ;
+
+               u = *t;
+               *t = 0;
+               Wset(pragstore + 1, warn, err);
+               *t = u;
+       } else if (strcmp(t, "poison") == 0) {
+               /* currently ignore */;
+       } else if (strcmp(t, "visibility") == 0) {
+               /* currently ignore */;
+       } else if (strcmp(t, "system_header") == 0) {
+               /* currently ignore */;
+       } else
+               werror("gcc pragma unsupported");
+       return 0;
+}
+
+/*
+ * Fixup types when modes given in defid().
+ */
+void
+gcc_modefix(NODE *p)
+{
+       struct attr *ap;
+#ifdef TARGET_TIMODE
+       struct attr *a2;
+#endif
+       struct symtab *sp;
+       char *s;
+       int i, u;
+
+       if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL)
+               return;
+
+       u = ISUNSIGNED(BTYPE(p->n_type));
+       if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) {
+               werror("unknown mode arg %s", ap->aa[0].sarg);
+               return;
+       }
+       i = mods[i].typ;
+       if (i >= 1 && i <= MAXTYPES) {
+               MODTYPE(p->n_type, ctype(i));
+               if (u)
+                       p->n_type = ENUNSIGN(p->n_type);
+       } else switch (i) {
+#ifdef TARGET_TIMODE
+       case 800:
+               if (BTYPE(p->n_type) == STRTY)
+                       break;
+               MODTYPE(p->n_type, tisp->stype);
+               p->n_df = tisp->sdf;
+               p->n_ap = tisp->sap;
+               if (ap->iarg(1) == u)
+                       break;
+               /* must add a new mode struct to avoid overwriting */
+               a2 = attr_new(GCC_ATYP_MODE, 3);
+               a2->sarg(0) = ap->sarg(0);
+               a2->iarg(1) = u;
+               p->n_ap = attr_add(p->n_ap, a2);
+               break;
+#endif
+       case FCOMPLEX:
+       case COMPLEX:
+       case LCOMPLEX:
+               /* Destination should have been converted to a struct already */
+               if (BTYPE(p->n_type) != STRTY)
+                       uerror("gcc_modefix: complex not STRTY");
+               i -= (FCOMPLEX-FLOAT);
+               ap = strattr(p->n_ap);
+               sp = ap->amlist;
+               if (sp->stype == (unsigned)i)
+                       return; /* Already correct type */
+               /* we must change to another struct */
+               s = i == FLOAT ? "0f" :
+                   i == DOUBLE ? "0d" :
+                   i == LDOUBLE ? "0l" : 0;
+               sp = lookup(addname(s), 0);
+               for (ap = sp->sap; ap != NULL; ap = ap->next)
+                       p->n_ap = attr_add(p->n_ap, attr_dup(ap));
+               break;
+
+       default:
+               cerror("gcc_modefix");
+       }
+}
+
+#ifdef TARGET_TIMODE
+
+/*
+ * Return ap if this node is a TI node, else NULL.
+ */
+struct attr *
+isti(NODE *p)
+{
+       struct attr *ap;
+
+       if (p->n_type != STRTY)
+               return NULL;
+       if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL)
+               return NULL;
+       if (strcmp(ap->sarg(0), TISTR))
+               return NULL;
+       return ap;
+}
+
+static char *
+tistack(void)
+{
+       struct symtab *sp, *sp2;
+       char buf[12];
+       NODE *q;
+       char *n;
+
+       /* allocate space on stack */
+       snprintf(buf, 12, "%d", getlab());
+       n = addname(buf);
+       sp = lookup(n, 0);
+       sp2 = tisp;
+       q = block(TYPE, NIL, NIL, sp2->stype, sp2->sdf, sp2->sap);
+       q->n_sp = sp;
+       nidcl2(q, AUTO, 0);
+       nfree(q);
+       return n;
+}
+
+#define        biop(x,y,z) block(x, y, z, INT, 0, 0)
+/*
+ * Create a ti node from something not a ti node.
+ * This usually means:  allocate space on stack, store val, give stack address.
+ */
+static NODE *
+ticast(NODE *p, int u)
+{
+       CONSZ val;
+       NODE *q;
+       char *n;
+       int u2;
+
+       n = tistack();
+
+       /* store val */
+       switch (p->n_op) {
+       case ICON:
+               val = 0;
+               if (u == 0 && p->n_lval < 0)
+                       val = -1;
+               q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti)));
+               q = buildtree(ASSIGN, q, p);
+               p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti));
+               p = eve(biop(ASSIGN, p, bcon(val)));
+               q = buildtree(COMOP, q, p);
+               p = buildtree(COMOP, q, eve(bdty(NAME, n)));
+               break;
+
+       default:
+               u2 = ISUNSIGNED(p->n_type);
+               q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti)));
+               q = buildtree(ASSIGN, q, p);
+               p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti));
+               if (u2) {
+                       p = eve(biop(ASSIGN, p, bcon(0)));
+               } else {
+                       q = buildtree(ASSIGN, eve(ccopy(p)), q);
+                       p = buildtree(RSEQ, eve(p), bcon(SZLONG-1));
+               }
+               q = buildtree(COMOP, q, p);
+               p = buildtree(COMOP, q, eve(bdty(NAME, n)));
+               break;
+       }
+       return p;
+}
+
+/*
+ * Check if we may have to do a cast to/from TI.
+ */
+NODE *
+gcc_eval_ticast(int op, NODE *p1, NODE *p2)
+{
+       struct attr *a1, *a2;
+       int t;
+
+       if ((a1 = isti(p1)) == NULL && (a2 = isti(p2)) == NULL)
+               return NIL;
+
+       if (op == RETURN)
+               p1 = ccopy(p1);
+       if (a1 == NULL) {
+               if (a2 == NULL)
+                       cerror("gcc_eval_ticast error");
+               switch (p1->n_type) {
+               case LDOUBLE:
+                       p2 = doacall(floatuntixfsp,
+                           nametree(floatuntixfsp), p2);
+                       tfree(p1);
+                       break;
+               case ULONG:
+               case LONG:
+                       p2 = cast(structref(p2, DOT, loti), p1->n_type, 0);
+                       tfree(p1);
+                       break;
+               case VOID:
+                       return NIL;
+               default:
+                       uerror("gcc_eval_ticast: %d", p1->n_type);
+               }
+               return p2;
+       }
+       /* p2 can be anything, but we must cast it to p1 */
+       t = a1->iarg(1);
+
+       if (p2->n_type == STRTY &&
+           (a2 = attr_find(p2->n_ap, GCC_ATYP_MODE)) &&
+           strcmp(a2->sarg(0), TISTR) == 0) {
+               /* Already TI, just add extra mode bits */
+               a2 = attr_new(GCC_ATYP_MODE, 3);
+               a2->sarg(0) = TISTR;
+               a2->iarg(1) = t;
+               p2->n_ap = attr_add(p2->n_ap, a2);
+       } else  {
+               p2 = ticast(p2, t);
+       }
+       tfree(p1);
+       return p2;
+}
+
+/*
+ * Apply a unary op on a TI value.
+ */
+NODE *
+gcc_eval_tiuni(int op, NODE *p1)
+{
+       struct attr *a1;
+       NODE *p;
+
+       if ((a1 = isti(p1)) == NULL)
+               return NULL;
+
+       switch (op) {
+       case UMINUS:
+               p = ticast(bcon(0), 0);
+               p = buildtree(CM, p, p1);
+               p = doacall(subvti3sp, nametree(subvti3sp), p);
+               break;
+
+       case UMUL:
+               p = NULL;
+       default:
+               uerror("unsupported unary TI mode op %d", op);
+               p = NULL;
+       }
+       return p;
+}
+
+/*
+ * Evaluate AND/OR/ER.  p1 and p2 are pointers to ti struct.
+ */
+static NODE *
+gcc_andorer(int op, NODE *p1, NODE *p2)
+{
+       char *n = tistack();
+       NODE *p, *t1, *t2, *p3;
+
+       t1 = tempnode(0, p1->n_type, p1->n_df, p1->n_ap);
+       t2 = tempnode(0, p2->n_type, p2->n_df, p2->n_ap);
+
+       p1 = buildtree(ASSIGN, ccopy(t1), p1);
+       p2 = buildtree(ASSIGN, ccopy(t2), p2);
+       p = buildtree(COMOP, p1, p2);
+
+       p3 = buildtree(ADDROF, eve(bdty(NAME, n)), NIL);
+       p1 = buildtree(ASSIGN, structref(ccopy(p3), STREF, hiti),
+           buildtree(op, structref(ccopy(t1), STREF, hiti),
+           structref(ccopy(t2), STREF, hiti)));
+       p = buildtree(COMOP, p, p1);
+       p1 = buildtree(ASSIGN, structref(ccopy(p3), STREF, loti),
+           buildtree(op, structref(t1, STREF, loti),
+           structref(t2, STREF, loti)));
+       p = buildtree(COMOP, p, p1);
+       p = buildtree(COMOP, p, buildtree(UMUL, p3, NIL));
+       return p;
+}
+
+/*
+ * Ensure that a 128-bit assign succeeds.
+ * If left is not TI, make right not TI,
+ * else if left _is_ TI, make right TI,
+ * else do nothing.
+ */
+static NODE *
+timodeassign(NODE *p1, NODE *p2)
+{
+       struct attr *a1, *a2;
+
+       a1 = isti(p1);
+       a2 = isti(p2);
+       if (a1 && a2 == NULL) {
+               p2 = ticast(p2, a1->iarg(1));
+       } else if (a1 == NULL && a2) {
+               if (ISFTY(p1->n_type))
+                       cerror("cannot TI float convert");
+               p2 = structref(p2, DOT, loti);
+       }
+       return buildtree(ASSIGN, p1, p2);
+}
+
+/*
+ * Evaluate 128-bit operands.
+ */
+NODE *
+gcc_eval_timode(int op, NODE *p1, NODE *p2)
+{
+       struct attr *a1, *a2;
+       struct symtab *sp;
+       NODE *p;
+       int isu = 0, gotti, isaop;
+
+       if (op == CM)
+               return buildtree(op, p1, p2);
+
+       a1 = isti(p1);
+       a2 = isti(p2);
+
+       if (a1 == NULL && a2 == NULL)
+               return NULL;
+
+       if (op == ASSIGN)
+               return timodeassign(p1, p2);
+
+       gotti = (a1 != NULL);
+       gotti += (a2 != NULL);
+
+       if (gotti == 0)
+               return NULL;
+
+       if (a1 != NULL)
+               isu = a1->iarg(1);
+       if (a2 != NULL && !isu)
+               isu = a2->iarg(1);
+
+       if (a1 == NULL) {
+               p1 = ticast(p1, isu);
+               a1 = attr_find(p1->n_ap, GCC_ATYP_MODE);
+       }
+       if (a2 == NULL && (cdope(op) & SHFFLG) == 0) {
+               p2 = ticast(p2, isu);
+               a2 = attr_find(p2->n_ap, GCC_ATYP_MODE);
+       }
+
+       switch (op) {
+       case GT:
+       case GE:
+       case LT:
+       case LE:
+       case EQ:
+       case NE:
+               /* change to call */
+               sp = isu ? ucmpti2sp : cmpti2sp;
+               p = doacall(sp, nametree(sp), buildtree(CM, p1, p2));
+               p = buildtree(op, p, bcon(1));
+               break;
+
+       case AND:
+       case ER:
+       case OR:
+               if (!ISPTR(p1->n_type))
+                       p1 = buildtree(ADDROF, p1, NIL);
+               if (!ISPTR(p2->n_type))
+                       p2 = buildtree(ADDROF, p2, NIL);
+               p = gcc_andorer(op, p1, p2);
+               break;
+
+       case LSEQ:
+       case RSEQ:
+       case LS:
+       case RS:
+               sp = op == LS || op == LSEQ ? ashldi3sp :
+                   isu ? lshrdi3sp : ashrdi3sp;
+               p2 = cast(p2, INT, 0);
+               /* XXX p1 ccopy may have side effects */
+               p = doacall(sp, nametree(sp), buildtree(CM, ccopy(p1), p2));
+               if (op == LSEQ || op == RSEQ) {
+                       p = buildtree(ASSIGN, p1, p);
+               } else
+                       tfree(p1);
+               break;
+
+       case PLUSEQ:
+       case MINUSEQ:
+       case MULEQ:
+       case DIVEQ:
+       case MODEQ:
+       case PLUS:
+       case MINUS:
+       case MUL:
+       case DIV:
+       case MOD:
+               isaop = (cdope(op)&ASGOPFLG);
+               if (isaop)
+                       op = UNASG op;
+               sp = op == PLUS ? addvti3sp :
+                   op == MINUS ? subvti3sp :
+                   op == MUL ? mulvti3sp :
+                   op == DIV ? (isu ? udivti3sp : divti3sp) :
+                   op == MOD ? (isu ? umodti3sp : modti3sp) : 0;
+               /* XXX p1 ccopy may have side effects */
+               p = doacall(sp, nametree(sp), buildtree(CM, ccopy(p1), p2));
+               if (isaop)
+                       p = buildtree(ASSIGN, p1, p);
+               else
+                       tfree(p1);
+               break;
+
+       default:
+               uerror("unsupported TImode op %d", op);
+               p = bcon(0);
+       }
+       return p;
+}
+#endif
+
+#ifdef PCC_DEBUG
+void
+dump_attr(struct attr *ap)
+{
+       printf("attributes; ");
+       for (; ap; ap = ap->next) {
+               if (ap->atype >= GCC_ATYP_MAX) {
+                       printf("bad type %d, ", ap->atype);
+               } else if (atax[ap->atype].name == 0) {
+                       char *c = ap->atype == ATTR_COMPLEX ? "complex" :
+                           ap->atype == ATTR_STRUCT ? "struct" : "badtype";
+                       printf("%s, ", c);
+               } else {
+                       printf("%s: ", atax[ap->atype].name);
+                       if (atax[ap->atype].typ & A1_STR)
+                               printf("%s ", ap->sarg(0));
+                       else
+                               printf("%d %d %d, ", ap->iarg(0),
+                                   ap->iarg(1), ap->iarg(2));
+               }
+       }
+       printf("\n");
+}
+#endif
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/init.c b/lang/pcc/pcc/cc/ccom/init.c
new file mode 100644 (file)
index 0000000..a18a557
--- /dev/null
@@ -0,0 +1,1284 @@
+/*     $Id: init.c,v 1.99 2015/11/17 19:19:40 ragge Exp $      */
+
+/*
+ * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass1.h"
+#include "unicode.h"
+#include <string.h>
+
+#define        NODE P1ND
+#define        tfree p1tfree
+#define        nfree p1nfree
+#define        fwalk p1fwalk
+
+/*
+ * The following machine-dependent routines may be called during
+ * initialization:
+ * 
+ * zbits(OFFSZ, int)   - sets int bits of zero at position OFFSZ.
+ * infld(CONSZ off, int fsz, CONSZ val)
+ *                     - sets the bitfield val starting at off and size fsz.
+ * ninval(CONSZ off, int fsz, NODE *)
+ *                     - prints an integer constant which may have
+ *                       a label associated with it, located at off and
+ *                       size fsz.
+ *
+ * Initialization may be of different kind:
+ * - Initialization at compile-time, all values are constants and laid
+ *   out in memory. Static or extern variables outside functions.
+ * - Initialization at run-time, written to their values as code.
+ *
+ * Currently run-time-initialized variables are only initialized by using
+ * move instructions.  An optimization might be to detect that it is
+ * initialized with constants and therefore copied from readonly memory.
+ */
+
+/*
+ * The base element(s) of an initialized variable is kept in a linked 
+ * list, allocated while initialized.
+ *
+ * When a scalar is found, entries are popped of the instk until it's
+ * possible to find an entry for a new scalar; then onstk() is called 
+ * to get the correct type and size of that scalar.
+ *
+ * If a right brace is found, pop the stack until a matching left brace
+ * were found while filling the elements with zeros.  This left brace is
+ * also marking where the current level is for designated initializations.
+ *
+ * Position entries are increased when traversing back down into the stack.
+ */
+
+/*
+ * Good-to-know entries from symtab:
+ *     soffset - # of bits from beginning of this structure.
+ */
+
+/*
+ * TO FIX:
+ * - Alignment of structs on like i386 char members.
+ */
+
+/*
+ * Struct used in array initialisation.
+ */
+static struct instk {
+       struct  instk *in_prev; /* linked list */
+       struct  symtab *in_lnk; /* member in structure initializations */
+       struct  symtab *in_sym; /* symtab index */
+       union   dimfun *in_df;  /* dimenston of array */
+       TWORD   in_t;           /* type for this level */
+       int     in_n;           /* number of arrays seen so far */
+       int     in_fl;  /* flag which says if this level is controlled by {} */
+} *pstk, pbase;
+
+int doing_init, statinit;
+static struct symtab *csym;
+
+#ifdef PCC_DEBUG
+static void prtstk(struct instk *in);
+#endif
+
+/*
+ * Linked lists for initializations.
+ */
+struct ilist {
+       struct ilist *next;
+       CONSZ off;      /* bit offset of this entry */
+       int fsz;        /* bit size of this entry */
+       NODE *n;        /* node containing this data info */
+};
+
+struct llist {
+       SLIST_ENTRY(llist) next;
+       CONSZ begsz;    /* bit offset of this entry */
+       struct ilist *il;
+};
+static SLIST_HEAD(llh, llist) lpole;
+static CONSZ basesz;
+static int numents; /* # of array entries allocated */
+
+static struct initctx {
+       struct initctx *prev;
+       struct instk *pstk;
+       struct symtab *psym;
+       struct llh lpole;
+       CONSZ basesz;
+       int numents;
+} *inilnk;
+
+static struct ilist *
+getil(struct ilist *next, CONSZ b, int sz, NODE *n)
+{
+       struct ilist *il = tmpalloc(sizeof(struct ilist));
+
+       il->off = b;
+       il->fsz = sz;
+       il->n = n;
+       il->next = next;
+       return il;
+}
+
+/*
+ * Allocate a new struct defining a block of initializers appended to the
+ * end of the llist. Return that entry.
+ */
+static struct llist *
+getll(void)
+{
+       struct llist *ll;
+
+       ll = tmpalloc(sizeof(struct llist));
+       ll->begsz = numents * basesz;
+       ll->il = NULL;
+       SLIST_INSERT_LAST(&lpole, ll, next);
+       numents++;
+       return ll;
+}
+
+/*
+ * Return structure containing off bitnumber.
+ * Allocate more entries, if needed.
+ */
+static struct llist *
+setll(OFFSZ off)
+{
+       struct llist *ll = NULL;
+
+       /* Ensure that we have enough entries */
+       while (off >= basesz * numents)
+                ll = getll();
+
+       if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off)
+               return ll;
+
+       SLIST_FOREACH(ll, &lpole, next)
+               if (ll->begsz <= off && ll->begsz + basesz > off)
+                       break;
+       return ll; /* ``cannot fail'' */
+}
+char *astypnames[] = { 0, 0, "\t.byte", "\t.byte", "\t.short", "\t.short",
+       "\t.word", "\t.word", "\t.long", "\t.long", "\t.quad", "\t.quad",
+       "ERR", "ERR", "ERR",
+};
+
+void
+inval(CONSZ off, int fsz, NODE *p)
+{
+       struct symtab *sp;
+       CONSZ val;
+       TWORD t;
+
+#ifndef NO_COMPLEX
+       if (ANYCX(p) && p->n_left->n_right->n_right->n_op == FCON &&
+           p->n_left->n_left->n_right->n_op == FCON) {
+               NODE *r = p->n_left->n_right->n_right;
+               int sz = (int)tsize(r->n_type, r->n_df, r->n_ap);
+               ninval(off, sz, p->n_left->n_left->n_right);
+               ninval(off, sz, r);
+               tfree(p);
+               return;
+       }
+#endif
+
+       if (p->n_op != ICON && p->n_op != FCON) {
+               uerror("constant required");
+               return;
+       }
+       if (p->n_type == BOOL) {
+               if ((U_CONSZ)glval(p) > 1)
+                       slval(p, 1);
+               p->n_type = BOOL_TYPE;
+       }
+       if (ninval(off, fsz, p))
+               return; /* dealt with in local.c */
+       t = p->n_type;
+       if (t > BTMASK)
+               t = INTPTR;
+
+       val = (CONSZ)(glval(p) & SZMASK(sztable[t]));
+       if (t <= ULONGLONG) {
+               sp = p->n_sp;
+               printf(PRTPREF "%s ",astypnames[t]);
+               if (val || sp == NULL)
+                       printf(CONFMT, val);
+               if (val && sp != NULL)
+                       printf("+");
+               if (sp != NULL) {
+                       if ((sp->sclass == STATIC && sp->slevel > 0)) {
+                               /* fix problem with &&label not defined yet */
+                               int o = sp->soffset;
+                               printf(LABFMT, o < 0 ? -o : o);
+                               if ((sp->sflags & SMASK) == SSTRING)
+                                       sp->sflags |= SASG;
+                       } else
+                               printf("%s", getexname(sp));
+               }
+               printf("\n");
+       } else
+               cerror("inval: unhandled type %d", (int)t);
+}
+
+#ifndef MYBFINIT
+
+static int inbits;
+static CONSZ xinval;
+/*
+ * Initialize a bitfield.
+ * XXX - use U_CONSZ?
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("infld off " CONFMT ", fsz %d, val " CONFMT " inbits %d\n",
+                   off, fsz, val, inbits);
+#endif
+       val &= SZMASK(fsz);
+#if TARGET_ENDIAN == TARGET_BE
+       while (fsz + inbits >= SZCHAR) {
+               int shsz = SZCHAR-inbits;
+               xinval = (xinval << shsz) | (val >> (fsz - shsz));
+               printf(PRTPREF "%s " CONFMT "\n",
+                   astypnames[CHAR], xinval & SZMASK(SZCHAR));
+               fsz -= shsz;
+               val &= SZMASK(fsz);
+               xinval = inbits = 0;
+       }
+       if (fsz) {
+               xinval = (xinval << fsz) | val;
+               inbits += fsz;
+       }
+#else
+       while (fsz + inbits >= SZCHAR) {
+               int shsz = SZCHAR-inbits;
+               xinval |= (val << inbits);
+               printf(PRTPREF "%s " CONFMT "\n",
+                   astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR)));
+               fsz -= shsz;
+               val >>= shsz;
+               xinval = inbits = 0;
+       }
+       if (fsz) {
+               xinval |= (val << inbits);
+               inbits += fsz;
+       }
+#endif
+}
+
+char *asspace = "\t.space";
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+       int m;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("zbits off " CONFMT ", fsz %d inbits %d\n", off, fsz, inbits);
+#endif
+#if TARGET_ENDIAN == TARGET_BE
+       if ((m = (inbits % SZCHAR))) {
+               m = SZCHAR - m;
+               if (fsz < m) {
+                       inbits += fsz;
+                       xinval <<= fsz;
+                       return;
+               } else {
+                       fsz -= m;
+                       xinval <<= m;
+                       printf(PRTPREF "%s " CONFMT "\n", 
+                           astypnames[CHAR], xinval & SZMASK(SZCHAR));
+                       xinval = inbits = 0;
+               }
+       }
+#else
+       if ((m = (inbits % SZCHAR))) {
+               m = SZCHAR - m;
+               if (fsz < m) {
+                       inbits += fsz;
+                       return;
+               } else {
+                       fsz -= m;
+                       printf(PRTPREF "%s " CONFMT "\n", 
+                           astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR)));
+                       xinval = inbits = 0;
+               }
+       }
+#endif
+       if (fsz >= SZCHAR) {
+               printf(PRTPREF "%s %d\n", asspace, fsz/SZCHAR);
+               fsz -= (fsz/SZCHAR) * SZCHAR;
+       }
+       if (fsz) {
+               xinval = 0;
+               inbits = fsz;
+       }
+}
+#endif
+
+/*
+ * beginning of initialization; allocate space to store initialized data.
+ * remember storage class for writeout in endinit().
+ * p is the newly declarated type.
+ */
+void
+beginit(struct symtab *sp)
+{
+       struct initctx *ict;
+       struct instk *is = &pbase;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass));
+#endif
+
+       if (pstk) {
+#ifdef PCC_DEBUG
+               if (idebug)
+                       printf("beginit: saving ctx pstk %p\n", pstk);
+#endif
+               /* save old context */
+               ict = tmpalloc(sizeof(struct initctx));
+               ict->prev = inilnk;
+               inilnk = ict;
+               ict->pstk = pstk;
+               ict->psym = csym;
+               ict->lpole = lpole;
+               ict->basesz = basesz;
+               ict->numents = numents;
+               is = tmpalloc(sizeof(struct instk));
+       }
+       csym = sp;
+
+       numents = 0; /* no entries in array list */
+       if (ISARY(sp->stype)) {
+               basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap);
+               if (basesz == 0) {
+                       uerror("array has incomplete type");
+                       basesz = SZINT;
+               }
+       } else
+               basesz = tsize(sp->stype, sp->sdf, sp->sap);
+       SLIST_INIT(&lpole);
+
+       /* first element */
+       if (ISSOU(sp->stype)) {
+               is->in_lnk = strmemb(sp->sap);
+       } else
+               is->in_lnk = NULL;
+       is->in_n = 0;
+       is->in_t = sp->stype;
+       is->in_sym = sp;
+       is->in_df = sp->sdf;
+       is->in_fl = 0;
+       is->in_prev = NULL;
+       pstk = is;
+       doing_init++;
+       if (sp->sclass == STATIC || sp->sclass == EXTDEF)
+               statinit++;
+}
+
+/*
+ * Push a new entry on the initializer stack.
+ * The new entry will be "decremented" to the new sub-type of the previous
+ * entry when called.
+ * Popping of entries is done elsewhere.
+ */
+static void
+stkpush(void)
+{
+       struct instk *is;
+       struct symtab *sq, *sp;
+       TWORD t;
+
+       if (pstk == NULL) {
+               sp = csym;
+               t = 0;
+       } else {
+               t = pstk->in_t;
+               sp = pstk->in_sym;
+       }
+
+#ifdef PCC_DEBUG
+       if (idebug) {
+               printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass));
+               tprint(t, 0);
+       }
+#endif
+
+       /*
+        * Figure out what the next initializer will be, and push it on 
+        * the stack.  If this is an array, just decrement type, if it
+        * is a struct or union, extract the next element.
+        */
+       is = tmpalloc(sizeof(struct instk));
+       is->in_fl = 0;
+       is->in_n = 0;
+       if (pstk == NULL) {
+               /* stack empty */
+               is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL;
+               is->in_t = sp->stype;
+               is->in_sym = sp;
+               is->in_df = sp->sdf;
+       } else if (ISSOU(t)) {
+               sq = pstk->in_lnk;
+               if (sq == NULL) {
+                       uerror("excess of initializing elements");
+               } else {
+                       is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL;
+                       is->in_t = sq->stype;
+                       is->in_sym = sq;
+                       is->in_df = sq->sdf;
+               }
+       } else if (ISARY(t)) {
+               is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0;
+               is->in_t = DECREF(t);
+               is->in_sym = sp;
+               if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim &&
+                   pstk->in_n >= pstk->in_df->ddim) {
+                       werror("excess of initializing elements");
+                       pstk->in_n--;
+               }
+               is->in_df = pstk->in_df+1;
+       } else
+               uerror("too many left braces");
+       is->in_prev = pstk;
+       pstk = is;
+
+#ifdef PCC_DEBUG
+       if (idebug) {
+               printf(" newtype ");
+               tprint(is->in_t, 0);
+               printf("\n");
+       }
+#endif
+}
+
+/*
+ * pop down to either next level that can handle a new initializer or
+ * to the next braced level.
+ */
+static void
+stkpop(void)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("stkpop\n");
+#endif
+       for (; pstk; pstk = pstk->in_prev) {
+               if (pstk->in_t == STRTY && pstk->in_lnk != NULL) {
+                       pstk->in_lnk = pstk->in_lnk->snext;
+                       if (pstk->in_lnk != NULL)
+                               break;
+               }
+               if (ISSOU(pstk->in_t) && pstk->in_fl)
+                       break; /* need } */
+               if (ISARY(pstk->in_t)) {
+                       pstk->in_n++;
+                       if (pstk->in_fl)
+                               break;
+                       if (pstk->in_df->ddim == NOOFFSET ||
+                           pstk->in_n < pstk->in_df->ddim)
+                               break; /* ger more elements */
+               }
+       }
+#ifdef PCC_DEBUG
+       if (idebug > 1)
+               prtstk(pstk);
+#endif
+}
+
+/*
+ * Count how many elements an array may consist of.
+ */
+static int
+acalc(struct instk *is, int n)
+{
+       if (is == NULL || !ISARY(is->in_t))
+               return 0;
+       return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n;
+}
+
+/*
+ * Find current bit offset of the top element on the stack from
+ * the beginning of the aggregate.
+ */
+static CONSZ
+findoff(void)
+{
+       struct instk *is;
+       OFFSZ off;
+
+#ifdef PCC_DEBUG
+       if (ISARY(pstk->in_t))
+               cerror("findoff on bad type %x", pstk->in_t);
+#endif
+
+       /*
+        * Offset calculations. If:
+        * - previous type is STRTY, soffset has in-struct offset.
+        * - this type is ARY, offset is ninit*stsize.
+        */
+       for (off = 0, is = pstk; is; is = is->in_prev) {
+               if (is->in_prev && is->in_prev->in_t == STRTY)
+                       off += is->in_sym->soffset;
+               if (ISARY(is->in_t)) {
+                       /* suesize is the basic type, so adjust */
+                       TWORD t = is->in_t;
+                       OFFSZ o;
+                       while (ISARY(t))
+                               t = DECREF(t);
+                       if (ISPTR(t)) {
+                               o = SZPOINT(t); /* XXX use tsize() */
+                       } else {
+                               o = tsize(t, is->in_sym->sdf, is->in_sym->sap);
+                       }
+                       off += o * acalc(is, 1);
+                       while (is->in_prev && ISARY(is->in_prev->in_t)) {
+                               if (is->in_prev->in_prev &&
+                                   is->in_prev->in_prev->in_t == STRTY)
+                                       off += is->in_sym->soffset;
+                               is = is->in_prev;
+                       }
+               }
+       }
+#ifdef PCC_DEBUG
+       if (idebug>1) {
+               printf("findoff: off " CONFMT "\n", off);
+               prtstk(pstk);
+       }
+#endif
+       return off;
+}
+
+/*
+ * Insert the node p with size fsz at position off.
+ * Bit fields are already dealt with, so a node of correct type
+ * with correct alignment and correct bit offset is given.
+ */
+static void
+nsetval(CONSZ off, int fsz, NODE *p)
+{
+       struct llist *ll;
+       struct ilist *il;
+
+       if (idebug>1)
+               printf("setval: off " CONFMT " fsz %d p %p\n", off, fsz, p);
+
+       if (fsz == 0)
+               return;
+
+       ll = setll(off);
+       off -= ll->begsz;
+       if (ll->il == NULL) {
+               ll->il = getil(NULL, off, fsz, p);
+       } else {
+               il = ll->il;
+               if (il->off > off) {
+                       ll->il = getil(ll->il, off, fsz, p);
+               } else {
+                       for (il = ll->il; il->next; il = il->next)
+                               if (il->off <= off && il->next->off > off)
+                                       break;
+                       if (il->off == off) {
+                               /* replace */
+                               nfree(il->n);
+                               il->n = p;
+                       } else
+                               il->next = getil(il->next, off, fsz, p);
+               }
+       }
+}
+
+/*
+ * take care of generating a value for the initializer p
+ * inoff has the current offset (last bit written)
+ * in the current word being generated
+ * Returns the offset.
+ */
+CONSZ
+scalinit(NODE *p)
+{
+       CONSZ woff;
+       NODE *q;
+       int fsz;
+
+#ifdef PCC_DEBUG
+       if (idebug > 2) {
+               printf("scalinit(%p)\n", p);
+               fwalk(p, eprint, 0);
+               prtstk(pstk);
+       }
+#endif
+
+       if (nerrors)
+               return 0;
+
+       p = optim(p);
+
+#ifdef notdef /* leave to the target to decide if useable */
+       if (csym->sclass != AUTO && p->n_op != ICON &&
+           p->n_op != FCON && p->n_op != NAME)
+               cerror("scalinit not leaf");
+#endif
+
+       /* Out of elements? */
+       if (pstk == NULL) {
+               uerror("excess of initializing elements");
+               return 0;
+       }
+
+       /*
+        * Get to the simple type if needed.
+        */
+       while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) {
+               stkpush();
+               /* If we are doing auto struct init */
+               if (ISSOU(pstk->in_t) && ISSOU(p->n_type) &&
+                   suemeq(pstk->in_sym->sap, p->n_ap)) {
+                       pstk->in_lnk = NULL; /* this elem is initialized */
+                       break;
+               }
+       }
+
+       if (ISSOU(pstk->in_t) == 0) {
+               /* let buildtree do typechecking (and casting) */
+               q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df,
+                   pstk->in_sym->sap);
+               p = buildtree(ASSIGN, q, p);
+               nfree(p->n_left);
+               q = p->n_right;
+               nfree(p);
+       } else
+               q = p;
+
+       q = optloop(q);
+
+       woff = findoff();
+
+       /* bitfield sizes are special */
+       if (pstk->in_sym->sclass & FIELD)
+               fsz = -(pstk->in_sym->sclass & FLDSIZ);
+       else
+               fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf,
+                   pstk->in_sym->sap);
+
+       nsetval(woff, fsz, q);
+       if (q->n_op == ICON && q->n_sp &&
+           ((q->n_sp->sflags & SMASK) == SSTRING))
+               q->n_sp->sflags |= SASG;
+
+       stkpop();
+#ifdef PCC_DEBUG
+       if (idebug > 2) {
+               printf("scalinit e(%p)\n", q);
+       }
+#endif
+       return woff;
+}
+
+/*
+ * Generate code to insert a value into a bitfield.
+ */
+static void
+insbf(OFFSZ off, int fsz, int val)
+{
+       struct symtab sym;
+       NODE *p, *r;
+       TWORD typ;
+
+#ifdef PCC_DEBUG
+       if (idebug > 1)
+               printf("insbf: off " CONFMT " fsz %d val %d\n", off, fsz, val);
+#endif
+
+       if (fsz == 0)
+               return;
+
+       /* small opt: do char instead of bf asg */
+       if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR)
+               typ = CHAR;
+       else
+               typ = INT;
+       /* Fake a struct reference */
+       p = buildtree(ADDROF, nametree(csym), NIL);
+       sym.stype = typ;
+       sym.squal = 0;
+       sym.sdf = 0;
+       sym.sap = NULL;
+       sym.soffset = (int)off;
+       sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU);
+       r = xbcon(0, &sym, typ);
+       p = block(STREF, p, r, INT, 0, 0);
+       ecomp(buildtree(ASSIGN, stref(p), bcon(val)));
+}
+
+/*
+ * Clear a bitfield, starting at off and size fsz.
+ */
+static void
+clearbf(OFFSZ off, OFFSZ fsz)
+{
+       /* Pad up to the next even initializer */
+       if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) {
+               int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off);
+               if (ba > fsz)
+                       ba = (int)fsz;
+               insbf(off, ba, 0);
+               off += ba;
+               fsz -= ba;
+       }
+       while (fsz >= SZCHAR) {
+               insbf(off, SZCHAR, 0);
+               off += SZCHAR;
+               fsz -= SZCHAR;
+       }
+       if (fsz)
+               insbf(off, fsz, 0);
+}
+
+/*
+ * final step of initialization.
+ * print out init nodes and generate copy code (if needed).
+ */
+void
+endinit(int seg)
+{
+       struct llist *ll;
+       struct ilist *il;
+       int fsz;
+       OFFSZ lastoff, tbit;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("endinit()\n");
+#endif
+
+       /* Calculate total block size */
+       if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) {
+               tbit = numents*basesz; /* open-ended arrays */
+               csym->sdf->ddim = numents;
+               if (csym->sclass == AUTO) { /* Get stack space */
+                       csym->soffset = NOOFFSET;
+                       oalloc(csym, &autooff);
+               }
+       } else
+               tbit = tsize(csym->stype, csym->sdf, csym->sap);
+
+       /* Setup symbols */
+       if (csym->sclass != AUTO) {
+               locctr(seg ? UDATA : DATA, csym);
+               defloc(csym);
+       }
+
+       /* Traverse all entries and print'em out */
+       lastoff = 0;
+       SLIST_FOREACH(ll, &lpole, next) {
+               for (il = ll->il; il; il = il->next) {
+#ifdef PCC_DEBUG
+                       if (idebug > 1) {
+                               printf("off " CONFMT " size %d val " CONFMT " type ",
+                                   ll->begsz+il->off, il->fsz, glval(il->n));
+                               tprint(il->n->n_type, 0);
+                               printf("\n");
+                       }
+#endif
+                       fsz = il->fsz;
+                       if (csym->sclass == AUTO) {
+                               struct symtab sym;
+                               NODE *p, *r, *n;
+
+                               if (ll->begsz + il->off > lastoff)
+                                       clearbf(lastoff,
+                                           (ll->begsz + il->off) - lastoff);
+
+                               /* Fake a struct reference */
+                               p = buildtree(ADDROF, nametree(csym), NIL);
+                               n = il->n;
+                               sym.stype = n->n_type;
+                               sym.squal = n->n_qual;
+                               sym.sdf = n->n_df;
+                               sym.sap = n->n_ap;
+                               sym.soffset = (int)(ll->begsz + il->off);
+                               sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0);
+                               r = xbcon(0, &sym, INT);
+                               p = block(STREF, p, r, INT, 0, 0);
+                               ecomp(buildtree(ASSIGN, stref(p), il->n));
+                               if (fsz < 0)
+                                       fsz = -fsz;
+
+                       } else {
+                               if (ll->begsz + il->off > lastoff)
+                                       zbits(lastoff,
+                                           (ll->begsz + il->off) - lastoff);
+                               if (fsz < 0) {
+                                       fsz = -fsz;
+                                       infld(il->off, fsz, glval(il->n));
+                               } else
+                                       inval(il->off, fsz, il->n);
+                               tfree(il->n);
+                       }
+                       lastoff = ll->begsz + il->off + fsz;
+               }
+       }
+       if (csym->sclass == AUTO) {
+               clearbf(lastoff, tbit-lastoff);
+       } else
+               zbits(lastoff, tbit-lastoff);
+       
+       doing_init--;
+       if (csym->sclass == STATIC || csym->sclass == EXTDEF)
+               statinit--;
+       endictx();
+}
+
+void
+endictx(void)
+{
+       struct initctx *ict = inilnk;
+
+       if (ict == NULL)
+               return;
+
+       pstk = ict->pstk;
+       csym = ict->psym;
+       lpole = ict->lpole;
+       basesz = ict->basesz;
+       numents = ict->numents;
+       inilnk = inilnk->prev;
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("endinit: restoring ctx pstk %p\n", pstk);
+#endif
+}
+
+/*
+ * process an initializer's left brace
+ */
+void
+ilbrace(void)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("ilbrace()\n");
+#endif
+
+       if (pstk == NULL)
+               return;
+
+       stkpush();
+       pstk->in_fl = 1; /* mark lbrace */
+#ifdef PCC_DEBUG
+       if (idebug > 1)
+               prtstk(pstk);
+#endif
+}
+
+/*
+ * called when a '}' is seen
+ */
+void
+irbrace(void)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("irbrace()\n");
+       if (idebug > 2)
+               prtstk(pstk);
+#endif
+
+       if (pstk == NULL)
+               return;
+
+       /* Got right brace, search for corresponding in the stack */
+       for (; pstk->in_prev != NULL; pstk = pstk->in_prev) {
+               if(!pstk->in_fl)
+                       continue;
+
+               /* we have one now */
+
+               pstk->in_fl = 0;  /* cancel { */
+               if (ISARY(pstk->in_t))
+                       pstk->in_n = pstk->in_df->ddim;
+               else if (pstk->in_t == STRTY) {
+                       while (pstk->in_lnk != NULL &&
+                           pstk->in_lnk->snext != NULL)
+                               pstk->in_lnk = pstk->in_lnk->snext;
+               }
+               stkpop();
+               return;
+       }
+}
+
+/*
+ * Create a new init stack based on given elements.
+ */
+static void
+mkstack(NODE *p)
+{
+
+#ifdef PCC_DEBUG
+       if (idebug) {
+               printf("mkstack: %p\n", p);
+               if (idebug > 1 && p)
+                       fwalk(p, eprint, 0);
+       }
+#endif
+
+       if (p == NULL)
+               return;
+       mkstack(p->n_left);
+
+       switch (p->n_op) {
+       case LB: /* Array index */
+               if (p->n_right->n_op != ICON)
+                       cerror("mkstack");
+               if (!ISARY(pstk->in_t))
+                       uerror("array indexing non-array");
+               pstk->in_n = (int)glval(p->n_right);
+               nfree(p->n_right);
+               break;
+
+       case NAME:
+               if (pstk->in_lnk) {
+                       for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext)
+                               if (pstk->in_lnk->sname == (char *)p->n_sp)
+                                       break;
+                       if (pstk->in_lnk == NULL)
+                               uerror("member missing");
+               } else {
+                       uerror("not a struct/union");
+               }
+               break;
+       default:
+               cerror("mkstack2");
+       }
+       nfree(p);
+       stkpush();
+
+}
+
+/*
+ * Initialize a specific element, as per C99.
+ */
+void
+desinit(NODE *p)
+{
+       int op = p->n_op;
+
+       if (pstk == NULL)
+               stkpush(); /* passed end of array */
+       while (pstk->in_prev && pstk->in_fl == 0)
+               pstk = pstk->in_prev; /* Empty stack */
+
+       if (ISSOU(pstk->in_t))
+               pstk->in_lnk = strmemb(pstk->in_sym->sap);
+
+       mkstack(p);     /* Setup for assignment */
+
+       /* pop one step if SOU, ilbrace will push */
+       if (op == NAME || op == LB)
+               pstk = pstk->in_prev;
+
+#ifdef PCC_DEBUG
+       if (idebug > 1) {
+               printf("desinit e\n");
+               prtstk(pstk);
+       }
+#endif
+}
+
+/*
+ * Convert a string to an array of char/wchar for asginit.
+ */
+static void
+strcvt(NODE *p)
+{
+       NODE *q = p;
+       char *s;
+       int i;
+
+#ifdef mach_arm
+       /* XXX */
+       if (p->n_op == UMUL && p->n_left->n_op == ADDROF)
+               p = p->n_left->n_left;
+#endif
+
+       for (s = p->n_sp->sname; *s != 0; ) {
+               if (p->n_type == ARY+WCHAR_TYPE)
+                       i = u82cp(&s);
+               else if (*s == '\\')
+                       i = esccon(&s);
+               else
+                       i = (unsigned char)*s++;
+               asginit(bcon(i));
+       } 
+       tfree(q);
+}
+
+/*
+ * Do an assignment to a struct element.
+ */
+void
+asginit(NODE *p)
+{
+       int g;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("asginit %p\n", p);
+       if (idebug > 1 && p)
+               fwalk(p, eprint, 0);
+#endif
+
+       /* convert string to array of char/wchar */
+       if (p && (DEUNSIGN(p->n_type) == ARY+CHAR ||
+           p->n_type == ARY+WCHAR_TYPE)) {
+               struct instk *is;
+               TWORD t;
+
+               t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR;
+               /*
+                * ...but only if next element is ARY+CHAR, otherwise 
+                * just fall through.
+                */
+
+               /* HACKHACKHACK */
+               is = pstk;
+
+               if (pstk == NULL)
+                       stkpush();
+               while (ISSOU(pstk->in_t) || ISARY(pstk->in_t))
+                       stkpush();
+               if (pstk->in_prev && 
+                   (DEUNSIGN(pstk->in_prev->in_t) == t ||
+                   pstk->in_prev->in_t == t)) {
+                       pstk = pstk->in_prev;
+                       if ((g = pstk->in_fl) == 0)
+                               pstk->in_fl = 1; /* simulate ilbrace */
+
+                       strcvt(p);
+                       if (g == 0)
+                               irbrace(); /* will fill with zeroes */
+                       return;
+               } else
+                       pstk = is; /* no array of char */
+               /* END HACKHACKHACK */
+       }
+
+       if (p == NULL) { /* only end of compound stmt */
+               irbrace();
+       } else /* assign next element */
+               scalinit(p);
+}
+
+#ifdef PCC_DEBUG
+void
+prtstk(struct instk *in)
+{
+       int i, o = 0;
+
+       printf("init stack:\n");
+       for (; in != NULL; in = in->in_prev) {
+               for (i = 0; i < o; i++)
+                       printf("  ");
+               printf("%p) '%s' ", in, in->in_sym->sname);
+               tprint(in->in_t, 0);
+               printf(" %s ", scnames(in->in_sym->sclass));
+               if (in->in_df /* && in->in_df->ddim */)
+                   printf("arydim=%d ", in->in_df->ddim);
+               printf("ninit=%d ", in->in_n);
+               if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t))
+                       printf("stsize=%d ",
+                           (int)tsize(in->in_t, in->in_df, in->in_sym->sap));
+               if (in->in_fl) printf("{ ");
+               printf("soff=%d ", in->in_sym->soffset);
+               if (in->in_t == STRTY) {
+                       if (in->in_lnk)
+                               printf("curel %s ", in->in_lnk->sname);
+                       else
+                               printf("END struct");
+               }
+               printf("\n");
+               o++;
+       }
+}
+#endif
+
+/*
+ * Do a simple initialization.
+ * At block 0, just print out the value, at higher levels generate
+ * appropriate code.
+ */
+void
+simpleinit(struct symtab *sp, NODE *p)
+{
+       NODE *q, *r, *nt;
+       TWORD t;
+       int sz;
+
+       /* May be an initialization of an array of char by a string */
+       if ((DEUNSIGN(p->n_type) == ARY+CHAR &&
+           DEUNSIGN(sp->stype) == ARY+CHAR) ||
+           (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) &&
+           DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) {
+               /* Handle "aaa" as { 'a', 'a', 'a' } */
+               beginit(sp);
+               strcvt(p);
+               if (csym->sdf->ddim == NOOFFSET)
+                       scalinit(bcon(0)); /* Null-term arrays */
+               endinit(0);
+               return;
+       }
+
+       nt = nametree(sp);
+       switch (sp->sclass) {
+       case STATIC:
+       case EXTDEF:
+               q = nt;
+               locctr(DATA, sp);
+               defloc(sp);
+#ifndef NO_COMPLEX
+               if (ANYCX(q) || ANYCX(p)) {
+                       r = cxop(ASSIGN, q, p);
+                       /* XXX must unwind the code generated here */
+                       /* We can rely on correct code generated */
+                       p = r->n_left->n_right->n_left;
+                       r->n_left->n_right->n_left = bcon(0);
+                       tfree(r);
+                       r = p->n_left->n_right;
+                       sz = (int)tsize(r->n_type, r->n_df, r->n_ap);
+                       inval(0, sz, r);
+                       inval(0, sz, p->n_right->n_right);
+                       tfree(p);
+                       break;
+               } else if (ISITY(p->n_type) || ISITY(q->n_type)) {
+                       /* XXX merge this with code from imop() */
+                       int li = 0, ri = 0;
+                       if (ISITY(p->n_type))
+                               li = 1, p->n_type = p->n_type - (FIMAG-FLOAT);
+                       if (ISITY(q->n_type))
+                               ri = 1, q->n_type = q->n_type - (FIMAG-FLOAT);
+                       if (!(li && ri)) {
+                               tfree(p);
+                               p = bcon(0);
+                       }
+                       /* continue below */
+               }
+#endif
+#ifdef TARGET_TIMODE
+               struct attr *ap;
+               if ((ap = attr_find(sp->sap, GCC_ATYP_MODE)) &&
+                   strcmp(ap->aa[0].sarg, "TI") == 0) {
+                       if (p->n_op != ICON)
+                               uerror("need to handle TImode initializer ");
+                       sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+                       p->n_type = ctype(LONGLONG);
+                       inval(0, sz/2, p);
+                       p->n_lval = 0; /* XXX fix signed types */
+                       inval(0, sz/2, p);
+                       tfree(p);
+                       tfree(q);
+                       break;
+               }
+#endif
+               if (p->n_op == NAME && p->n_sp &&
+                   (p->n_sp->sflags & SMASK) == SSTRING)
+                       p->n_sp->sflags |= SASG;
+               p = optloop(buildtree(ASSIGN, nt, p));
+               q = p->n_right;
+               t = q->n_type;
+               sz = (int)tsize(t, q->n_df, q->n_ap);
+               inval(0, sz, q);
+               tfree(p);
+               break;
+
+       case AUTO:
+       case REGISTER:
+               if (ISARY(sp->stype))
+                       cerror("no array init");
+               q = nt;
+#ifdef TARGET_TIMODE
+               if ((r = gcc_eval_timode(ASSIGN, q, p)) != NULL)
+                       ;
+               else
+#endif
+#ifndef NO_COMPLEX
+
+               if (ANYCX(q) || ANYCX(p))
+                       r = cxop(ASSIGN, q, p);
+               else if (ISITY(p->n_type) || ISITY(q->n_type))
+                       r = imop(ASSIGN, q, p);
+               else
+#endif
+                       r = buildtree(ASSIGN, q, p);
+               ecomp(r);
+               break;
+
+       default:
+               uerror("illegal initialization");
+       }
+}
diff --git a/lang/pcc/pcc/cc/ccom/inline.c b/lang/pcc/pcc/cc/ccom/inline.c
new file mode 100644 (file)
index 0000000..7b6f3e8
--- /dev/null
@@ -0,0 +1,667 @@
+/*     $Id: inline.c,v 1.65 2015/11/17 19:19:40 ragge Exp $    */
+/*
+ * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#include <stdarg.h>
+
+/*
+ * Simple description of how the inlining works:
+ * A function found with the keyword "inline" is always saved.
+ * If it also has the keyword "extern" it is written out thereafter.
+ * If it has the keyword "static" it will be written out if it is referenced.
+ * inlining will only be done if -xinline is given, and only if it is 
+ * possible to inline the function.
+ */
+static void printip(struct interpass *pole);
+
+struct ntds {
+       int temp;
+       TWORD type;
+       union dimfun *df;
+       struct attr *attr;
+};
+
+/*
+ * ilink from ipole points to the next struct in the list of functions.
+ */
+static struct istat {
+       SLIST_ENTRY(istat) link;
+       struct symtab *sp;
+       int flags;
+#define        CANINL  1       /* function is possible to inline */
+#define        WRITTEN 2       /* function is written out */
+#define        REFD    4       /* Referenced but not yet written out */
+       struct ntds *nt;/* Array of arg temp type data */
+       int nargs;      /* number of args in array */
+       int retval;     /* number of return temporary, if any */
+       struct interpass shead;
+} *cifun;
+
+static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw };
+static int nlabs, svclass;
+
+#define        IP_REF  (MAXIP+1)
+#ifdef PCC_DEBUG
+#define        SDEBUG(x)       if (sdebug) printf x
+#else
+#define        SDEBUG(x)
+#endif
+
+int isinlining;
+int inlstatcnt;
+
+#define        SZSI    sizeof(struct istat)
+int istatsz = SZSI;
+#define        ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
+
+/*
+ * Get prolog/epilog for a function.
+ */
+static struct interpass_prolog *
+getprol(struct istat *is, int type)
+{
+       struct interpass *ip;
+
+       DLIST_FOREACH(ip, &is->shead, qelem)
+               if (ip->type == type)
+                       return (struct interpass_prolog *)ip;
+       cerror("getprol: %d not found", type);
+       return 0; /* XXX */
+}
+
+static struct istat *
+findfun(struct symtab *sp)
+{
+       struct istat *is;
+
+       SLIST_FOREACH(is, &ipole, link)
+               if (is->sp == sp)
+                       return is;
+       return NULL;
+}
+
+static void
+refnode(struct symtab *sp)
+{
+       struct interpass *ip;
+
+       SDEBUG(("refnode(%s)\n", sp->sname));
+
+       ip = permalloc(sizeof(*ip));
+       ip->type = IP_REF;
+       ip->ip_name = (char *)sp;
+       inline_addarg(ip);
+}
+
+/*
+ * Save attributes permanent.
+ */
+static struct attr *
+inapcopy(struct attr *ap)
+{
+       struct attr *nap = attr_dup(ap);
+
+       if (ap->next)
+               nap->next = inapcopy(ap->next);
+       return nap;
+}
+
+/*
+ * Copy a tree onto the permanent heap to save for inline.
+ */
+static NODE *
+intcopy(NODE *p)
+{
+       NODE *q = permalloc(sizeof(NODE));
+       int o = coptype(p->n_op); /* XXX pass2 optype? */
+
+       *q = *p;
+       if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
+           regno(p) == FPREG)
+               SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */
+       if (q->n_ap)
+               q->n_ap = inapcopy(q->n_ap);
+       if (q->n_op == NAME || q->n_op == ICON ||
+           q->n_op == XASM || q->n_op == XARG) {
+               if (*q->n_name)
+                       q->n_name = xstrdup(q->n_name); /* XXX permstrdup */
+               else
+                       q->n_name = "";
+       }
+       if (o == BITYPE)
+               q->n_right = intcopy(q->n_right);
+       if (o != LTYPE)
+               q->n_left = intcopy(q->n_left);
+       return q;
+}
+
+void
+inline_addarg(struct interpass *ip)
+{
+       struct interpass_prolog *ipp;
+       NODE *q;
+       static int g = 0;
+       extern P1ND *cftnod;
+
+       SDEBUG(("inline_addarg(%p)\n", ip));
+       DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem);
+       switch (ip->type) {
+       case IP_ASM:
+               ip->ip_asm = xstrdup(ip->ip_asm);
+               break;
+       case IP_DEFLAB:
+               nlabs++;
+               break;
+       case IP_NODE:
+               q = ip->ip_node;
+               ip->ip_node = intcopy(ip->ip_node);
+               tfree(q);
+               break;
+       case IP_EPILOG:
+               ipp = (struct interpass_prolog *)ip;
+               if (ipp->ip_labels[0])
+                       uerror("no computed goto in inlined functions");
+               ipp->ip_labels = &g;
+               break;
+       }
+       if (cftnod)
+               cifun->retval = regno(cftnod);
+}
+
+/*
+ * Called to setup for inlining of a new function.
+ */
+void
+inline_start(struct symtab *sp, int class)
+{
+       struct istat *is;
+
+       SDEBUG(("inline_start(\"%s\")\n", sp->sname));
+
+       if (isinlining)
+               cerror("already inlining function");
+
+       svclass = class;
+       if ((is = findfun(sp)) != 0) {
+               if (!DLIST_ISEMPTY(&is->shead, qelem))
+                       uerror("inline function already defined");
+       } else {
+               is = ialloc();
+               is->sp = sp;
+               SLIST_INSERT_FIRST(&ipole, is, link);
+               DLIST_INIT(&is->shead, qelem);
+       }
+       cifun = is;
+       nlabs = 0;
+       isinlining++;
+}
+
+/*
+ * End of an inline function. In C99 an inline function declared "extern"
+ * should also have external linkage and are therefore printed out.
+ *
+ * Gcc inline syntax is a mess, see matrix below on emitting functions:
+ *                 without extern
+ *     -std=           -       gnu89   gnu99   
+ *     gcc 3.3.5:      ja      ja      ja
+ *     gcc 4.1.3:      ja      ja      ja
+ *     gcc 4.3.1       ja      ja      nej     
+ * 
+ *                  with extern
+ *     gcc 3.3.5:      nej     nej     nej
+ *     gcc 4.1.3:      nej     nej     nej
+ *     gcc 4.3.1       nej     nej     ja      
+ *
+ * The above is only true if extern is given on the same line as the
+ * function declaration.  If given as a separate definition it do not count.
+ *
+ * The attribute gnu_inline sets gnu89 behaviour.
+ * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate.
+ */
+void
+inline_end(void)
+{
+       struct symtab *sp = cifun->sp;
+
+       SDEBUG(("inline_end()\n"));
+
+       if (sdebug)printip(&cifun->shead);
+       isinlining = 0;
+
+       if (xgnu89 && svclass == SNULL)
+               sp->sclass = EXTERN;
+
+#ifdef GCC_COMPAT
+       if (sp->sclass != STATIC &&
+           (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) {
+               if (sp->sclass == EXTDEF)
+                       sp->sclass = EXTERN;
+               else
+                       sp->sclass = EXTDEF;
+       }
+#endif
+
+       if (sp->sclass == EXTDEF) {
+               cifun->flags |= REFD;
+               inline_prtout();
+       }
+}
+
+/*
+ * Called when an inline function is found, to be sure that it will
+ * be written out.
+ * The function may not be defined when inline_ref() is called.
+ */
+void
+inline_ref(struct symtab *sp)
+{
+       struct istat *w;
+
+       SDEBUG(("inline_ref(\"%s\")\n", sp->sname));
+       if (sp->sclass == SNULL)
+               return; /* only inline, no references */
+       if (isinlining) {
+               refnode(sp);
+       } else {
+               SLIST_FOREACH(w,&ipole, link) {
+                       if (w->sp != sp)
+                               continue;
+                       w->flags |= REFD;
+                       return;
+               }
+               /* function not yet defined, print out when found */
+               w = ialloc();
+               w->sp = sp;
+               w->flags |= REFD;
+               SLIST_INSERT_FIRST(&ipole, w, link);
+               DLIST_INIT(&w->shead, qelem);
+       }
+}
+
+static void
+puto(struct istat *w)
+{
+       struct interpass_prolog *ipp, *epp, *pp;
+       struct interpass *ip, *nip;
+       extern int crslab;
+       int lbloff = 0;
+
+       /* Copy the saved function and print it out */
+       ipp = 0; /* XXX data flow analysis */
+       DLIST_FOREACH(ip, &w->shead, qelem) {
+               switch (ip->type) {
+               case IP_EPILOG:
+               case IP_PROLOG:
+                       if (ip->type == IP_PROLOG) {
+                               ipp = (struct interpass_prolog *)ip;
+                               /* fix label offsets */
+                               lbloff = crslab - ipp->ip_lblnum;
+                       } else {
+                               epp = (struct interpass_prolog *)ip;
+                               crslab += (epp->ip_lblnum - ipp->ip_lblnum);
+                       }
+                       pp = xmalloc(sizeof(struct interpass_prolog));
+                       memcpy(pp, ip, sizeof(struct interpass_prolog));
+                       pp->ip_lblnum += lbloff;
+#ifdef PCC_DEBUG
+                       if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum)
+                               cerror("puto: %d != %d", crslab, pp->ip_lblnum);
+#endif
+                       pass2_compile((struct interpass *)pp);
+                       break;
+
+               case IP_REF:
+                       inline_ref((struct symtab *)ip->ip_name);
+                       break;
+
+               default:
+                       nip = xmalloc(sizeof(struct interpass));
+                       *nip = *ip;
+                       if (nip->type == IP_NODE) {
+                               NODE *p;
+
+                               p = nip->ip_node = tcopy(nip->ip_node);
+                               if (p->n_op == GOTO)
+                                       slval(p->n_left,
+                                           glval(p->n_left) + lbloff);
+                               else if (p->n_op == CBRANCH)
+                                       slval(p->n_right,
+                                           glval(p->n_right) + lbloff);
+                       } else if (nip->type == IP_DEFLAB)
+                               nip->ip_lbl += lbloff;
+                       pass2_compile(nip);
+                       break;
+               }
+       }
+       w->flags |= WRITTEN;
+}
+
+/*
+ * printout functions that are referenced.
+ */
+void
+inline_prtout(void)
+{
+       struct istat *w;
+       int gotone = 0;
+
+       SLIST_FOREACH(w, &ipole, link) {
+               if ((w->flags & (REFD|WRITTEN)) == REFD &&
+                   !DLIST_ISEMPTY(&w->shead, qelem)) {
+                       locctr(PROG, w->sp);
+                       defloc(w->sp);
+                       puto(w);
+                       w->flags |= WRITTEN;
+                       gotone++;
+               }
+       }
+       if (gotone)
+               inline_prtout();
+}
+
+#if 1
+static void
+printip(struct interpass *pole)
+{
+       static char *foo[] = {
+          0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+       struct interpass *ip;
+       struct interpass_prolog *ipplg, *epplg;
+
+       DLIST_FOREACH(ip, pole, qelem) {
+               if (ip->type > MAXIP)
+                       printf("IP(%d) (%p): ", ip->type, ip);
+               else
+                       printf("%s (%p): ", foo[ip->type], ip);
+               switch (ip->type) {
+               case IP_NODE: printf("\n");
+#ifdef PCC_DEBUG
+#ifndef TWOPASS
+                       { extern void e2print(NODE *p, int down, int *a, int *b);
+                       fwalk(ip->ip_node, e2print, 0); break; }
+#endif
+#endif
+               case IP_PROLOG:
+                       ipplg = (struct interpass_prolog *)ip;
+                       printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
+                           ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "",
+                           (long)ipplg->ipp_regs[0], ipplg->ipp_autos,
+                           ipplg->ip_tmpnum, ipplg->ip_lblnum);
+                       break;
+               case IP_EPILOG:
+                       epplg = (struct interpass_prolog *)ip;
+                       printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
+                           epplg->ipp_name, epplg->ipp_vis ? "(local)" : "",
+                           (long)epplg->ipp_regs[0], epplg->ipp_autos,
+                           epplg->ip_tmpnum, epplg->ip_lblnum);
+                       break;
+               case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
+               case IP_DEFNAM: printf("\n"); break;
+               case IP_ASM: printf("%s", ip->ip_asm); break;
+               default:
+                       break;
+               }
+       }
+}
+#endif
+
+static int toff;
+
+static P1ND *
+mnode(struct ntds *nt, P1ND *p)
+{
+       P1ND *q;
+       int num = nt->temp + toff;
+
+       if (p->n_op == CM) {
+               q = p->n_right;
+               q = tempnode(num, nt->type, nt->df, nt->attr);
+               nt--;
+               p->n_right = buildtree(ASSIGN, q, p->n_right);
+               p->n_left = mnode(nt, p->n_left);
+               p->n_op = COMOP;
+       } else {
+               p = pconvert(p);
+               q = tempnode(num, nt->type, nt->df, nt->attr);
+               p = buildtree(ASSIGN, q, p);
+       }
+       return p;
+}
+
+static void
+rtmps(NODE *p, void *arg)
+{
+       if (p->n_op == TEMP)
+               regno(p) += toff;
+}
+
+/*
+ * Inline a function. Returns the return value.
+ * There are two major things that must be converted when 
+ * inlining a function:
+ * - Label numbers must be updated with an offset.
+ * - The stack block must be relocated (add to REG or OREG).
+ * - Temporaries should be updated (but no must)
+ *
+ * Extra tricky:  The call is P1ND, nut the resulting tree is already NODE...
+ */
+P1ND *
+inlinetree(struct symtab *sp, P1ND *f, P1ND *ap)
+{
+       extern int crslab, tvaloff;
+       struct istat *is = findfun(sp);
+       struct interpass *ip, *ipf, *ipl;
+       struct interpass_prolog *ipp, *ipe;
+       int lmin, l0, l1, l2, gainl, n;
+       NODE *pp;
+       P1ND *p, *rp;
+
+       if (is == NULL || nerrors) {
+               inline_ref(sp); /* prototype of not yet declared inline ftn */
+               return NULL;
+       }
+
+       SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL));
+
+#ifdef GCC_COMPAT
+       gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL;
+#else
+       gainl = 0;
+#endif
+
+       n = nerrors;
+       if ((is->flags & CANINL) == 0 && gainl)
+               werror("cannot inline but always_inline");
+       nerrors = n;
+
+       if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) {
+               if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
+                       inline_ref(sp);
+               return NULL;
+       }
+
+       if (isinlining && cifun->sp == sp) {
+               /* Do not try to inline ourselves */
+               inline_ref(sp);
+               return NULL;
+       }
+
+#ifdef mach_i386
+       if (kflag) {
+               is->flags |= REFD; /* if static inline, emit */
+               return NULL; /* XXX cannot handle hidden ebx arg */
+       }
+#endif
+
+       /* emit jumps to surround inline function */
+       branch(l0 = getlab());
+       plabel(l1 = getlab());
+       l2 = getlab();
+       SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2));
+
+       /* From here it is NODE */
+
+       ipp = getprol(is, IP_PROLOG);
+       ipe = getprol(is, IP_EPILOG);
+
+       /* Fix label & temp offsets */
+
+       SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff));
+       lmin = crslab - ipp->ip_lblnum;
+       crslab += (ipe->ip_lblnum - ipp->ip_lblnum) + 2;
+       toff = tvaloff - ipp->ip_tmpnum;
+       tvaloff += (ipe->ip_tmpnum - ipp->ip_tmpnum) + 1;
+       SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
+           crslab, lmin, tvaloff, toff));
+
+       /* traverse until first real label */
+       n = 0;
+       DLIST_FOREACH(ipf, &is->shead, qelem) {
+               if (ipf->type == IP_REF)
+                       inline_ref((struct symtab *)ipf->ip_name);
+               if (ipf->type == IP_DEFLAB && n++ == 1)
+                       break;
+       }
+
+       /* traverse backwards to last label */
+       DLIST_FOREACH_REVERSE(ipl, &is->shead, qelem) {
+               if (ipl->type == IP_REF)
+                       inline_ref((struct symtab *)ipl->ip_name);
+               if (ipl->type == IP_DEFLAB)
+                       break;
+       }
+               
+       /* So, walk over all statements and emit them */
+       for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) {
+               switch (ip->type) {
+               case IP_NODE:
+                       pp = tcopy(ip->ip_node);
+                       if (pp->n_op == GOTO)
+                               slval(pp->n_left, glval(pp->n_left) + lmin);
+                       else if (pp->n_op == CBRANCH)
+                               slval(pp->n_right, glval(pp->n_right) + lmin);
+                       walkf(pp, rtmps, 0);
+#ifdef PCC_DEBUG
+#ifndef TWOPASS
+                       if (sdebug) {
+                               extern void e2print(NODE *p, int down, int *a, int *b);
+                               printf("converted node\n");
+                               fwalk(ip->ip_node, e2print, 0);
+                               fwalk(pp, e2print, 0);
+                       }
+#endif
+#endif
+                       send_passt(IP_NODE, pp);
+                       break;
+
+               case IP_DEFLAB:
+                       SDEBUG(("converted label %d to %d\n",
+                           ip->ip_lbl, ip->ip_lbl + lmin));
+                       send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+                       break;
+
+               case IP_ASM:
+                       send_passt(IP_ASM, ip->ip_asm);
+                       break;
+
+               case IP_REF:
+                       inline_ref((struct symtab *)ip->ip_name);
+                       break;
+
+               default:
+                       cerror("bad inline stmt %d", ip->type);
+               }
+       }
+       SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin));
+       send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+
+       branch(l2);
+       plabel(l0);
+
+       /* Here we are P1ND again */
+       rp = block(GOTO, bcon(l1), NULL, INT, 0, 0);
+       if (is->retval)
+               p = tempnode(is->retval + toff, DECREF(sp->stype),
+                   sp->sdf, sp->sap);
+       else
+               p = xbcon(0, NULL, DECREF(sp->stype));
+       rp = buildtree(COMOP, rp, p);
+
+       if (is->nargs) {
+               p = mnode(&is->nt[is->nargs-1], ap);
+               rp = buildtree(COMOP, p, rp);
+       }
+
+       p1tfree(f);
+       return rp;
+}
+
+void
+inline_args(struct symtab **sp, int nargs)
+{
+       union arglist *al;
+       struct istat *cf;
+       TWORD t;
+       int i;
+
+       SDEBUG(("inline_args\n"));
+       cf = cifun;
+       /*
+        * First handle arguments.  We currently do not inline anything if:
+        * - function has varargs
+        * - function args are volatile, checked if no temp node is asg'd.
+        */
+       /* XXX - this is ugly, invent something better */
+       if (cf->sp->sdf->dfun == NULL)
+               return; /* no prototype */
+       for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) {
+               t = al->type;
+               if (t == TELLIPSIS)
+                       return; /* cannot inline */
+               if (ISSOU(BTYPE(t)))
+                       al++;
+               for (; t > BTMASK; t = DECREF(t))
+                       if (ISARY(t) || ISFTN(t))
+                               al++;
+       }
+
+       if (nargs) {
+               for (i = 0; i < nargs; i++)
+                       if ((sp[i]->sflags & STNODE) == 0)
+                               return; /* not temporary */
+               cf->nt = permalloc(sizeof(struct ntds)*nargs);
+               for (i = 0; i < nargs; i++) {
+                       cf->nt[i].temp = sp[i]->soffset;
+                       cf->nt[i].type = sp[i]->stype;
+                       cf->nt[i].df = sp[i]->sdf;
+                       cf->nt[i].attr = sp[i]->sap;
+               }
+       }
+       cf->nargs = nargs;
+       cf->flags |= CANINL;
+}
diff --git a/lang/pcc/pcc/cc/ccom/main.c b/lang/pcc/pcc/cc/ccom/main.c
new file mode 100644 (file)
index 0000000..70f32a7
--- /dev/null
@@ -0,0 +1,431 @@
+/*     $Id: main.c,v 1.133 2016/02/21 11:04:01 ragge Exp $     */
+
+/*
+ * Copyright (c) 2002 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+int bdebug, ddebug, edebug, idebug, ndebug;
+int odebug, pdebug, sdebug, tdebug, xdebug, wdebug;
+int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug;
+int r2debug, s2debug, t2debug, u2debug, x2debug;
+int gflag, kflag;
+int pflag, sflag;
+int sspflag;
+int xssa, xtailcall, xtemps, xdeljumps, xdce, xinline, xccp, xgnu89, xgnu99;
+int xuchar;
+int freestanding;
+char *prgname, *ftitle;
+
+static void prtstats(void);
+
+static void
+usage(void)
+{
+       (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n",
+           prgname);
+       exit(1);
+}
+
+static void
+segvcatch(int a)
+{
+       char buf[1024];
+
+       snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n",
+           nerrors ? "" : "major ", ftitle, lineno);
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+       _exit(1);
+}
+
+static void
+xopt(char *str)
+{
+       if (strcmp(str, "ssa") == 0)
+               xssa++;
+       else if (strcmp(str, "tailcall") == 0)
+               xtailcall++;
+       else if (strcmp(str, "temps") == 0)
+               xtemps++;
+       else if (strcmp(str, "deljumps") == 0)
+               xdeljumps++;
+       else if (strcmp(str, "dce") == 0)
+               xdce++;
+       else if (strcmp(str, "inline") == 0)
+               xinline++;
+       else if (strcmp(str, "ccp") == 0)
+               xccp++;
+       else if (strcmp(str, "gnu89") == 0)
+               xgnu89++;
+       else if (strcmp(str, "gnu99") == 0)
+               xgnu99++;
+       else if (strcmp(str, "uchar") == 0)
+               xuchar++;
+       else {
+               fprintf(stderr, "unknown -x option '%s'\n", str);
+               usage();
+       }
+}
+
+static void
+fflags(char *str)
+{
+       int flagval = 1;
+
+       if (strncmp("no-", str, 3) == 0) {
+               str += 3;
+               flagval = 0;
+       }
+
+#ifndef PASS2
+       if (strcmp(str, "stack-protector") == 0)
+               sspflag = flagval;
+       else if (strcmp(str, "stack-protector-all") == 0)
+               sspflag = flagval;
+       else if (strncmp(str, "pack-struct", 11) == 0)
+               pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1);
+       else if (strcmp(str, "freestanding") == 0)
+               freestanding = flagval;
+       else {
+               fprintf(stderr, "unknown -f option '%s'\n", str);
+               usage();
+       }
+#endif
+}
+
+/* control multiple files */
+int
+main(int argc, char *argv[])
+{
+       int ch;
+
+//kflag = 1;
+#ifdef TIMING
+       struct timeval t1, t2;
+
+       (void)gettimeofday(&t1, NULL);
+#endif
+
+       prgname = argv[0];
+
+       while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gkm:psvwx:")) != -1) {
+               switch (ch) {
+#ifndef PASS2
+               case 'X':       /* pass1 debugging */
+                       while (*optarg)
+                               switch (*optarg++) {
+                               case 'b': ++bdebug; break; /* buildtree */
+                               case 'd': ++ddebug; break; /* declarations */
+                               case 'e': ++edebug; break; /* pass1 exit */
+                               case 'i': ++idebug; break; /* initializations */
+                               case 'n': ++ndebug; break; /* node allocation */
+                               case 'o': ++odebug; break; /* optim */
+                               case 'p': ++pdebug; break; /* prototype */
+                               case 's': ++sdebug; break; /* inline */
+                               case 't': ++tdebug; break; /* type match */
+                               case 'x': ++xdebug; break; /* MD code */
+                               default:
+                                       fprintf(stderr, "unknown -X flag '%c'\n",
+                                           optarg[-1]);
+                                       exit(1);
+                               }
+                       break;
+#endif
+#ifndef PASS1
+               case 'Z':       /* pass2 debugging */
+                       while (*optarg)
+                               switch (*optarg++) {
+                               case 'b': /* basic block and SSA building */
+                                       ++b2debug;
+                                       break;
+                               case 'c': /* code printout */
+                                       ++c2debug;
+                                       break;
+                               case 'e': /* print tree upon pass2 enter */
+                                       ++e2debug;
+                                       break;
+                               case 'f': /* instruction matching */
+                                       ++f2debug;
+                                       break;
+                               case 'g': /* print flow graphs */
+                                       ++g2debug;
+                                       break;
+                               case 'n': /* node allocation */
+                                       ++ndebug;
+                                       break;
+                               case 'o': /* instruction generator */
+                                       ++o2debug;
+                                       break;
+                               case 'r': /* register alloc/graph coloring */
+                                       ++r2debug;
+                                       break;
+                               case 's': /* shape matching */
+                                       ++s2debug;
+                                       break;
+                               case 't': /* type matching */
+                                       ++t2debug;
+                                       break;
+                               case 'u': /* Sethi-Ullman debugging */
+                                       ++u2debug;
+                                       break;
+                               case 'x': /* target specific */
+                                       ++x2debug;
+                                       break;
+                               default:
+                                       fprintf(stderr, "unknown -Z flag '%c'\n",
+                                           optarg[-1]);
+                                       exit(1);
+                               }
+                       break;
+#endif
+               case 'f': /* Language */
+                       fflags(optarg);
+                       break;
+
+               case 'g': /* Debugging */
+                       ++gflag;
+                       break;
+
+               case 'k': /* PIC code */
+                       ++kflag;
+                       break;
+
+               case 'm': /* Target-specific */
+                       mflags(optarg);
+                       break;
+
+               case 'p': /* Profiling */
+                       ++pflag;
+                       break;
+
+               case 's': /* Statistics */
+                       ++sflag;
+                       break;
+
+               case 'w': /* No warnings emitted */
+                       ++wdebug;
+                       break;
+
+               case 'W': /* Enable different warnings */
+                       Wflags(optarg);
+                       break;
+
+               case 'x': /* Different settings */
+                       xopt(optarg);
+                       break;
+
+               case 'v':
+                       printf("ccom: %s\n", VERSSTR);
+                       break;
+
+               case '?':
+               default:
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       ftitle = xstrdup("<stdin>");
+       if (argc > 0 && strcmp(argv[0], "-") != 0) {
+               if (freopen(argv[0], "r", stdin) == NULL) {
+                       fprintf(stderr, "open input file '%s':",
+                           argv[0]);
+                       perror(NULL);
+                       exit(1);
+               }
+       }
+       if (argc > 1 && strcmp(argv[1], "-") != 0) {
+               if (freopen(argv[1], "w", stdout) == NULL) {
+                       fprintf(stderr, "open output file '%s':",
+                           argv[1]);
+                       perror(NULL);
+                       exit(1);
+               }
+       }
+
+       mkdope();
+       signal(SIGSEGV, segvcatch);
+#ifdef SIGBUS
+       signal(SIGBUS, segvcatch);
+#endif
+
+#ifndef PASS2
+       lineno = 1;
+#ifdef GCC_COMPAT
+       gcc_init();
+#endif
+
+       /* starts past any of the above */
+       reached = 1;
+
+       bjobcode();
+#ifndef TARGET_VALIST
+       {
+               P1ND *p = block(NAME, NULL, NULL, PTR|CHAR, NULL, 0);
+               struct symtab *sp = lookup(addname("__builtin_va_list"), 0);
+               p->n_sp = sp;
+               defid(p, TYPEDEF);
+               p1nfree(p);
+       }
+#endif
+       complinit();
+       kwinit();
+#ifndef NO_BUILTIN
+       builtin_init();
+#endif
+
+#ifdef DWARF
+       if (gflag)
+               dwarf_init(argc ? argv[0] : "");
+#endif
+#ifdef STABS
+       if (gflag) {
+               stabs_file(argc ? argv[0] : "");
+               stabs_init();
+       }
+#endif
+
+       if (sspflag)
+               sspinit();
+#endif /* PASS2 */
+
+#ifndef PASS1
+       fregs = FREGS;  /* number of free registers */
+#ifdef PASS2
+       mainp2();
+#endif
+#endif
+
+#ifndef PASS2
+       (void) yyparse();
+       yyaccpt();
+
+       if (!nerrors) {
+               lcommprint();
+#ifndef NO_STRING_SAVE
+               strprint();
+#endif
+       }
+#endif
+
+#ifndef PASS2
+#ifdef STABS
+       if (gflag)
+               stabs_efile(argc ? argv[0] : "");
+#endif
+       ejobcode( nerrors ? 1 : 0 );
+#endif
+
+#ifdef TIMING
+       (void)gettimeofday(&t2, NULL);
+       t2.tv_sec -= t1.tv_sec;
+       t2.tv_usec -= t1.tv_usec;
+       if (t2.tv_usec < 0) {
+               t2.tv_usec += 1000000;
+               t2.tv_sec -= 1;
+       }
+       fprintf(stderr, "ccom total time: %ld s %ld us\n",
+           t2.tv_sec, t2.tv_usec);
+#endif
+#ifdef DWARF
+       if (gflag)
+               dwarf_end();
+#endif
+
+       if (sflag)
+               prtstats();
+
+       return(nerrors?1:0);
+}
+
+void
+prtstats(void)
+{
+#ifndef PASS2
+       extern int nametabs, namestrlen, treestrsz;
+       extern int arglistcnt, dimfuncnt, inlstatcnt;
+       extern int symtabcnt, suedefcnt, strtabs, strstrlen;
+       extern int blkalloccnt, lcommsz, istatsz;
+       extern int savstringsz, newattrsz, nodesszcnt, symtreecnt;
+#endif
+       extern size_t permallocsize, tmpallocsize, lostmem;
+
+       /* common allocations */
+       fprintf(stderr, "Permanent allocated memory:    %zu B\n", permallocsize);
+       fprintf(stderr, "Temporary allocated memory:    %zu B\n", tmpallocsize);
+       fprintf(stderr, "Lost memory:                   %zu B\n", lostmem);
+
+#ifndef PASS2
+       /* pass1 allocations */
+       fprintf(stderr, "Name table entries:            %d pcs\n", nametabs);
+       fprintf(stderr, "String table entries:          %d pcs\n", strtabs);
+       fprintf(stderr, "Argument list unions:          %d pcs\n", arglistcnt);
+       fprintf(stderr, "Dimension/function unions:     %d pcs\n", dimfuncnt);
+       fprintf(stderr, "Struct/union/enum blocks:      %d pcs\n", suedefcnt);
+       fprintf(stderr, "Inline control blocks:         %d pcs\n", inlstatcnt);
+       fprintf(stderr, "Permanent symtab entries:      %d pcs\n", symtabcnt);
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Name table tree size:          %d B\n",
+           nametabs * treestrsz);
+       fprintf(stderr, "Name string size:              %d B\n", namestrlen);
+       fprintf(stderr, "String table tree size:                %d B\n",
+           strtabs * treestrsz);
+       fprintf(stderr, "String size:                   %d B\n", strstrlen);
+       fprintf(stderr, "Inline control block size:     %d B\n",
+           inlstatcnt * istatsz);
+       fprintf(stderr, "Argument list size:            %d B\n",
+           arglistcnt * (int)sizeof(union arglist));
+       fprintf(stderr, "Dimension/function size:       %d B\n",
+           dimfuncnt * (int)sizeof(union dimfun));
+       fprintf(stderr, "Permanent symtab size:         %d B\n",
+           symtabcnt * (int)sizeof(struct symtab));
+       fprintf(stderr, "Symtab tree size:              %d B\n",
+           symtreecnt * treestrsz);
+       fprintf(stderr, "lcomm struct size:             %d B\n", lcommsz);
+       fprintf(stderr, "blkalloc size:                 %d B\n", blkalloccnt);
+       fprintf(stderr, "(saved strings size):          %d B\n", savstringsz);
+       fprintf(stderr, "attribute size:                        %d B\n", newattrsz);
+       fprintf(stderr, "nodes size:                    %d B\n", nodesszcnt);
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Not accounted for:             %d B\n",
+           (int)permallocsize-(nametabs * treestrsz)-namestrlen-strstrlen-
+           (arglistcnt * (int)sizeof(union arglist))-(strtabs * treestrsz)-
+           (dimfuncnt * (int)sizeof(union dimfun))-(inlstatcnt * istatsz)-
+           (symtabcnt * (int)sizeof(struct symtab))-(symtreecnt * treestrsz)-
+           lcommsz-blkalloccnt-newattrsz-nodesszcnt);
+#endif
+}
diff --git a/lang/pcc/pcc/cc/ccom/optim.c b/lang/pcc/pcc/cc/ccom/optim.c
new file mode 100644 (file)
index 0000000..b91e6cd
--- /dev/null
@@ -0,0 +1,499 @@
+/*     $Id: optim.c,v 1.61 2016/02/09 17:57:35 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+#define        NODE P1ND
+#define        nfree p1nfree
+#define        tfree p1tfree
+
+# define SWAP(p,q) {sp=p; p=q; q=sp;}
+# define RCON(p) (p->n_right->n_op==ICON)
+# define RO(p) p->n_right->n_op
+# define RV(p) getlval(p->n_right)
+# define LCON(p) (p->n_left->n_op==ICON)
+# define LO(p) p->n_left->n_op
+# define LV(p) getlval(p->n_left)
+
+/* remove left node */
+static NODE *
+zapleft(NODE *p)
+{
+       NODE *q;
+
+       q = p->n_left;
+       nfree(p->n_right);
+       nfree(p);
+       return q;
+}
+
+/*
+ * fortran function arguments
+ */
+static NODE *
+fortarg(NODE *p)
+{
+       if( p->n_op == CM ){
+               p->n_left = fortarg( p->n_left );
+               p->n_right = fortarg( p->n_right );
+               return(p);
+       }
+
+       while( ISPTR(p->n_type) ){
+               p = buildtree( UMUL, p, NIL );
+       }
+       return( optim(p) );
+}
+
+       /* mapping relationals when the sides are reversed */
+short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT };
+
+/*
+ * local optimizations, most of which are probably
+ * machine independent
+ */
+NODE *
+optim(NODE *p)
+{
+       int o, ty;
+       NODE *sp, *q;
+       OFFSZ sz;
+       int i;
+
+       if (odebug) return(p);
+
+       ty = coptype(p->n_op);
+       if( ty == LTYPE ) return(p);
+
+       if( ty == BITYPE ) p->n_right = optim(p->n_right);
+       p->n_left = optim(p->n_left);
+
+       /* collect constants */
+again: o = p->n_op;
+       switch(o){
+
+       case SCONV:
+               if (concast(p->n_left, p->n_type)) {
+                       q = p->n_left;
+                       nfree(p);
+                       p = q;
+                       break;
+               }
+               /* FALLTHROUGH */
+       case PCONV:
+               if (p->n_type != VOID)
+                       p = clocal(p);
+               break;
+
+       case FORTCALL:
+               p->n_right = fortarg( p->n_right );
+               break;
+
+       case ADDROF:
+               if (LO(p) == TEMP)
+                       break;
+               if( LO(p) != NAME ) cerror( "& error" );
+
+               if( !andable(p->n_left) && !statinit)
+                       break;
+
+               LO(p) = ICON;
+
+               setuleft:
+               /* paint over the type of the left hand side with the type of the top */
+               p->n_left->n_type = p->n_type;
+               p->n_left->n_df = p->n_df;
+               p->n_left->n_ap = p->n_ap;
+               q = p->n_left;
+               nfree(p);
+               p = q;
+               break;
+
+       case NOT:
+       case UMINUS:
+       case COMPL:
+               if (LCON(p) && conval(p->n_left, o, p->n_left))
+                       p = nfree(p);
+               break;
+
+       case UMUL:
+               /* Do not discard ADDROF TEMP's */
+               if (LO(p) == ADDROF && LO(p->n_left) != TEMP) {
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       nfree(p);
+                       p = q;
+                       break;
+               }
+               if( LO(p) != ICON ) break;
+               LO(p) = NAME;
+               goto setuleft;
+
+       case RS:
+               if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
+                       goto zapright;
+
+               sz = tsize(p->n_type, p->n_df, p->n_ap);
+
+               if (LO(p) == RS && RCON(p->n_left) && RCON(p) &&
+                   (RV(p) + RV(p->n_left)) < sz) {
+                       /* two right-shift  by constants */
+                       RV(p) += RV(p->n_left);
+                       p->n_left = zapleft(p->n_left);
+               }
+#if 0
+                 else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
+                       RV(p) -= RV(p->n_left);
+                       if (RV(p) < 0)
+                               o = p->n_op = LS, RV(p) = -RV(p);
+                       p->n_left = zapleft(p->n_left);
+               }
+#endif
+               if (RO(p) == ICON) {
+                       if (RV(p) < 0) {
+                               RV(p) = -RV(p);
+                               p->n_op = LS;
+                               goto again;
+                       }
+#ifdef notyet /* must check for side effects, --a >> 32; */
+                       if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) &&
+                           ISUNSIGNED(p->n_type)) { /* ignore signed shifts */
+                               /* too many shifts */
+                               tfree(p->n_left);
+                               nfree(p->n_right);
+                               p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL;
+                       } else
+#endif
+                       /* avoid larger shifts than type size */
+                       if (RV(p) >= sz)
+                               werror("shift larger than type");
+                       if (RV(p) == 0)
+                               p = zapleft(p);
+               }
+               break;
+
+       case LS:
+               if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
+                       goto zapright;
+
+               sz = tsize(p->n_type, p->n_df, p->n_ap);
+
+               if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
+                       /* two left-shift  by constants */
+                       RV(p) += RV(p->n_left);
+                       p->n_left = zapleft(p->n_left);
+               }
+#if 0
+                 else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) {
+                       RV(p) -= RV(p->n_left);
+                       p->n_left = zapleft(p->n_left);
+               }
+#endif
+               if (RO(p) == ICON) {
+                       if (RV(p) < 0) {
+                               RV(p) = -RV(p);
+                               p->n_op = RS;
+                               goto again;
+                       }
+#ifdef notyet /* must check for side effects */
+                       if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) {
+                               /* too many shifts */
+                               tfree(p->n_left);
+                               nfree(p->n_right);
+                               p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL;
+                       } else
+#endif
+                       /* avoid larger shifts than type size */
+                       if (RV(p) >= sz)
+                               werror("shift larger than type");
+                       if (RV(p) == 0)  
+                               p = zapleft(p);
+               }
+               break;
+
+       case QUEST:
+               if (!LCON(p))
+                       break;
+               if (LV(p) == 0) {
+                       q = p->n_right->n_right;
+               } else {
+                       q = p->n_right->n_left;
+                       p->n_right->n_left = p->n_right->n_right;
+               }
+               p->n_right->n_op = UMUL; /* for tfree() */
+               tfree(p);
+               p = q;
+               break;
+
+       case MINUS:
+               if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) {
+                       /* link-time constants, but both are the same */
+                       /* solve it now by forgetting the symbols */
+                       p->n_left->n_sp = p->n_right->n_sp = NULL;
+               }
+               if( !nncon(p->n_right) ) break;
+               RV(p) = -RV(p);
+               o = p->n_op = PLUS;
+               /* FALLTHROUGH */
+       case MUL:
+               /*
+                * Check for u=(x-y)+z; where all vars are pointers to
+                * the same struct. This has two advantages:
+                * 1: avoid a mul+div
+                * 2: even if not allowed, people may get surprised if this
+                *    calculation do not give correct result if using
+                *    unaligned structs.
+                */
+               if (o == MUL && p->n_type == INTPTR && RCON(p) &&
+                   LO(p) == DIV && RCON(p->n_left) &&
+                   RV(p) == RV(p->n_left) &&
+                   LO(p->n_left) == MINUS) {
+                       q = p->n_left->n_left;
+                       if (q->n_left->n_type == PTR+STRTY &&
+                           q->n_right->n_type == PTR+STRTY &&
+                           strmemb(q->n_left->n_ap) ==
+                           strmemb(q->n_right->n_ap)) {
+                               p = zapleft(p);
+                               p = zapleft(p);
+                       }
+               }
+               /* FALLTHROUGH */
+       case PLUS:
+       case AND:
+       case OR:
+       case ER:
+               /* commutative ops; for now, just collect constants */
+               /* someday, do it right */
+               if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) )
+                       SWAP( p->n_left, p->n_right );
+               /* make ops tower to the left, not the right */
+               if( RO(p) == o ){
+                       SWAP(p->n_left, p->n_right);
+#ifdef notdef
+               /* Yetch, this breaks type correctness in trees */
+               /* Code was probably written before types */
+               /* All we can do here is swap and pray */
+                       NODE *t1, *t2, *t3;
+                       t1 = p->n_left;
+                       sp = p->n_right;
+                       t2 = sp->n_left;
+                       t3 = sp->n_right;
+                       /* now, put together again */
+                       p->n_left = sp;
+                       sp->n_left = t1;
+                       sp->n_right = t2;
+                       sp->n_type = p->n_type;
+                       p->n_right = t3;
+#endif
+                       }
+               if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) &&
+                  conval(p->n_right, MINUS, p->n_left->n_right)){
+                       zapleft:
+
+                       q = p->n_left->n_left;
+                       nfree(p->n_left->n_right);
+                       nfree(p->n_left);
+                       p->n_left = q;
+               }
+               if( RCON(p) && LO(p)==o && RCON(p->n_left) &&
+                   conval( p->n_right, o, p->n_left->n_right ) ){
+                       goto zapleft;
+                       }
+               else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){
+                       zapright:
+                       nfree(p->n_right);
+                       q = makety(p->n_left, p->n_type, p->n_qual,
+                           p->n_df, p->n_ap);
+                       nfree(p);
+                       p = clocal(q);
+                       break;
+                       }
+
+               /* change muls to shifts */
+
+               if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){
+                       if( i == 0 ) { /* multiplication by 1 */
+                               goto zapright;
+                               }
+                       o = p->n_op = LS;
+                       p->n_right->n_type = INT;
+                       p->n_right->n_df = NULL;
+                       RV(p) = i;
+                       }
+
+               /* change +'s of negative consts back to - */
+               if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){
+                       RV(p) = -RV(p);
+                       o = p->n_op = MINUS;
+                       }
+
+               /* remove ops with RHS 0 */
+               if ((o == PLUS || o == MINUS || o == OR || o == ER) &&
+                   nncon(p->n_right) && RV(p) == 0) {
+                       goto zapright;
+               }
+               break;
+
+       case DIV:
+               if( nncon( p->n_right ) && getlval(p->n_right) == 1 )
+                       goto zapright;
+               if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right))
+                       goto zapright;
+               if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) {
+                       p->n_op = RS;
+                       RV(p) = i;
+                       q = p->n_right;
+                       if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT)
+                               p->n_right = makety(q, INT, 0, 0, 0);
+
+                       break;
+               }
+               break;
+
+       case MOD:
+               if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) {
+                       p->n_op = AND;
+                       RV(p) = RV(p) -1;
+                       break;
+               }
+               break;
+
+       case EQ:
+       case NE:
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+       case ULT:
+       case ULE:
+       case UGT:
+       case UGE:
+               if (LCON(p) && RCON(p) &&
+                   !ISPTR(p->n_left->n_type) && !ISPTR(p->n_right->n_type)) {
+                       /* Do constant evaluation */
+                       q = p->n_left;
+                       if (conval(q, o, p->n_right)) {
+                               nfree(p->n_right);
+                               nfree(p);
+                               p = q;
+                               break;
+                       }
+               }
+
+               if( !LCON(p) ) break;
+
+               /* exchange operands */
+
+               sp = p->n_left;
+               p->n_left = p->n_right;
+               p->n_right = sp;
+               p->n_op = revrel[p->n_op - EQ ];
+               break;
+
+       case CBRANCH:
+               if (LCON(p)) {
+                       if (LV(p) == 0) {
+                               tfree(p);
+                               p = bcon(0);
+                       } else {
+                               tfree(p->n_left);
+                               p->n_left = p->n_right;
+                               p->n_op = GOTO;
+                       }
+               }
+               break;
+                               
+
+#ifdef notyet
+       case ASSIGN:
+               /* Simple test to avoid two branches */
+               if (RO(p) != NE)
+                       break;
+               q = p->n_right;
+               if (RCON(q) && RV(q) == 0 && LO(q) == AND &&
+                   RCON(q->n_left) && (i = ispow2(RV(q->n_left))) &&
+                   q->n_left->n_type == INT) {
+                       q->n_op = RS;
+                       RV(q) = i;
+               }
+               break;
+#endif
+
+       case ANDAND:
+               if (!nncon(p->n_left))
+                       break;
+               if (LV(p) == 0) { /* right not evaluated */
+                       p1walkf(p, putjops, 0);
+                       p1tfree(p);
+                       p = bcon(0);
+               } else {
+                       q = p->n_right;
+                       nfree(nfree(p));
+                       p = cast(q, INT, 0);
+               }
+               break;
+       case OROR:
+               if (!nncon(p->n_left))
+                       break;
+               if (LV(p) != 0) { /* right not evaluated */
+                       p1walkf(p, putjops, 0);
+                       p1tfree(p);
+                       p = bcon(1);
+               } else {
+                       q = p->n_right;
+                       nfree(nfree(p));
+                       p = cast(q, INT, 0);
+               }
+               break;
+       }
+
+       return(p);
+       }
+
+int
+ispow2(CONSZ c)
+{
+       int i;
+       if( c <= 0 || (c&(c-1)) ) return(-1);
+       for( i=0; c>1; ++i) c >>= 1;
+       return(i);
+}
+
+int
+nncon(NODE *p)
+{
+       /* is p a constant without a name */
+       return( p->n_op == ICON && p->n_sp == NULL );
+}
diff --git a/lang/pcc/pcc/cc/ccom/pass1.h b/lang/pcc/pcc/cc/ccom/pass1.h
new file mode 100644 (file)
index 0000000..335716f
--- /dev/null
@@ -0,0 +1,771 @@
+/*     $Id: pass1.h,v 1.295 2016/03/08 18:17:45 ragge Exp $    */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+
+#ifndef MKEXT
+#include "external.h"
+#else
+typedef unsigned int bittype; /* XXX - for basicblock */
+#endif
+#include "manifest.h"
+#include "softfloat.h"
+
+/*
+ * Storage classes
+ */
+#define SNULL          0
+#define AUTO           1
+#define EXTERN         2
+#define STATIC         3
+#define REGISTER       4
+#define EXTDEF         5
+#define THLOCAL                6
+#define KEYWORD                7
+#define MOS            8
+#define PARAM          9
+#define STNAME         10
+#define MOU            11
+#define UNAME          12
+#define TYPEDEF                13
+/* #define FORTRAN             14 */
+#define ENAME          15
+#define MOE            16
+/* #define UFORTRAN    17 */
+#define USTATIC                18
+
+       /* field size is ORed in */
+#define FIELD          0200
+#define FLDSIZ         0177
+extern char *scnames(int);
+
+/*
+ * Symbol table flags
+ */
+#define        SNORMAL         0
+#define        STAGNAME        01
+#define        SLBLNAME        02
+#define        SMOSNAME        03
+#define        SSTRING         04
+#define        NSTYPES         05
+#define        SMASK           07
+
+#define        STLS            00010   /* Thread Local Support variable */
+#define SINSYS         00020   /* Declared in system header */
+#define        SSTMT           SINSYS  /* Allocate symtab on statement stack */
+#define SNOCREAT       00040   /* don't create a symbol in lookup() */
+#define STEMP          00100   /* Allocate symtab from temp or perm mem */
+#define        SDYNARRAY       00200   /* symbol is dynamic array on stack */
+#define        SINLINE         00400   /* function is of type inline */
+#define        SBLK            SINLINE /* Allocate symtab from blk mem */
+#define        STNODE          01000   /* symbol shall be a temporary node */
+#define        SBUILTIN        02000   /* this is a builtin function */
+#define        SASG            04000   /* symbol is assigned to already */
+#define        SLOCAL1         010000
+#define        SLOCAL2         020000
+#define        SLOCAL3         040000
+
+       /* alignment of initialized quantities */
+#ifndef AL_INIT
+#define        AL_INIT ALINT
+#endif
+
+struct rstack;
+struct symtab;
+union arglist;
+#ifdef GCC_COMPAT
+struct gcc_attr_pack;
+#endif
+
+/*
+ * Dimension/prototype information.
+ *     ddim > 0 holds the dimension of an array.
+ *     ddim < 0 is a dynamic array and refers to a tempnode.
+ *     ...unless:
+ *             ddim == NOOFFSET, an array without dimenston, "[]"
+ *             ddim == -1, dynamic array while building before defid.
+ */
+union dimfun {
+       int     ddim;           /* Dimension of an array */
+       union arglist *dfun;    /* Prototype index */
+};
+
+/*
+ * Argument list member info when storing prototypes.
+ */
+union arglist {
+       TWORD type;
+       union dimfun *df;
+       struct attr *sap;
+};
+#define TNULL          INCREF(FARG) /* pointer to FARG -- impossible type */
+#define TELLIPSIS      INCREF(INCREF(FARG))
+
+/*
+ * Symbol table definition.
+ */
+struct symtab {
+       struct  symtab *snext;  /* link to other symbols in the same scope */
+       int     soffset;        /* offset or value */
+       char    sclass;         /* storage class */
+       char    slevel;         /* scope level */
+       short   sflags;         /* flags, see below */
+       char    *sname;         /* Symbol name */
+       TWORD   stype;          /* type word */
+       TWORD   squal;          /* qualifier word */
+       union   dimfun *sdf;    /* ptr to the dimension/prototype array */
+       struct  attr *sap;      /* the base type attribute list */
+};
+
+#define        ISSOU(ty)   ((ty) == STRTY || (ty) == UNIONTY)
+
+/*
+ * External definitions
+ */
+struct swents {                        /* switch table */
+       struct swents *next;    /* Next struct in linked list */
+       CONSZ   sval;           /* case value */
+       int     slab;           /* associated label */
+};
+int mygenswitch(int, TWORD, struct swents **, int);
+
+extern int blevel;
+extern int oldstyle;
+
+extern int lineno, nerrors, issyshdr;
+
+extern char *ftitle;
+extern struct symtab *cftnsp;
+extern int autooff, maxautooff, argoff;
+
+extern OFFSZ inoff;
+
+extern int reached;
+extern int isinlining;
+extern int xinline, xgnu89, xgnu99;
+extern int bdebug, ddebug, edebug, idebug, ndebug;
+extern int odebug, pdebug, sdebug, tdebug, xdebug;
+
+/* various labels */
+extern int brklab;
+extern int contlab;
+extern int flostat;
+extern int retlab;
+extern int doing_init, statinit;
+extern short sztable[];
+extern char *astypnames[];
+
+/* pragma globals */
+extern int pragma_allpacked, pragma_packed, pragma_aligned;
+
+/*
+ * Flags used in the (elementary) flow analysis ...
+ */
+#define FBRK           02
+#define FCONT          04
+#define FDEF           010
+#define FLOOP          020
+
+/*
+ * Location counters
+ */
+#define NOSEG          -1
+#define PROG           0               /* (ro) program segment */
+#define DATA           1               /* (rw) data segment */
+#define RDATA          2               /* (ro) data segment */
+#define LDATA          3               /* (rw) local data */
+#define UDATA          4               /* (rw) uninitialized data */
+#define STRNG          5               /* (ro) string segment */
+#define PICDATA                6               /* (rw) relocatable data segment */
+#define PICRDATA       7               /* (ro) relocatable data segment */
+#define PICLDATA       8               /* (rw) local relocatable data */
+#define TLSDATA                9               /* (rw) TLS data segment */
+#define TLSUDATA       10              /* (rw) TLS uninitialized segment */
+#define CTORS          11              /* constructor */
+#define DTORS          12              /* destructor */
+#define        NMSEG           13              /* other (named) segment */
+
+extern int lastloc;
+void locctr(int type, struct symtab *sp);
+void setseg(int type, char *name);
+void defalign(int al);
+void symdirec(struct symtab *sp);
+
+/*
+ * Tree struct for pass1.  
+ */
+struct flt;
+
+typedef struct p1node {
+       int     n_op;
+       TWORD   n_type;
+       TWORD   n_qual;
+       union {
+               char *  _name;
+               union   dimfun *_df;
+       } n_5;
+       struct attr *n_ap;
+       union {
+               struct {
+                       union {
+                               struct p1node *_left;
+                               CONSZ _val;
+                       } n_l;
+                       union {
+                               struct p1node *_right;
+                               int _rval;
+                               struct symtab *_sp;
+                       } n_r;
+               } n_u;
+               struct {
+                       struct flt *_dcon;
+                       struct flt *_ccon;
+               };
+       } n_f;
+} P1ND;
+
+#define glval(p)       ((p)->n_f.n_u.n_l._val)
+#define slval(p,v)     ((p)->n_f.n_u.n_l._val = (v))
+#define        n_ccon          n_f._ccon
+
+
+/*     mark an offset which is undefined */
+
+#define NOOFFSET       (-10201)
+
+/* declarations of various functions */
+extern P1ND
+       *buildtree(int, P1ND *, P1ND *r),
+       *mkty(unsigned, union dimfun *, struct attr *),
+       *rstruct(char *, int),
+       *dclstruct(struct rstack *),
+       *strend(char *, TWORD),
+       *tymerge(P1ND *, P1ND *),
+       *stref(P1ND *),
+#ifdef WORD_ADDRESSED
+       *offcon(OFFSZ, TWORD, union dimfun *, struct attr *),
+#endif
+       *bcon(int),
+       *xbcon(CONSZ, struct symtab *, TWORD),
+       *bpsize(P1ND *),
+       *convert(P1ND *, int),
+       *pconvert(P1ND *),
+       *oconvert(P1ND *),
+       *ptmatch(P1ND *),
+       *makety(P1ND *, TWORD, TWORD, union dimfun *, struct attr *),
+       *block(int, P1ND *, P1ND *, TWORD, union dimfun *, struct attr *),
+       *doszof(P1ND *),
+       *p1alloc(void),
+       *optim(P1ND *),
+       *clocal(P1ND *),
+       *tempnode(int, TWORD, union dimfun *, struct attr *),
+       *eve(P1ND *),
+       *doacall(struct symtab *, P1ND *, P1ND *);
+P1ND   *intprom(P1ND *);
+OFFSZ  tsize(TWORD, union dimfun *, struct attr *),
+       psize(P1ND *);
+P1ND * typenode(P1ND *new);
+void   spalloc(P1ND *, P1ND *, OFFSZ);
+char   *exname(char *);
+struct flt     *floatcon(char *);
+struct flt *fhexcon(char *);
+P1ND   *bdty(int op, ...);
+extern struct rstack *rpole;
+
+int oalloc(struct symtab *, int *);
+void deflabel(char *, P1ND *);
+void gotolabel(char *);
+unsigned int esccon(char **);
+void inline_start(struct symtab *, int class);
+void inline_end(void);
+void inline_addarg(struct interpass *);
+void inline_ref(struct symtab *);
+void inline_prtout(void);
+void inline_args(struct symtab **, int);
+P1ND *inlinetree(struct symtab *, P1ND *, P1ND *);
+void ftnarg(P1ND *);
+struct rstack *bstruct(char *, int, P1ND *);
+void moedef(char *);
+void beginit(struct symtab *);
+void simpleinit(struct symtab *, P1ND *);
+struct symtab *lookup(char *, int);
+struct symtab *getsymtab(char *, int);
+char *addstring(char *);
+char *addname(char *);
+void symclear(int);
+struct symtab *hide(struct symtab *);
+void soumemb(P1ND *, char *, int);
+int talign(unsigned int, struct attr *);
+void bfcode(struct symtab **, int);
+int chkftn(union arglist *, union arglist *);
+void branch(int);
+void cbranch(P1ND *, P1ND *);
+void extdec(struct symtab *);
+void defzero(struct symtab *);
+int falloc(struct symtab *, int, P1ND *);
+TWORD ctype(TWORD);  
+void inval(CONSZ, int, P1ND *);
+int ninval(CONSZ, int, P1ND *);
+void infld(CONSZ, int, CONSZ);
+void zbits(CONSZ, int);
+void instring(struct symtab *);
+void inwstring(struct symtab *);
+void plabel(int);
+void bjobcode(void);
+void ejobcode(int);
+void calldec(P1ND *, P1ND *);
+int cisreg(TWORD);
+void asginit(P1ND *);
+void desinit(P1ND *);
+void endinit(int);
+void endictx(void);
+void sspinit(void);
+void sspstart(void);
+void sspend(void);
+void ilbrace(void);
+void irbrace(void);
+CONSZ scalinit(P1ND *);
+void p1print(char *, ...);
+char *copst(int);
+int cdope(int);
+void myp2tree(P1ND *);
+void lcommprint(void), strprint(void);
+void lcommdel(struct symtab *);
+P1ND *funcode(P1ND *);
+struct symtab *enumhd(char *);
+P1ND *enumdcl(struct symtab *);
+P1ND *enumref(char *);
+CONSZ icons(P1ND *);
+CONSZ valcast(CONSZ v, TWORD t);
+int mypragma(char *);
+char *pragtok(char *);
+int eat(int);
+void fixdef(struct symtab *);
+int cqual(TWORD, TWORD);
+void defloc(struct symtab *);
+int fldchk(int);
+int nncon(P1ND *);
+void cunput(char);
+P1ND *nametree(struct symtab *sp);
+void pass1_lastchance(struct interpass *);
+void fldty(struct symtab *p);
+struct suedef *sueget(struct suedef *p);
+void complinit(void);
+void kwinit(void);
+P1ND *structref(P1ND *p, int f, char *name);
+P1ND *cxop(int op, P1ND *l, P1ND *r);
+P1ND *imop(int op, P1ND *l, P1ND *r);
+P1ND *cxelem(int op, P1ND *p);
+P1ND *cxconj(P1ND *p);
+P1ND *cxcast(P1ND *p1, P1ND *p2);
+P1ND *cxret(P1ND *p, P1ND *q);
+P1ND *imret(P1ND *p, P1ND *q);
+P1ND *cast(P1ND *p, TWORD t, TWORD q);
+P1ND *ccast(P1ND *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue);
+int andable(P1ND *);
+int conval(P1ND *, int, P1ND *);
+int ispow2(CONSZ);
+void defid(P1ND *q, int class);
+void defid2(P1ND *q, int class, char *astr);
+void efcode(void);
+void ecomp(P1ND *p);
+int upoff(int size, int alignment, int *poff);
+void nidcl(P1ND *p, int class);
+void nidcl2(P1ND *p, int class, char *astr);
+void eprint(P1ND *, int, int *, int *);
+int uclass(int class);
+int notlval(P1ND *);
+void ecode(P1ND *p);
+void ftnend(void);
+void dclargs(void);
+int suemeq(struct attr *s1, struct attr *s2);
+struct symtab *strmemb(struct attr *ap);
+int yylex(void);
+void yyerror(char *);
+int pragmas_gcc(char *t);
+int concast(P1ND *p, TWORD t);
+char *stradd(char *old, char *new);
+#ifdef WORD_ADDRESSED
+#define rmpconv(p) (p)
+#else
+P1ND *rmpconv(P1ND *);
+#endif
+P1ND *optloop(P1ND *);
+P1ND *nlabel(int label);
+TWORD styp(void);
+void *stmtalloc(size_t);
+void *blkalloc(size_t);
+void stmtfree(void);
+void blkfree(void);
+char *getexname(struct symtab *sp);
+void putjops(P1ND *p, void *arg);
+
+void p1walkf(P1ND *, void (*f)(P1ND *, void *), void *);
+void p1fwalk(P1ND *t, void (*f)(P1ND *, int, int *, int *), int down);
+void p1listf(P1ND *p, void (*f)(P1ND *));
+void p1flist(P1ND *p, void (*f)(P1ND *, void *), void *);
+P1ND *p1nfree(P1ND *);
+void p1tfree(P1ND *);
+P1ND *p1tcopy(P1ND *);
+
+struct flt {
+       union {
+               long double fp; 
+               struct softfloat sf;
+       };
+       TWORD t;
+};     
+typedef struct flt FLT;        
+FLT flt_zero; 
+#define        fltallo()               stmtalloc(sizeof(FLT))
+#define FLOAT_ZERO             (&flt_zero)
+#define        FCAST(x)                ((FLT *)(x))
+
+#ifdef NATIVE_FLOATING_POINT
+#define FLOAT_PLUS(p1,p2)      ((p1)->n_dcon->fp += (p2)->n_dcon->fp)
+#define FLOAT_MINUS(p1,p2)     ((p1)->n_dcon->fp -= (p2)->n_dcon->fp)
+#define FLOAT_MUL(p1,p2)       ((p1)->n_dcon->fp *= (p2)->n_dcon->fp)
+#define FLOAT_DIV(p1,p2)       ((p1)->n_dcon->fp /= (p2)->n_dcon->fp)
+#define FLOAT_ISZERO(p)                ((p)->fp == 0.0)
+#define FLOAT_FP2FP(f,t)       (f->fp = (t == FLOAT ? (float)f->fp :   \
+       t == DOUBLE ? (double)f->fp : f->fp))
+#define FLOAT_INT2FP(d,p,v)    (ISUNSIGNED(v) ? \
+       (d->fp = (long double)(U_CONSZ)(p)) : (d->fp = (long double)(CONSZ)(p)))
+#define FLOAT_FP2INT(i,d,t)     (ISUNSIGNED(t) ? \
+       (i = (U_CONSZ)(d->fp)) : (i = d->fp))
+#define FLOAT_EQ(d1,d2)                (d1->fp == d2->fp)
+#define FLOAT_NE(d1,d2)                (d1->fp != d2->fp)
+#define FLOAT_GE(d1,d2)                (d1->fp >= d2->fp)
+#define FLOAT_GT(d1,d2)                (d1->fp > d2->fp)
+#define FLOAT_LE(d1,d2)                (d1->fp <= d2->fp)
+#define FLOAT_LT(d1,d2)                (d1->fp < d2->fp)
+#define FLOAT_NEG(p)           (p->fp = -p->fp)
+#define        FLOAT_SETZERO(d)        (d)->fp = FLOAT_ZERO
+
+#else
+#define FLOAT_PLUS(p1,p2)      p1->n_dcon->sf = \
+       soft_plus(p1->n_dcon->sf, p2->n_dcon->sf)
+#define FLOAT_MINUS(p1,p2)     p1->n_dcon->sf = \
+       soft_minus(p1->n_dcon->sf, p2->n_dcon->sf)
+#define FLOAT_MUL(p1,p2)       p1->n_dcon->sf = \
+       soft_mul(p1->n_dcon->sf, p2->n_dcon->sf)
+#define FLOAT_DIV(p1,p2)       p1->n_dcon->sf = \
+       soft_div(p1->n_dcon->sf, p2->n_dcon->sf)
+#define FLOAT_ISZERO(p)                soft_isz(p->sf)
+#define FLOAT_FP2FP(f,t)       f->sf = soft_fp2fp(f->sf, t)
+#define FLOAT_INT2FP(f,p,t)    f->sf = soft_int2fp(p, t)
+#define FLOAT_FP2INT(i,d,t)    i = soft_fp2int(d->sf, t) /* XXX fp format */
+#define FLOAT_EQ(d1,d2)                soft_cmp(d1->sf, d2->sf, EQ)
+#define FLOAT_NE(d1,d2)                soft_cmp(d1->sf, d2->sf, NE)
+#define FLOAT_GE(d1,d2)                soft_cmp(d1->sf, d2->sf, GE)
+#define FLOAT_GT(d1,d2)                soft_cmp(d1->sf, d2->sf, GT)
+#define FLOAT_LE(d1,d2)                soft_cmp(d1->sf, d2->sf, LE)
+#define FLOAT_LT(d1,d2)                soft_cmp(d1->sf, d2->sf, LT)
+#define FLOAT_NEG(flt)         flt->sf = soft_neg(flt->sf)
+#define        FLOAT_SETZERO(d)        (d)->sf = FLOAT_ZERO
+
+#endif
+
+enum { ATTR_FIRST = ATTR_MI_MAX + 1,
+
+       /* PCC used attributes */
+       ATTR_COMPLEX,   /* Internal definition of complex */
+       xxxATTR_BASETYP,        /* Internal; see below */
+       ATTR_QUALTYP,   /* Internal; const/volatile, see below */
+       ATTR_ALIGNED,   /* Internal; also used as gcc type attribute */
+       ATTR_NORETURN,  /* Function does not return */
+       ATTR_STRUCT,    /* Internal; element list */
+#define ATTR_MAX ATTR_STRUCT
+
+       ATTR_P1LABELS,  /* used to store stuff while parsing */
+       ATTR_SONAME,    /* output name of symbol */
+
+#ifdef GCC_COMPAT
+       /* type attributes */
+       GCC_ATYP_PACKED,
+       GCC_ATYP_SECTION,
+       GCC_ATYP_TRANSP_UNION,
+       GCC_ATYP_UNUSED,
+       GCC_ATYP_DEPRECATED,
+       GCC_ATYP_MAYALIAS,
+
+       /* variable attributes */
+       GCC_ATYP_MODE,
+
+       /* function attributes */
+       GCC_ATYP_FORMAT,
+       GCC_ATYP_NONNULL,
+       GCC_ATYP_SENTINEL,
+       GCC_ATYP_WEAK,
+       GCC_ATYP_FORMATARG,
+       GCC_ATYP_GNU_INLINE,
+       GCC_ATYP_MALLOC,
+       GCC_ATYP_NOTHROW,
+       GCC_ATYP_CONST,
+       GCC_ATYP_PURE,
+       GCC_ATYP_CONSTRUCTOR,
+       GCC_ATYP_DESTRUCTOR,
+       GCC_ATYP_VISIBILITY,
+       GCC_ATYP_WARN_UNUSED_RESULT,
+       GCC_ATYP_USED,
+       GCC_ATYP_NO_INSTR_FUN,
+       GCC_ATYP_NOINLINE,
+       GCC_ATYP_ALIAS,
+       GCC_ATYP_WEAKREF,
+       GCC_ATYP_ALLOCSZ,
+       GCC_ATYP_ALW_INL,
+       GCC_ATYP_TLSMODEL,
+       GCC_ATYP_ALIASWEAK,
+       GCC_ATYP_RETURNS_TWICE,
+       GCC_ATYP_WARNING,
+       GCC_ATYP_NOCLONE,
+       GCC_ATYP_REGPARM,
+       GCC_ATYP_FASTCALL,
+
+       /* other stuff */
+       GCC_ATYP_BOUNDED,       /* OpenBSD extra boundary checks */
+
+       /* OSX toolchain */
+       GCC_ATYP_WEAKIMPORT,
+
+       GCC_ATYP_MAX,
+#endif
+#ifdef ATTR_P1_TARGET
+       ATTR_P1_TARGET,
+#endif
+       ATTR_P1_MAX
+};
+
+/*
+#ifdef notdef
+ * ATTR_BASETYP has the following layout:
+ * aa[0].iarg has size
+ * aa[1].iarg has alignment
+#endif
+ * ATTR_QUALTYP has the following layout:
+ * aa[0].iarg has CON/VOL + FUN/ARY/PTR
+ * Not defined yet...
+ * aa[3].iarg is dimension for arrays (XXX future)
+ * aa[3].varg is function defs for functions.
+ */
+#ifdef notdef
+#define        atypsz  aa[0].iarg
+#define        aalign  aa[1].iarg
+#endif
+
+/*
+ * ATTR_STRUCT member list.
+ */
+#define amlist  aa[0].varg
+#define amsize  aa[1].iarg
+#define        strattr(x)      (attr_find(x, ATTR_STRUCT))
+
+void gcc_init(void);
+int gcc_keyword(char *);
+struct attr *gcc_attr_parse(P1ND *);
+void gcc_tcattrfix(P1ND *);
+struct gcc_attrib *gcc_get_attr(struct suedef *, int);
+void dump_attr(struct attr *gap);
+void gcc_modefix(P1ND *);
+P1ND *gcc_eval_timode(int op, P1ND *, P1ND *);
+P1ND *gcc_eval_ticast(int op, P1ND *, P1ND *);
+P1ND *gcc_eval_tiuni(int op, P1ND *);
+struct attr *isti(P1ND *p);
+
+#ifndef NO_C_BUILTINS
+struct bitable {
+       char *name;
+       P1ND *(*fun)(const struct bitable *, P1ND *a);
+       short flags;
+#define        BTNOPROTO       001
+#define        BTNORVAL        002
+#define        BTNOEVE         004
+#define        BTGNUONLY       010
+       short narg;
+       TWORD *tp;
+       TWORD rt;
+};
+
+P1ND *builtin_check(struct symtab *, P1ND *a);
+void builtin_init(void);
+
+/* Some builtins targets need to implement */
+P1ND *builtin_frame_address(const struct bitable *bt, P1ND *a);
+P1ND *builtin_return_address(const struct bitable *bt, P1ND *a);
+P1ND *builtin_cfa(const struct bitable *bt, P1ND *a);
+#endif
+
+
+#ifdef STABS
+void stabs_init(void);
+void stabs_file(char *);
+void stabs_efile(char *);
+void stabs_line(int);
+void stabs_rbrac(int);
+void stabs_lbrac(int);
+void stabs_func(struct symtab *);
+void stabs_newsym(struct symtab *);
+void stabs_chgsym(struct symtab *);
+void stabs_struct(struct symtab *, struct attr *);
+#endif
+#ifdef DWARF
+void dwarf_init(char *);
+void dwarf_file(char *);
+void dwarf_end(void);
+#endif
+
+#ifndef CHARCAST
+/* to make character constants into character connstants */
+/* this is a macro to defend against cross-compilers, etc. */
+#define CHARCAST(x) (char)(x)
+#endif
+
+/* sometimes int is smaller than pointers */
+#if SZPOINT(CHAR) <= SZINT
+#define INTPTR  INT
+#elif SZPOINT(CHAR) <= SZLONG
+#define INTPTR  LONG
+#elif SZPOINT(CHAR) <= SZLONGLONG
+#define INTPTR  LONGLONG
+#else
+#error int size unknown
+#endif
+
+/* Generate a bitmask from a given type size */
+#define SZMASK(y) ((((1LL << ((y)-1))-1) << 1) | 1)
+
+/*
+ * finction specifiers.
+ */
+#define        INLINE          1
+#define        NORETURN        2
+
+/*
+ * C compiler first pass extra defines.
+ */
+#define        QUALIFIER       (MAXOP+1)
+#define        CLASS           (MAXOP+2)
+#define        RB              (MAXOP+3)
+#define        DOT             (MAXOP+4)
+#define        ELLIPSIS        (MAXOP+5)
+#define        TYPE            (MAXOP+6)
+#define        LB              (MAXOP+7)
+#define        COMOP           (MAXOP+8)
+#define        QUEST           (MAXOP+9)
+#define        COLON           (MAXOP+10)
+#define        ANDAND          (MAXOP+11)
+#define        OROR            (MAXOP+12)
+#define        NOT             (MAXOP+13)
+#define        CAST            (MAXOP+14)
+#define        STRING          (MAXOP+15)
+
+/* The following must be in the same order as their NOASG counterparts */
+#define        PLUSEQ          (MAXOP+16)
+#define        MINUSEQ         (MAXOP+17)
+#define        DIVEQ           (MAXOP+18)
+#define        MODEQ           (MAXOP+19)
+#define        MULEQ           (MAXOP+20)
+#define        ANDEQ           (MAXOP+21)
+#define        OREQ            (MAXOP+22)
+#define        EREQ            (MAXOP+23)
+#define        LSEQ            (MAXOP+24)
+#define        RSEQ            (MAXOP+25)
+
+#define        UNASG           (-(PLUSEQ-PLUS))+
+
+#define INCR           (MAXOP+26)
+#define DECR           (MAXOP+27)
+#define SZOF           (MAXOP+28)
+#define CLOP           (MAXOP+29)
+#define ATTRIB         (MAXOP+30)
+#define XREAL          (MAXOP+31)
+#define XIMAG          (MAXOP+32)
+#define TYMERGE                (MAXOP+33)
+#define LABEL          (MAXOP+34)
+#define BIQUEST                (MAXOP+35)
+#define UPLUS          (MAXOP+36)
+#define ALIGN          (MAXOP+37)
+#define FUNSPEC                (MAXOP+38)
+#define STREF          (MAXOP+39)
+
+/*
+ * The following types are only used in pass1.
+ */
+#define SIGNED         (MAXTYPES+1)
+#define FARG           (MAXTYPES+2)
+#define        FIMAG           (MAXTYPES+3)
+#define        IMAG            (MAXTYPES+4)
+#define        LIMAG           (MAXTYPES+5)
+#define        FCOMPLEX        (MAXTYPES+6)
+#define        COMPLEX         (MAXTYPES+7)
+#define        LCOMPLEX        (MAXTYPES+8)
+#define        ENUMTY          (MAXTYPES+9)
+
+#define        ISFTY(x)        ((x) >= FLOAT && (x) <= LDOUBLE)
+#define        ISCTY(x)        ((x) >= FCOMPLEX && (x) <= LCOMPLEX)
+#define        ISITY(x)        ((x) >= FIMAG && (x) <= LIMAG)
+#define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX))
+
+#define coptype(o)     (cdope(o)&TYFLG)
+#define clogop(o)      (cdope(o)&LOGFLG)
+#define casgop(o)      (cdope(o)&ASGFLG)
+
+#ifdef TWOPASS
+#define        PRTPREF "* "
+#else
+#define        PRTPREF ""
+#endif
+
+/*
+ * Allocation routines.
+ */
+#if defined(__PCC__) || defined(__GNUC__)
+#define        FUNALLO(x)      __builtin_alloca(x)
+#define        FUNFREE(x)
+#elif defined(HAVE_ALLOCA)
+#define FUNALLO(x)      alloca(x)
+#define FUNFREE(x)
+#else
+#define FUNALLO(x)     malloc(x)
+#define FUNFREE(x)     free(x)
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/pftn.c b/lang/pcc/pcc/cc/ccom/pftn.c
new file mode 100644 (file)
index 0000000..ac60d33
--- /dev/null
@@ -0,0 +1,3585 @@
+/*     $Id: pftn.c,v 1.421 2016/03/05 15:31:24 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Many changes from the 32V sources, among them:
+ * - New symbol table manager (moved to another file).
+ * - Prototype saving/checks.
+ */
+
+# include "pass1.h"
+#include "unicode.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "cgram.h"
+
+#define        NODE P1ND
+#define        tfree p1tfree
+#define        nfree p1nfree
+#define        ccopy p1tcopy
+#define        flist p1flist
+#define        fwalk p1fwalk
+
+struct symtab *cftnsp;
+int arglistcnt, dimfuncnt;     /* statistics */
+int symtabcnt, suedefcnt;      /* statistics */
+int lcommsz, blkalloccnt;
+int autooff,           /* the next unused automatic offset */
+    maxautooff,                /* highest used automatic offset in function */
+    argoff;            /* the next unused argument offset */
+int retlab = NOLAB;    /* return label for subroutine */
+int brklab;
+int contlab;
+int flostat;
+int blevel;
+int reached, prolab;
+
+struct params;
+
+#ifdef NATIVE_FLOATING_POINT
+FLT flt_zero = { { .fp = 0.0, }, LDOUBLE };
+#endif
+
+#define MKTY(p, t, d, s) r = p1alloc(); *r = *p; \
+       r = argcast(r, t, d, s); *p = *r; nfree(r);
+
+/*
+ * Linked list stack while reading in structs.
+ */
+struct rstack {
+       struct  rstack *rnext;
+       int     rsou;
+       int     rstr;
+       struct  symtab *rsym;
+       struct  symtab *rb;
+       struct  attr *ap;
+       int     flags;
+#define        LASTELM 1
+} *rpole;
+
+/*
+ * Linked list for parameter (and struct elements) declaration.
+ */
+static struct params {
+       struct params *prev;
+       struct symtab *sym;
+} *lparam;
+static int nparams;
+
+/* defines used for getting things off of the initialization stack */
+
+NODE *arrstk[10];
+int arrstkp;
+static int intcompare;
+NODE *parlink;
+
+void fixtype(NODE *p, int class);
+int fixclass(int class, TWORD type);
+static void dynalloc(struct symtab *p, int *poff);
+static void evalidx(struct symtab *p);
+int isdyn(struct symtab *p);
+void inforce(OFFSZ n);
+void vfdalign(int n);
+static void ssave(struct symtab *);
+#ifdef PCC_DEBUG
+static void alprint(union arglist *al, int in);
+#endif
+static void lcommadd(struct symtab *sp);
+static NODE *mkcmplx(NODE *p, TWORD dt);
+static void cxargfixup(NODE *arg, TWORD dt, struct attr *ap);
+extern int fun_inline;
+
+void
+defid(NODE *q, int class)
+{
+       defid2(q, class, 0);
+}
+
+static void
+addsoname(struct symtab *sp, char *so)
+{
+       struct attr *ap = attr_new(ATTR_SONAME, 1);
+       ap->sarg(0) = so;
+       sp->sap = attr_add(sp->sap, ap);
+}
+
+/*
+ * Declaration of an identifier.  Handles redeclarations, hiding,
+ * incomplete types and forward declarations.
+ *
+ * q is a TYPE node setup after parsing with n_type, n_df and n_ap.
+ * n_sp is a pointer to the not-yet initalized symbol table entry
+ * unless it's a redeclaration or supposed to hide a variable.
+ */
+
+void
+defid2(NODE *q, int class, char *astr)
+{
+       struct attr *ap;
+       struct symtab *p;
+       TWORD type, qual;
+       TWORD stp, stq;
+       int scl;
+       union dimfun *dsym, *ddef;
+       int slev, temp, changed;
+
+       if (q == NIL)
+               return;  /* an error was detected */
+
+#ifdef GCC_COMPAT
+       gcc_modefix(q);
+#endif
+       p = q->n_sp;
+
+       if (p->sname == NULL)
+               cerror("defining null identifier");
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("defid(%s '%s'(%p), ", p->sname, "soname" , p);
+               tprint(q->n_type, q->n_qual);
+               printf(", %s, (%p)), level %d\n\t", scnames(class),
+                   q->n_df, blevel);
+#ifdef GCC_COMPAT
+               dump_attr(q->n_ap);
+#endif
+       }
+#endif
+
+       fixtype(q, class);
+
+       type = q->n_type;
+       qual = q->n_qual;
+       class = fixclass(class, type);
+
+       stp = p->stype;
+       stq = p->squal;
+       slev = p->slevel;
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("        modified to ");
+               tprint(type, qual);
+               printf(", %s\n", scnames(class));
+               printf("        previous def'n: ");
+               tprint(stp, stq);
+               printf(", %s, (%p,%p)), level %d\n",
+                   scnames(p->sclass), p->sdf, p->sap, slev);
+       }
+#endif
+
+       if (blevel == 1) {
+               switch (class) {
+               default:
+                       if (!(class&FIELD) && !ISFTN(type))
+                               uerror("declared argument %s missing",
+                                   p->sname );
+                       break;
+               case MOS:
+               case MOU:
+                       cerror("field5");
+               case TYPEDEF:
+               case PARAM:
+                       break;
+               }
+       }
+
+       if (stp == UNDEF)
+               goto enter; /* New symbol */
+
+       if (type != stp)
+               goto mismatch;
+
+       if (blevel > slev && (class == AUTO || class == REGISTER))
+               /* new scope */
+               goto mismatch;
+
+       /*
+        * test (and possibly adjust) dimensions.
+        * also check that prototypes are correct.
+        */
+       dsym = p->sdf;
+       ddef = q->n_df;
+       changed = 0;
+       for (temp = type; temp & TMASK; temp = DECREF(temp)) {
+               if (ISARY(temp)) {
+                       if (dsym->ddim == NOOFFSET) {
+                               dsym->ddim = ddef->ddim;
+                               changed = 1;
+                       } else if (ddef->ddim != NOOFFSET &&
+                           dsym->ddim!=ddef->ddim) {
+                               goto mismatch;
+                       }
+                       ++dsym;
+                       ++ddef;
+               } else if (ISFTN(temp)) {
+                       /* add a late-defined prototype here */
+                       if (!oldstyle && dsym->dfun == NULL)
+                               dsym->dfun = ddef->dfun;
+                       if (!oldstyle && ddef->dfun != NULL &&
+                           chkftn(dsym->dfun, ddef->dfun))
+                               uerror("declaration doesn't match prototype");
+                       dsym++, ddef++;
+               }
+       }
+#ifdef STABS
+       if (changed && gflag)
+               stabs_chgsym(p); /* symbol changed */
+#endif
+
+       /* check that redeclarations are to the same structure */
+       if (temp == STRTY || temp == UNIONTY) {
+               if (strmemb(p->sap) != strmemb(q->n_ap))
+                       goto mismatch;
+       }
+
+       scl = p->sclass;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("        previous class: %s\n", scnames(scl));
+#endif
+
+       /*
+        * Its allowed to add attributes to existing declarations.
+        * Be careful though not to trash existing attributes.
+        * XXX - code below is probably not correct.
+        */
+       if (p->sap && p->sap->atype <= ATTR_MAX) {
+               /* nothing special, just overwrite */
+               p->sap = q->n_ap;
+       } else {
+               if (p->slevel == blevel) {
+                       for (ap = q->n_ap; ap; ap = ap->next) {
+                               if (ap->atype > ATTR_MAX)
+                                       p->sap = attr_add(p->sap, attr_dup(ap));
+                       }
+               } else
+                       p->sap = q->n_ap;
+       }
+
+       if (class & FIELD)
+               cerror("field1");
+       switch(class) {
+
+       case EXTERN:
+               if (astr)
+                       addsoname(p, astr);
+               switch( scl ){
+               case STATIC:
+               case USTATIC:
+                       if( slev==0 )
+                               goto done;
+                       break;
+               case EXTDEF:
+               case EXTERN:
+                       goto done;
+               case SNULL:
+                       if (p->sflags & SINLINE) {
+                               p->sclass = EXTDEF;
+                               inline_ref(p);
+                               goto done;
+                       }
+                       break;
+               }
+               break;
+
+       case STATIC:
+               if (astr)
+                       addsoname(p, astr);
+               if (scl==USTATIC || (scl==EXTERN && blevel==0)) {
+                       p->sclass = STATIC;
+                       goto done;
+               }
+               if (changed || (scl == STATIC && blevel == slev))
+                       goto done; /* identical redeclaration */
+               break;
+
+       case USTATIC:
+               if (scl==STATIC || scl==USTATIC)
+                       goto done;
+               break;
+
+       case TYPEDEF:
+               if (scl == class)
+                       goto done;
+               break;
+
+       case MOU:
+       case MOS:
+               cerror("field6");
+
+       case EXTDEF:
+               switch (scl) {
+               case EXTERN:
+                       p->sclass = EXTDEF;
+                       goto done;
+               case USTATIC:
+                       p->sclass = STATIC;
+                       goto done;
+               case SNULL:
+#ifdef GCC_COMPAT
+                       /*
+                        * Handle redeclarations of inlined functions.
+                        * This is allowed if the previous declaration is of
+                        * type gnu_inline.
+                        */
+                       if (attr_find(p->sap, GCC_ATYP_GNU_INLINE))
+                               goto done;
+#endif
+                       break;
+               }
+               break;
+
+       case AUTO:
+       case REGISTER:
+               break;  /* mismatch.. */
+       case SNULL:
+               if (fun_inline && ISFTN(type)) {
+                       if (scl == EXTERN) {
+                               p->sclass = EXTDEF;
+                               inline_ref(p);
+                       }
+                       goto done;
+               }
+               break;
+       }
+
+       mismatch:
+
+       /*
+        * Only allowed for automatic variables.
+        */
+       if ((blevel == 2 && slev == 1) || blevel <= slev || class == EXTERN) {
+               uerror("redeclaration of %s", p->sname);
+               return;
+       }
+       if ((ISFTN(p->stype) && ISFTN(type)) ||
+           (!ISFTN(p->stype) && !ISFTN(type)))
+               warner(Wshadow, p->sname, p->slevel ? "local" : "global");
+       q->n_sp = p = hide(p);
+
+       enter:  /* make a new entry */
+
+       if (type == VOID && class != TYPEDEF)
+               uerror("void not allowed for variables");
+
+#ifdef PCC_DEBUG
+       if(ddebug)
+               printf("        new entry made\n");
+#endif
+       p->stype = type;
+       p->squal = qual;
+       p->sclass = (char)class;
+       p->slevel = (char)blevel;
+       p->soffset = NOOFFSET;
+       if (q->n_ap)
+               p->sap = attr_add(q->n_ap, p->sap);
+
+       /* copy dimensions */
+       p->sdf = q->n_df;
+       /* Do not save param info for old-style functions */
+       if (ISFTN(type) && oldstyle)
+               p->sdf->dfun = NULL;
+
+       if (arrstkp)
+               evalidx(p);
+
+       /* allocate offsets */
+       if (class&FIELD) {
+               cerror("field2");  /* new entry */
+       } else switch (class) {
+
+       case REGISTER:
+               if (astr != NULL)
+                       werror("no register assignment (yet)");
+               p->sclass = class = AUTO;
+               /* FALLTHROUGH */
+       case AUTO:
+               if (isdyn(p)) {
+                       p->sflags |= SDYNARRAY;
+                       dynalloc(p, &autooff);
+               } else
+                       oalloc(p, &autooff);
+               break;
+
+       case PARAM:
+               if (q->n_type != FARG)
+                       oalloc(p, &argoff);
+               break;
+               
+       case STATIC:
+       case EXTDEF:
+       case EXTERN:
+               p->soffset = getlab();
+               /* FALLTHROUGH */
+       case USTATIC:
+               if (astr)
+                       addsoname(p, astr);
+               break;
+
+       case MOU:
+       case MOS:
+               cerror("field7");
+       case SNULL:
+#ifdef notdef
+               if (fun_inline) {
+                       p->slevel = 1;
+                       p->soffset = getlab();
+               }
+#endif
+               break;
+       }
+
+#ifdef STABS
+       if (gflag && p->stype != FARG)
+               stabs_newsym(p);
+#endif
+
+done:
+       fixdef(p);      /* Leave last word to target */
+#ifndef HAVE_WEAKREF
+       {
+               struct attr *at;
+
+               /* Refer renamed function */
+               if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF)))
+                       addsoname(p, at->sarg(0));
+       }
+#endif
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf( "       sdf, offset: %p, %d\n\t",
+                   p->sdf, p->soffset);
+#ifdef GCC_COMPAT
+               dump_attr(p->sap);
+#endif
+       }
+#endif
+}
+
+void
+ssave(struct symtab *sym)
+{
+       struct params *p;
+
+       p = tmpalloc(sizeof(struct params));
+       p->prev = lparam;
+       p->sym = sym;
+       lparam = p;
+}
+
+/*
+ * end of function
+ */
+void
+ftnend(void)
+{
+#ifdef GCC_COMPAT
+       struct attr *gc, *gd;
+#endif
+       extern int *mkclabs(void);
+       extern NODE *cftnod;
+       extern struct savbc *savbc;
+       extern struct swdef *swpole;
+       extern int tvaloff;
+       char *c;
+
+       if (retlab != NOLAB && nerrors == 0) { /* inside a real function */
+               plabel(retlab);
+               if (cftnod)
+                       ecomp(buildtree(FORCE, p1tcopy(cftnod), NIL));
+               efcode(); /* struct return handled here */
+               c = getexname(cftnsp);
+               SETOFF(maxautooff, ALCHAR);
+               send_passt(IP_EPILOG, maxautooff/SZCHAR, c,
+                   cftnsp->stype, cftnsp->sclass == EXTDEF,
+                   retlab, tvaloff, mkclabs());
+       }
+
+       cftnod = NIL;
+       tcheck();
+       brklab = contlab = retlab = NOLAB;
+       flostat = 0;
+       if (nerrors == 0) {
+               if (savbc != NULL)
+                       cerror("bcsave error");
+               if (lparam != NULL)
+                       cerror("parameter reset error");
+               if (swpole != NULL)
+                       cerror("switch error");
+       }
+#ifdef GCC_COMPAT
+       if (cftnsp) {
+               gc = attr_find(cftnsp->sap, GCC_ATYP_CONSTRUCTOR);
+               gd = attr_find(cftnsp->sap, GCC_ATYP_DESTRUCTOR);
+               if (gc || gd) {
+                       struct symtab sts = *cftnsp;
+                       NODE *p;
+                       sts.stype = INCREF(sts.stype);
+                       p = nametree(&sts);
+                       p->n_op = ICON;
+                       if (gc) {
+                               locctr(CTORS, NULL);
+                               inval(0, SZPOINT(0), p);
+                       }
+                       if (gd) {
+                               locctr(DTORS, NULL);
+                               inval(0, SZPOINT(0), p);
+                       }
+                       tfree(p);
+               }
+       }
+#endif
+       savbc = NULL;
+       lparam = NULL;
+       cftnsp = NULL;
+       maxautooff = autooff = AUTOINIT;
+       reached = 1;
+
+       if (isinlining)
+               inline_end();
+       inline_prtout();
+
+       tmpfree(); /* Release memory resources */
+}
+
+static struct symtab nulsym = {
+       NULL, 0, 0, 0, 0, "null", INT, 0, NULL, NULL
+};
+
+void
+dclargs(void)
+{
+       union dimfun *df;
+       union arglist *al;
+       struct params *a;
+       struct symtab *p, **parr = NULL; /* XXX gcc */
+       int i;
+
+       /*
+        * Deal with fun(void) properly.
+        */
+       if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID)
+               goto done;
+
+       /*
+        * Generate a list for bfcode().
+        * Parameters were pushed in reverse order.
+        */
+       if (nparams != 0)
+               parr = FUNALLO(sizeof(struct symtab *) * nparams);
+
+       if (nparams)
+           for (a = lparam, i = 0; a != NULL; a = a->prev) {
+               p = a->sym;
+               parr[i++] = p;
+               if (p == NULL) {
+                       uerror("parameter %d name missing", i);
+                       p = &nulsym; /* empty symtab */
+               }
+               if (p->stype == FARG)
+                       p->stype = INT;
+               if (ISARY(p->stype)) {
+                       p->stype += (PTR-ARY);
+                       p->sdf++;
+               } else if (ISFTN(p->stype)) {
+                       werror("function declared as argument");
+                       p->stype = INCREF(p->stype);
+               }
+#ifdef STABS
+               if (gflag)
+                       stabs_newsym(p);
+#endif
+       }
+       if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) {
+               /*
+                * Check against prototype of oldstyle function.
+                */
+               union arglist *al2, *alb;
+
+               alb = al2 = FUNALLO(sizeof(union arglist) * nparams * 3 + 1);
+               for (i = 0; i < nparams; i++) {
+                       TWORD type = parr[i]->stype;
+                       (al2++)->type = type;
+                       if (ISSOU(BTYPE(type)))
+                               (al2++)->sap = parr[i]->sap;
+                       while (!ISFTN(type) && !ISARY(type) && type > BTMASK)
+                               type = DECREF(type);
+                       if (type > BTMASK)
+                               (al2++)->df = parr[i]->sdf;
+               }
+               al2->type = TNULL;
+               intcompare = 1;
+               if (chkftn(al, alb))
+                       uerror("function doesn't match prototype");
+               FUNFREE(alb);
+               intcompare = 0;
+
+       }
+
+       if (oldstyle && nparams) {
+               /* Must recalculate offset for oldstyle args here */
+               argoff = ARGINIT;
+               for (i = 0; i < nparams; i++) {
+                       parr[i]->soffset = NOOFFSET;
+                       oalloc(parr[i], &argoff);
+               }
+       }
+
+done:  autooff = AUTOINIT;
+
+       plabel(prolab); /* after prolog, used in optimization */
+       retlab = getlab();
+       bfcode(parr, nparams);
+       if (fun_inline && (xinline
+#ifdef GCC_COMPAT
+ || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL)
+#endif
+               ))
+               inline_args(parr, nparams);
+       FUNFREE(parr);
+       plabel(getlab()); /* used when spilling */
+       if (parlink)
+               ecomp(parlink);
+       parlink = NIL;
+       lparam = NULL;
+       nparams = 0;
+       symclear(1);    /* In case of function pointer args */
+}
+
+/*
+ * basic attributes for structs and enums
+ */
+static struct attr *
+seattr(void)
+{
+       return attr_add(attr_new(ATTR_ALIGNED, 4), attr_new(ATTR_STRUCT, 2));
+}
+
+/*
+ * Struct/union/enum symtab construction.
+ */
+static void
+defstr(struct symtab *sp, int class)
+{
+       sp->sclass = (char)class;
+       if (class == STNAME)
+               sp->stype = STRTY;
+       else if (class == UNAME)
+               sp->stype = UNIONTY;
+       else if (class == ENAME)
+               sp->stype = ENUMTY;
+}
+
+/*
+ * Declare a struct/union/enum tag.
+ * If not found, create a new tag with UNDEF type.
+ */
+static struct symtab *
+deftag(char *name, int class)
+{
+       struct symtab *sp;
+
+       if ((sp = lookup(name, STAGNAME))->sap == NULL) {
+               /* New tag */
+               defstr(sp, class);
+       } else if (sp->sclass != class)
+               uerror("tag %s redeclared", name);
+       return sp;
+}
+
+/*
+ * reference to a structure or union, with no definition
+ */
+NODE *
+rstruct(char *tag, int soru)
+{
+       struct symtab *sp;
+
+       sp = deftag(tag, soru);
+       if (sp->sap == NULL)
+               sp->sap = seattr();
+       return mkty(sp->stype, 0, sp->sap);
+}
+
+static int enumlow, enumhigh;
+int enummer;
+
+/*
+ * Declare a member of enum.
+ */
+void
+moedef(char *name)
+{
+       struct symtab *sp;
+
+       sp = lookup(name, SNORMAL);
+       if (sp->stype == UNDEF || (sp->slevel < blevel)) {
+               if (sp->stype != UNDEF)
+                       sp = hide(sp);
+               sp->stype = INT; /* always */
+               sp->sclass = MOE;
+               sp->soffset = enummer;
+       } else
+               uerror("%s redeclared", name);
+       if (enummer < enumlow)
+               enumlow = enummer;
+       if (enummer > enumhigh)
+               enumhigh = enummer;
+       enummer++;
+}
+
+/*
+ * Declare an enum tag.  Complain if already defined.
+ */
+struct symtab *
+enumhd(char *name)
+{
+       struct attr *ap;
+       struct symtab *sp;
+
+       enummer = enumlow = enumhigh = 0;
+       if (name == NULL)
+               return NULL;
+
+       sp = deftag(name, ENAME);
+       if (sp->stype != ENUMTY) {
+               if (sp->slevel == blevel)
+                       uerror("%s redeclared", name);
+               sp = hide(sp);
+               defstr(sp, ENAME);
+       }
+       if (sp->sap == NULL)
+               ap = sp->sap = attr_new(ATTR_STRUCT, 4);
+       else
+               ap = attr_find(sp->sap, ATTR_STRUCT);
+       ap->amlist = sp;
+       return sp;
+}
+
+/*
+ * finish declaration of an enum
+ */
+NODE *
+enumdcl(struct symtab *sp)
+{
+       NODE *p;
+       TWORD t;
+
+#ifdef ENUMSIZE
+       t = ENUMSIZE(enumhigh, enumlow);
+#else
+       t = ctype(enumlow < 0 ? INT : UNSIGNED);
+#ifdef notdef
+       if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR)
+               t = ctype(CHAR);
+       else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT)
+               t = ctype(SHORT);
+       else
+               t = ctype(INT);
+#endif
+#endif
+       
+       if (sp)
+               sp->stype = t;
+       p = mkty(t, 0, 0);
+       p->n_sp = sp;
+       return p;
+}
+
+/*
+ * Handle reference to an enum
+ */
+NODE *
+enumref(char *name)
+{
+       struct symtab *sp;
+       NODE *p;
+
+       sp = lookup(name, STAGNAME);
+
+#ifdef notdef
+       /*
+        * 6.7.2.3 Clause 2:
+        * "A type specifier of the form 'enum identifier' without an
+        *  enumerator list shall only appear after the type it specifies
+        *  is complete."
+        */
+       if (sp->sclass != ENAME)
+               uerror("enum %s undeclared", name);
+#endif
+       if (sp->sclass == SNULL) {
+               /* declare existence of enum */
+               sp = enumhd(name);
+               sp->stype = ENUMTY;
+       }
+
+       p = mkty(sp->stype, 0, sp->sap);
+       p->n_sp = sp;
+       return p;
+}
+
+/*
+ * begining of structure or union declaration
+ * It's an error if this routine is called twice with the same struct.
+ */
+struct rstack *
+bstruct(char *name, int soru, NODE *gp)
+{
+       struct rstack *r;
+       struct symtab *sp;
+       struct attr *ap, *gap;
+
+#ifdef GCC_COMPAT
+       gap = gp ? gcc_attr_parse(gp) : NULL;
+#else
+       gap = NULL;
+#endif
+
+       if (name != NULL) {
+               sp = deftag(name, soru);
+               if (sp->sap == NULL)
+                       sp->sap = seattr();
+               ap = attr_find(sp->sap, ATTR_ALIGNED);
+               if (ap->iarg(0) != 0) {
+                       if (sp->slevel < blevel) {
+                               sp = hide(sp);
+                               defstr(sp, soru);
+                               sp->sap = seattr();
+                       } else
+                               uerror("%s redeclared", name);
+               }
+               gap = sp->sap = attr_add(sp->sap, gap);
+       } else {
+               gap = attr_add(seattr(), gap);
+               sp = NULL;
+       }
+
+       r = tmpcalloc(sizeof(struct rstack));
+       r->rsou = soru;
+       r->rsym = sp;
+       r->rb = NULL;
+       r->ap = gap;
+       r->rnext = rpole;
+       rpole = r;
+
+       return r;
+}
+
+/*
+ * Called after a struct is declared to restore the environment.
+ * - If ALSTRUCT is defined, this will be the struct alignment and the
+ *   struct size will be a multiple of ALSTRUCT, otherwise it will use
+ *   the alignment of the largest struct member.
+ */
+NODE *
+dclstruct(struct rstack *r)
+{
+       NODE *n;
+       struct attr *aps, *apb;
+       struct symtab *sp;
+       int al, sa, sz;
+
+       apb = attr_find(r->ap, ATTR_ALIGNED);
+       aps = attr_find(r->ap, ATTR_STRUCT);
+       aps->amlist = r->rb;
+
+#ifdef ALSTRUCT
+       al = ALSTRUCT;
+#else
+       al = ALCHAR;
+#endif
+
+       /*
+        * extract size and alignment, calculate offsets
+        */
+       for (sp = r->rb; sp; sp = sp->snext) {
+               sa = talign(sp->stype, sp->sap);
+               if (sp->sclass & FIELD)
+                       sz = sp->sclass&FLDSIZ;
+               else
+                       sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+               if (sz > rpole->rstr)
+                       rpole->rstr = sz;  /* for use with unions */
+               /*
+                * set al, the alignment, to the lcm of the alignments
+                * of the members.
+                */
+               SETOFF(al, sa);
+       }
+
+       SETOFF(rpole->rstr, al);
+
+       aps->amsize = rpole->rstr;
+       apb->iarg(0) = al;
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("dclstruct(%s): size=%d, align=%d\n",
+                   r->rsym ? r->rsym->sname : "??",
+                   aps->amsize, apb->iarg(0));
+       }
+       if (ddebug>1) {
+               printf("\tsize %d align %d link %p\n",
+                   aps->amsize, apb->iarg(0), aps->amlist);
+               for (sp = aps->amlist; sp != NULL; sp = sp->snext) {
+                       printf("\tmember %s(%p)\n", sp->sname, sp);
+               }
+       }
+#endif
+
+#ifdef STABS
+       if (gflag)
+               stabs_struct(r->rsym, r->ap);
+#endif
+
+       rpole = r->rnext;
+       n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap);
+       n->n_sp = r->rsym;
+
+       n->n_qual |= 1; /* definition place XXX used by attributes */
+       return n;
+}
+
+/*
+ * Add a new member to the current struct or union being declared.
+ */
+void
+soumemb(NODE *n, char *name, int class)
+{
+       struct symtab *sp, *lsp;
+       int incomp, tsz, al;
+       TWORD t;
+       if (rpole == NULL)
+               cerror("soumemb");
+       /* check if tag name exists */
+       lsp = NULL;
+       for (sp = rpole->rb; sp != NULL; lsp = sp, sp = sp->snext)
+               if (*name != '*' && sp->sname == name)
+                       uerror("redeclaration of %s", name);
+
+       sp = getsymtab(name, SMOSNAME);
+       if (rpole->rb == NULL)
+               rpole->rb = sp;
+       else
+               lsp->snext = sp;
+
+       n->n_sp = sp;
+       sp->stype = n->n_type;
+       sp->squal = n->n_qual;
+       sp->slevel = blevel;
+       sp->sap = n->n_ap;
+       sp->sdf = n->n_df;
+
+       if (class & FIELD) {
+               sp->sclass = (char)class;
+               if (rpole->rsou == UNAME)
+                       rpole->rstr = 0;
+               falloc(sp, class&FLDSIZ, NIL);
+       } else if (rpole->rsou == STNAME || rpole->rsou == UNAME) {
+               sp->sclass = rpole->rsou == STNAME ? MOS : MOU;
+               if (sp->sclass == MOU)
+                       rpole->rstr = 0;
+               al = talign(sp->stype, sp->sap);
+               tsz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+               sp->soffset = upoff(tsz, al, &rpole->rstr);
+       }
+
+       /*
+        * 6.7.2.1 clause 16:
+        * "...the last member of a structure with more than one
+        *  named member may have incomplete array type;"
+        */
+       if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+               incomp = 1;
+       else
+               incomp = 0;
+       if ((rpole->flags & LASTELM) || (rpole->rb == sp && incomp == 1))
+               uerror("incomplete array in struct");
+       if (incomp == 1)
+               rpole->flags |= LASTELM;
+
+       /*
+        * 6.7.2.1 clause 2:
+        * "...such a structure shall not be a member of a structure
+        *  or an element of an array."
+        */
+       t = sp->stype;
+       if (rpole->rsou != STNAME || BTYPE(t) != STRTY)
+               return; /* not for unions */
+       while (ISARY(t))
+               t = DECREF(t);
+       if (ISPTR(t))
+               return;
+
+       if ((lsp = strmemb(sp->sap)) != NULL) {
+               for (; lsp->snext; lsp = lsp->snext)
+                       ;
+               if (ISARY(lsp->stype) && lsp->snext &&
+                   lsp->sdf->ddim == NOOFFSET)
+                       uerror("incomplete struct in struct");
+       }
+}
+
+/*
+ * error printing routine in parser
+ */
+void
+yyerror(char *s)
+{
+       uerror(s);
+}
+
+void yyaccpt(void);
+void
+yyaccpt(void)
+{
+       ftnend();
+}
+
+/*
+ * p is top of type list given to tymerge later.
+ * Find correct CALL node and declare parameters from there.
+ */
+void
+ftnarg(NODE *p)
+{
+       NODE *q;
+
+#ifdef PCC_DEBUG
+       if (ddebug > 2)
+               printf("ftnarg(%p)\n", p);
+#endif
+       /*
+        * Push argument symtab entries onto param stack in reverse order,
+        * due to the nature of the stack it will be reclaimed correct.
+        */
+       for (; p->n_op != NAME; p = p->n_left) {
+               if (p->n_op == UCALL && p->n_left->n_op == NAME)
+                       return; /* Nothing to enter */
+               if (p->n_op == CALL && p->n_left->n_op == NAME)
+                       break;
+       }
+
+       p = p->n_right;
+       while (p->n_op == CM) {
+               q = p->n_right;
+               if (q->n_op != ELLIPSIS) {
+                       ssave(q->n_sp);
+                       nparams++;
+#ifdef PCC_DEBUG
+                       if (ddebug > 2)
+                               printf("        saving sym %s (%p) from (%p)\n",
+                                   q->n_sp->sname, q->n_sp, q);
+#endif
+               }
+               p = p->n_left;
+       }
+       ssave(p->n_sp);
+       if (p->n_type != VOID)
+               nparams++;
+
+#ifdef PCC_DEBUG
+       if (ddebug > 2)
+               printf("        saving sym %s (%p) from (%p)\n",
+                   nparams ? p->n_sp->sname : "<noname>", p->n_sp, p);
+#endif
+}
+
+/*
+ * compute the alignment of an object with type ty, sizeoff index s
+ */
+int
+talign(unsigned int ty, struct attr *apl)
+{
+       struct attr *al;
+       int a;
+
+       for (; ty > BTMASK; ty = DECREF(ty)) {
+               switch (ty & TMASK) {
+               case PTR:
+                       return(ALPOINT);
+               case ARY:
+                       continue;
+               case FTN:
+                       cerror("compiler takes alignment of function");
+               }
+       }
+
+       /* check for alignment attribute */
+       if ((al = attr_find(apl, ATTR_ALIGNED))) {
+               if ((a = al->iarg(0)) == 0) {
+                       uerror("no alignment");
+                       a = ALINT;
+               } 
+               return a;
+       }
+
+#ifndef NO_COMPLEX
+       if (ISITY(ty))
+               ty -= (FIMAG-FLOAT);
+#endif
+       ty = BTYPE(ty);
+       if (ty >= CHAR && ty <= ULONGLONG && ISUNSIGNED(ty))
+               ty = DEUNSIGN(ty);
+
+       switch (ty) {
+#ifdef GCC_COMPAT
+       case VOID: a = ALCHAR; break; /* GCC */
+#endif
+       case BOOL: a = ALBOOL; break;
+       case CHAR: a = ALCHAR; break;
+       case SHORT: a = ALSHORT; break;
+       case INT: a = ALINT; break;
+       case LONG: a = ALLONG; break;
+       case LONGLONG: a = ALLONGLONG; break;
+       case FLOAT: a = ALFLOAT; break;
+       case DOUBLE: a = ALDOUBLE; break;
+       case LDOUBLE: a = ALLDOUBLE; break;
+       default:
+               uerror("no alignment");
+               a = ALINT;
+       }
+       return a;
+}
+
+short sztable[] = { 0, SZBOOL, SZCHAR, SZCHAR, SZSHORT, SZSHORT, SZINT, SZINT,
+       SZLONG, SZLONG, SZLONGLONG, SZLONGLONG, SZFLOAT, SZDOUBLE, SZLDOUBLE };
+
+/* compute the size associated with type ty,
+ *  dimoff d, and sizoff s */
+/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */
+OFFSZ
+tsize(TWORD ty, union dimfun *d, struct attr *apl)
+{
+       struct attr *ap, *ap2;
+       OFFSZ mult, sz;
+
+       mult = 1;
+
+       for (; ty > BTMASK; ty = DECREF(ty)) {
+               switch (ty & TMASK) {
+
+               case FTN:
+                       uerror( "cannot take size of function");
+               case PTR:
+                       return( SZPOINT(ty) * mult );
+               case ARY:
+                       if (d->ddim == NOOFFSET)
+                               return 0;
+                       if (d->ddim < 0)
+                               cerror("tsize: dynarray");
+                       mult *= d->ddim;
+                       d++;
+               }
+       }
+
+#ifndef NO_COMPLEX
+       if (ISITY(ty))
+               ty -= (FIMAG-FLOAT);
+#endif
+
+       if (ty == VOID)
+               ty = CHAR;
+       if (ty <= LDOUBLE)
+               sz = sztable[ty];
+       else if (ISSOU(ty)) {
+               if ((ap = strattr(apl)) == NULL ||
+                   (ap2 = attr_find(apl, ATTR_ALIGNED)) == NULL ||
+                   (ap2->iarg(0) == 0)) {
+                       uerror("unknown structure/union/enum");
+                       sz = SZINT;
+               } else
+                       sz = ap->amsize;
+       } else {
+               uerror("unknown type");
+               sz = SZINT;
+       }
+
+       return((unsigned int)sz * mult);
+}
+
+#ifndef MYINSTRING
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+       unsigned short sh[2];
+       char *s, *str;
+       TWORD t;
+       NODE *p;
+
+       locctr(STRNG, sp);
+       defloc(sp);
+
+       t = BTYPE(sp->stype);
+       str = s = sp->sname;
+       if (t == ctype(USHORT)) {
+               /* convert to UTF-16 */
+               p = xbcon(0, NULL, t);
+               while (*s) {
+                       cp2u16(u82cp(&s), sh);
+                       if ((glval(p) = sh[0]))
+                               inval(0, SZSHORT, p);
+                       if ((glval(p) = sh[1]))
+                               inval(0, SZSHORT, p);
+               }
+               slval(p, 0);
+               inval(0, SZSHORT, p);
+               nfree(p);
+       } else if (t == ctype(SZINT < 32 ? ULONG : UNSIGNED) ||
+           t == ctype(SZINT < 32 ? LONG : INT)) {
+               /* convert to UTF-32 */
+               p = xbcon(0, NULL, t);
+               while (*s) {
+                       slval(p, u82cp(&s));
+                       inval(0, SZINT < 32 ? SZLONG : SZINT, p);
+               }
+               slval(p, 0);
+               inval(0, SZINT < 32 ? SZLONG : SZINT, p);
+               nfree(p);
+       } else if (t == CHAR || t == UCHAR) {
+               printf(PRTPREF "\t.ascii \"");
+               while (*s) {
+                       if (*s == '\\')
+                               (void)esccon(&s);
+                       else
+                               s++;
+       
+                       if (s - str > 60) {
+                               fwrite(str, 1, s - str, stdout);
+                               printf("\"\n" PRTPREF "\t.ascii \"");
+                               str = s;
+                       }
+               }
+
+               fwrite(str, 1, s - str, stdout);
+               printf("\\0\"\n");
+       } else
+               cerror("instring %ld", t);
+}
+#endif
+
+/*
+ * update the offset pointed to by poff; return the
+ * offset of a value of size `size', alignment `alignment',
+ * given that off is increasing
+ */
+int
+upoff(int size, int alignment, int *poff)
+{
+       int off;
+
+       off = *poff;
+       SETOFF(off, alignment);
+       if (off < 0)
+               cerror("structure or stack overgrown"); /* wrapped */
+       *poff = off+size;
+       return (off);
+}
+
+/*
+ * allocate p with offset *poff, and update *poff
+ */
+int
+oalloc(struct symtab *p, int *poff )
+{
+       int al, off, tsz;
+       int noff;
+
+       /*
+        * Only generate tempnodes if we are optimizing,
+        * and only for integers, floats or pointers,
+        * and not if the type on this level is volatile.
+        */
+       if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) &&
+           (p->stype < STRTY || ISPTR(p->stype)) &&
+           !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) {
+               NODE *tn = tempnode(0, p->stype, p->sdf, p->sap);
+               p->soffset = regno(tn);
+               p->sflags |= STNODE;
+               nfree(tn);
+               return 0;
+       }
+
+       al = talign(p->stype, p->sap);
+       noff = off = *poff;
+       tsz = (int)tsize(p->stype, p->sdf, p->sap);
+#ifdef BACKAUTO
+       if (p->sclass == AUTO) {
+               noff = off + tsz;
+               if (noff < 0)
+                       cerror("stack overflow");
+               SETOFF(noff, al);
+               off = -noff;
+       } else
+#endif
+       if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR ||
+           p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) {
+               off = upoff(SZINT, ALINT, &noff);
+#if TARGET_ENDIAN == TARGET_BE
+               off = noff - tsz;
+#endif
+       } else {
+               off = upoff(tsz, al, &noff);
+       }
+
+       if (p->sclass != REGISTER) {
+       /* in case we are allocating stack space for register arguments */
+               if (p->soffset == NOOFFSET)
+                       p->soffset = off;
+               else if(off != p->soffset)
+                       return(1);
+       }
+
+       *poff = noff;
+       return(0);
+}
+
+/*
+ * Delay emission of code generated in argument headers.
+ */
+static void
+edelay(NODE *p)
+{
+       if (blevel == 1) {
+               /* Delay until after declarations */
+               if (parlink == NULL)
+                       parlink = p;
+               else
+                       parlink = block(COMOP, parlink, p, 0, 0, 0);
+       } else
+               ecomp(p);
+}
+
+/*
+ * Traverse through the array args, evaluate them and put the 
+ * resulting temp numbers in the dim fields.
+ */
+static void
+evalidx(struct symtab *sp)
+{
+       union dimfun *df;
+       NODE *p;
+       TWORD t;
+       int astkp = 0;
+
+       if (arrstk[0] == NIL)
+               astkp++; /* for parameter arrays */
+
+       if (isdyn(sp))
+               sp->sflags |= SDYNARRAY;
+
+       df = sp->sdf;
+       for (t = sp->stype; t > BTMASK; t = DECREF(t)) {
+               if (!ISARY(t))
+                       continue;
+               if (df->ddim == -1) {
+                       p = tempnode(0, INT, 0, 0);
+                       df->ddim = -regno(p);
+                       edelay(buildtree(ASSIGN, p, arrstk[astkp++]));
+               }
+               df++;
+       }
+       arrstkp = 0;
+}
+
+/*
+ * Return 1 if dynamic array, 0 otherwise.
+ */
+int
+isdyn(struct symtab *sp)
+{
+       union dimfun *df = sp->sdf;
+       TWORD t;
+
+       for (t = sp->stype; t > BTMASK; t = DECREF(t)) {
+               if (!ISARY(t))
+                       return 0;
+               if (df->ddim < 0 && df->ddim != NOOFFSET)
+                       return 1;
+               df++;
+       }
+       return 0;
+}
+
+/*
+ * Allocate space on the stack for dynamic arrays (or at least keep track
+ * of the index).
+ * Strategy is as follows:
+ * - first entry is a pointer to the dynamic datatype.
+ * - if it's a one-dimensional array this will be the only entry used.
+ * - if it's a multi-dimensional array the following (numdim-1) integers
+ *   will contain the sizes to multiply the indexes with.
+ * - code to write the dimension sizes this will be generated here.
+ * - code to allocate space on the stack will be generated here.
+ */
+static void
+dynalloc(struct symtab *p, int *poff)
+{
+       union dimfun *df;
+       NODE *n, *tn, *pol;
+       TWORD t;
+
+       /*
+        * The pointer to the array is not necessarily stored in a
+        * TEMP node, but if it is, its number is in the soffset field;
+        */
+       t = p->stype;
+       p->sflags |= STNODE;
+       p->stype = INCREF(p->stype); /* Make this an indirect pointer */
+       tn = tempnode(0, p->stype, p->sdf, p->sap);
+       p->soffset = regno(tn);
+
+       df = p->sdf;
+
+       pol = bcon(1);
+       for (; t > BTMASK; t = DECREF(t)) {
+               if (!ISARY(t))
+                       break;
+               if (df->ddim < 0)
+                       n = tempnode(-df->ddim, INT, 0, 0);
+               else
+                       n = bcon(df->ddim);
+
+               pol = buildtree(MUL, pol, n);
+               df++;
+       }
+       /* Create stack gap */
+       spalloc(tn, pol, tsize(t, 0, p->sap));
+}
+
+/*
+ * allocate a field of width w
+ * new is 0 if new entry, 1 if redefinition, -1 if alignment
+ */
+int
+falloc(struct symtab *p, int w, NODE *pty)
+{
+       TWORD otype, type;
+       int al,sz;
+
+       otype = type = p ? p->stype : pty->n_type;
+
+       if (type == BOOL)
+               type = BOOL_TYPE;
+       if (!ISINTEGER(type)) {
+               uerror("illegal field type");
+               type = INT;
+       }
+
+       al = talign(type, NULL);
+       sz = tsize(type, NULL, NULL);
+
+       if (w > sz) {
+               uerror("field too big");
+               w = sz;
+       }
+
+       if (w == 0) { /* align only */
+               SETOFF(rpole->rstr, al);
+               if (p != NULL)
+                       uerror("zero size field");
+               return(0);
+       }
+
+       if (rpole->rstr%al + w > sz)
+               SETOFF(rpole->rstr, al);
+       if (p == NULL) {
+               rpole->rstr += w;  /* we know it will fit */
+               return(0);
+       }
+
+       /* establish the field */
+
+       p->soffset = rpole->rstr;
+       rpole->rstr += w;
+       p->stype = otype;
+       fldty(p);
+       return(0);
+}
+
+/*
+ * Check if this symbol should be a common or must be handled in data seg.
+ */
+static void
+commchk(struct symtab *sp)
+{
+       if ((sp->sflags & STLS)
+#ifdef GCC_COMPAT
+               || attr_find(sp->sap, GCC_ATYP_SECTION)
+#endif
+           ) {
+               /* TLS handled in data segment */
+               if (sp->sclass == EXTERN)
+                       sp->sclass = EXTDEF;
+               beginit(sp);
+               endinit(1);
+       } else {
+               symdirec(sp);
+               defzero(sp);
+       }
+}
+
+void
+nidcl(NODE *p, int class)
+{
+       nidcl2(p, class, 0);
+}
+
+/*
+ * handle unitialized declarations assumed to be not functions:
+ * int a;
+ * extern int a;
+ * static int a;
+ */
+void
+nidcl2(NODE *p, int class, char *astr)
+{
+       struct symtab *sp;
+       int commflag = 0;
+
+       /* compute class */
+       if (class == SNULL) {
+               if (blevel > 1)
+                       class = AUTO;
+               else if (blevel != 0 || rpole)
+                       cerror( "nidcl error" );
+               else /* blevel = 0 */
+                       commflag = 1, class = EXTERN;
+       }
+
+       defid2(p, class, astr);
+
+       sp = p->n_sp;
+       /* check if forward decl */
+       if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+               return;
+
+       if (sp->sflags & SASG)
+               return; /* already initialized */
+
+       switch (class) {
+       case EXTDEF:
+               /* simulate initialization by 0 */
+               simpleinit(p->n_sp, bcon(0));
+               break;
+       case EXTERN:
+               if (commflag)
+                       lcommadd(p->n_sp);
+               else
+                       extdec(p->n_sp);
+               break;
+       case STATIC:
+               if (blevel == 0)
+                       lcommadd(p->n_sp);
+               else
+                       commchk(p->n_sp);
+               break;
+       }
+}
+
+struct lcd {
+       SLIST_ENTRY(lcd) next;
+       struct symtab *sp;
+};
+
+static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw};
+
+/*
+ * Add a local common statement to the printout list.
+ */
+void
+lcommadd(struct symtab *sp)
+{
+       struct lcd *lc, *lcp;
+
+       lcp = NULL;
+       SLIST_FOREACH(lc, &lhead, next) {
+               if (lc->sp == sp)
+                       return; /* already exists */
+               if (lc->sp == NULL && lcp == NULL)
+                       lcp = lc;
+       }
+       if (lcp == NULL) {
+               lc = permalloc(sizeof(struct lcd));
+               lcommsz += sizeof(struct lcd);
+               lc->sp = sp;
+               SLIST_INSERT_LAST(&lhead, lc, next);
+       } else
+               lcp->sp = sp;
+}
+
+/*
+ * Delete a local common statement.
+ */
+void
+lcommdel(struct symtab *sp)
+{
+       struct lcd *lc;
+
+       SLIST_FOREACH(lc, &lhead, next) {
+               if (lc->sp == sp) {
+                       lc->sp = NULL;
+                       return;
+               }
+       }
+}
+
+/*
+ * Print out the remaining common statements.
+ */
+void
+lcommprint(void)
+{
+       struct lcd *lc;
+
+       SLIST_FOREACH(lc, &lhead, next) {
+               if (lc->sp != NULL)
+                       commchk(lc->sp);
+       }
+}
+
+/*
+ * Merge given types to a single node.
+ * Any type can end up here.
+ * p is the old node, q is the old (if any).
+ * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF.
+ * QUALIFIER is VOL or CON
+ * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT,
+ *     DOUBLE, STRTY, UNIONTY.
+ */
+struct typctx {
+       int class, qual, sig, uns, cmplx, imag, err, align;
+       TWORD type;
+       NODE *saved;
+       struct attr *pre, *post;
+};
+
+static void
+typwalk(NODE *p, void *arg)
+{
+       struct typctx *tc = arg;
+
+#define        cmop(x,y) block(CM, x, y, INT, 0, 0)
+       switch (p->n_op) {
+       case ALIGN:
+               if (tc->align < glval(p))
+                       tc->align = glval(p);
+                break;
+       case ATTRIB:
+#ifdef GCC_COMPAT
+               if (tc->saved && (tc->saved->n_qual & 1)) {
+                       tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left));
+               } else {
+                       tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left));
+               }
+               p->n_left = bcon(0); /* For tfree() */
+#else
+               uerror("gcc type attribute used");
+#endif
+               break;
+       case CLASS:
+               if (p->n_type == 0)
+                       break;  /* inline hack */
+               if (tc->class)
+                       tc->err = 1; /* max 1 class */
+               tc->class = p->n_type;
+               break;
+
+       case FUNSPEC:
+               if (p->n_type == INLINE) {
+                       fun_inline = 1;
+               } else if (p->n_type == NORETURN) {
+                       tc->pre = attr_add(tc->pre, attr_new(ATTR_NORETURN, 3));
+               } else
+                       tc->err = 1;
+               break;
+
+       case QUALIFIER:
+               if (p->n_qual == 0 && 
+                   ((tc->saved && !ISPTR(tc->saved->n_type)) ||
+                   (tc->saved == 0)))
+                       uerror("invalid use of 'restrict'");
+               tc->qual |= p->n_qual >> TSHIFT;
+               break;
+
+       case TYPE:
+               if (p->n_sp != NULL || ISSOU(p->n_type)) {
+                       /* typedef, enum or struct/union */
+                       if (tc->saved || tc->type)
+                               tc->err = 1;
+#ifdef GCC_COMPAT
+                       if (ISSOU(p->n_type) && p->n_left) {
+                               if (tc->post)
+                                       cerror("typwalk");
+                               tc->post = gcc_attr_parse(p->n_left);
+                       }
+#endif
+                       tc->saved = ccopy(p);
+                       break;
+               }
+
+               switch (p->n_type) {
+               case BOOL:
+               case CHAR:
+               case FLOAT:
+               case VOID:
+                       if (tc->type)
+                               tc->err = 1;
+                       tc->type = p->n_type;
+                       break;
+               case DOUBLE:
+                       if (tc->type == 0)
+                               tc->type = DOUBLE;
+                       else if (tc->type == LONG)
+                               tc->type = LDOUBLE;
+                       else
+                               tc->err = 1;
+                       break;
+               case SHORT:
+                       if (tc->type == 0 || tc->type == INT)
+                               tc->type = SHORT;
+                       else
+                               tc->err = 1;
+                       break;
+               case INT:
+                       if (tc->type == SHORT || tc->type == LONG ||
+                           tc->type == LONGLONG)
+                               break;
+                       else if (tc->type == 0)
+                               tc->type = INT;
+                       else
+                               tc->err = 1;
+                       break;
+               case LONG:
+                       if (tc->type == 0)
+                               tc->type = LONG;
+                       else if (tc->type == INT)
+                               break;
+                       else if (tc->type == LONG)
+                               tc->type = LONGLONG;
+                       else if (tc->type == DOUBLE)
+                               tc->type = LDOUBLE;
+                       else
+                               tc->err = 1;
+                       break;
+               case SIGNED:
+                       if (tc->sig || tc->uns)
+                               tc->err = 1;
+                       tc->sig = 1;
+                       break;
+               case UNSIGNED:
+                       if (tc->sig || tc->uns)
+                               tc->err = 1;
+                       tc->uns = 1;
+                       break;
+               case COMPLEX:
+                       tc->cmplx = 1;
+                       break;
+               case IMAG:
+                       tc->imag = 1;
+                       break;
+               default:
+                       cerror("typwalk");
+               }
+       }
+
+}
+
+NODE *
+typenode(NODE *p)
+{
+       struct attr *ap;
+       struct symtab *sp;
+       struct typctx tc;
+       NODE *q;
+       char *c;
+
+       memset(&tc, 0, sizeof(struct typctx));
+
+       flist(p, typwalk, &tc);
+       tfree(p);
+
+       if (tc.err)
+               goto bad;
+
+       if (tc.cmplx || tc.imag) {
+               if (tc.type == 0)
+                       tc.type = DOUBLE;
+               if ((tc.cmplx && tc.imag) || tc.sig || tc.uns ||
+                   !ISFTY(tc.type))
+                       goto bad;
+               if (tc.cmplx) {
+                       c = tc.type == DOUBLE ? "0d" :
+                           tc.type == FLOAT ? "0f" : "0l";
+                       sp = lookup(addname(c), 0);
+                       tc.type = STRTY;
+                       tc.saved = mkty(tc.type, sp->sdf, sp->sap);
+                       tc.saved->n_sp = sp;
+                       tc.type = 0;
+               } else
+                       tc.type += (FIMAG-FLOAT);
+       }
+
+       if (tc.saved && tc.type)
+               goto bad;
+       if (tc.sig || tc.uns) {
+               if (tc.type == 0)
+                       tc.type = tc.sig ? INT : UNSIGNED;
+               if (tc.type > ULONGLONG)
+                       goto bad;
+               if (tc.uns)
+                       tc.type = ENUNSIGN(tc.type);
+       }
+
+       if (xuchar && tc.type == CHAR && tc.sig == 0)
+               tc.type = UCHAR;
+
+#ifdef GCC_COMPAT
+       if (pragma_packed) {
+               q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed));
+               tc.post = attr_add(tc.post, gcc_attr_parse(q));
+       }
+       if (pragma_aligned) {
+               /* Deal with relevant pragmas */
+               if (tc.align < pragma_aligned)
+                       tc.align = pragma_aligned;
+       }
+       pragma_aligned = pragma_packed = 0;
+#endif
+       if ((q = tc.saved) == NULL) {
+               TWORD t;
+               if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID &&
+                   t != BOOL && !(t >= FIMAG && t <= LIMAG))
+                       cerror("typenode2 t %x", tc.type);
+               if (t == UNDEF) {
+                       t = INT;
+                       MODTYPE(tc.type, INT);
+               }
+               q =  mkty(tc.type, 0, 0);
+       }
+       q->n_ap = attr_add(q->n_ap, tc.post);
+       q->n_qual = tc.qual;
+       slval(q, tc.class);
+#ifdef GCC_COMPAT
+       if (tc.post) {
+               /* Can only occur for TYPEDEF, STRUCT or UNION */
+               if (tc.saved == NULL)
+                       cerror("typenode");
+               if (tc.saved->n_sp) /* trailer attributes for structs */
+                       tc.saved->n_sp->sap = q->n_ap;
+       }
+       if (tc.pre)
+               q->n_ap = attr_add(q->n_ap, tc.pre);
+       gcc_tcattrfix(q);
+#endif
+
+       if (tc.align && (ap = attr_find(q->n_ap, ATTR_ALIGNED)) &&
+           ap->iarg(0) && tc.align > talign(q->n_type, q->n_ap)/SZCHAR) {
+               q->n_ap = attr_add(q->n_ap, attr_new(ATTR_ALIGNED, 1));
+               q->n_ap->aa[0].iarg = SZCHAR * tc.align;
+       }
+
+       return q;
+
+bad:   uerror("illegal type combination");
+       return mkty(INT, 0, 0);
+}
+
+struct tylnk {
+       struct tylnk *next;
+       union dimfun df;
+};
+
+/*
+ * Retrieve all CM-separated argument types, sizes and dimensions and
+ * put them in an array.
+ * XXX - can only check first type level, side effects?
+ */
+static union arglist *
+arglist(NODE *n)
+{
+       union arglist *al;
+       NODE *w = n, **ap;
+       int num, cnt, i, j, k;
+       TWORD ty;
+
+#ifdef PCC_DEBUG
+       if (pdebug) {
+               printf("arglist %p\n", n);
+               fwalk(n, eprint, 0);
+       }
+#endif
+       /* First: how much to allocate */
+       for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) {
+               cnt++;  /* Number of levels */
+               num++;  /* At least one per step */
+               if (w->n_right->n_op == ELLIPSIS)
+                       continue;
+               ty = w->n_right->n_type;
+               if (ty == ENUMTY) {
+                       uerror("arg %d enum undeclared", cnt);
+                       ty = w->n_right->n_type = INT;
+               }
+               if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+                       num++;
+               while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK)
+                       ty = DECREF(ty);
+               if (ty > BTMASK)
+                       num++;
+       }
+       cnt++;
+       ty = w->n_type;
+       if (ty == ENUMTY) {
+               uerror("arg %d enum undeclared", cnt);
+               ty = w->n_type = INT;
+       }
+       if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+               num++;
+       while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK)
+               ty = DECREF(ty);
+       if (ty > BTMASK)
+               num++;
+       num += 2; /* TEND + last arg type */
+
+       /* Second: Create list to work on */
+       ap = FUNALLO(sizeof(NODE *) * cnt);
+       al = permalloc(sizeof(union arglist) * num);
+       arglistcnt += num;
+
+       for (w = n, i = 0; w->n_op == CM; w = w->n_left)
+               ap[i++] = w->n_right;
+       ap[i] = w;
+
+       /* Third: Create actual arg list */
+       for (k = 0, j = i; j >= 0; j--) {
+               if (ap[j]->n_op == ELLIPSIS) {
+                       al[k++].type = TELLIPSIS;
+                       ap[j]->n_op = ICON; /* for tfree() */
+                       continue;
+               }
+               /* Convert arrays to pointers */
+               if (ISARY(ap[j]->n_type)) {
+                       ap[j]->n_type += (PTR-ARY);
+                       ap[j]->n_df++;
+               }
+               /* Convert (silently) functions to pointers */
+               if (ISFTN(ap[j]->n_type))
+                       ap[j]->n_type = INCREF(ap[j]->n_type);
+               ty = ap[j]->n_type;
+#ifdef GCC_COMPAT
+               if (ty == UNIONTY &&
+                   attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){
+                       /* transparent unions must have compatible types
+                        * shortcut here: if pointers, set void *, 
+                        * otherwise btype.
+                        */
+                       struct symtab *sp = strmemb(ap[j]->n_ap);
+                       ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype;
+               }
+#endif
+               al[k++].type = ty;
+               if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+                       al[k++].sap = ap[j]->n_ap;
+               while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK)
+                       ty = DECREF(ty);
+               if (ty > BTMASK)
+                       al[k++].df = ap[j]->n_df;
+       }
+       al[k++].type = TNULL;
+       if (k > num)
+               cerror("arglist: k%d > num%d", k, num);
+       tfree(n);
+       FUNFREE(ap);
+#ifdef PCC_DEBUG
+       if (pdebug)
+               alprint(al, 0);
+#endif
+       return al;
+}
+
+static void
+tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim)
+{
+       (*tylkp)->next = tmpalloc(sizeof(struct tylnk));
+       *tylkp = (*tylkp)->next;
+       (*tylkp)->next = NULL;
+       (*tylkp)->df = dim;
+       (*ntdim)++;
+}
+
+/*
+ * build a type, and stash away dimensions,
+ * from a parse tree of the declaration
+ * the type is build top down, the dimensions bottom up
+ */
+static void
+tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim)
+{
+       union dimfun dim;
+       NODE *r = NULL;
+       int o;
+       TWORD t, q;
+
+       o = p->n_op;
+       if (o == NAME) {
+               p->n_qual = DECQAL(p->n_qual);
+               return;
+       }
+
+       t = INCREF(p->n_type);
+       q = p->n_qual;
+       switch (o) {
+       case CALL:
+               t += (FTN-PTR);
+               dim.dfun = arglist(p->n_right);
+               break;
+       case UCALL:
+               t += (FTN-PTR);
+               dim.dfun = NULL;
+               break;
+       case LB:
+               t += (ARY-PTR);
+               if (p->n_right->n_op != ICON) {
+                       r = p->n_right;
+                       o = RB;
+               } else {
+                       dim.ddim = (int)glval(p->n_right);
+                       nfree(p->n_right);
+#ifdef notdef
+       /* XXX - check dimensions at usage time */
+                       if (dim.ddim == NOOFFSET && p->n_left->n_op == LB)
+                               uerror("null dimension");
+#endif
+               }
+               break;
+       }
+
+       p->n_left->n_type = t;
+       p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual;
+       tyreduce(p->n_left, tylkp, ntdim);
+
+       if (o == LB || o == UCALL || o == CALL)
+               tylkadd(dim, tylkp, ntdim);
+       if (o == RB) {
+               dim.ddim = -1;
+               tylkadd(dim, tylkp, ntdim);
+               arrstk[arrstkp++] = r;
+       }
+
+       p->n_sp = p->n_left->n_sp;
+       p->n_type = p->n_left->n_type;
+       p->n_qual = p->n_left->n_qual;
+}
+
+/*
+ * merge type typ with identifier idp.
+ * idp is returned as a NAME node with correct types,
+ * typ is untouched since multiple declarations uses it.
+ * typ has type attributes, idp can never carry such attributes
+ * so on return just a pointer to the typ attributes is returned.
+ */
+NODE *
+tymerge(NODE *typ, NODE *idp)
+{
+       TWORD t;
+       NODE *p;
+       union dimfun *j;
+       struct tylnk *base, tylnk, *tylkp;
+       struct attr *bap;
+       int ntdim, i;
+
+#ifdef PCC_DEBUG
+       if (ddebug > 2) {
+               printf("tymerge(%p,%p)\n", typ, idp);
+               fwalk(typ, eprint, 0);
+               fwalk(idp, eprint, 0);
+       }
+#endif
+
+       if (typ->n_op != TYPE)
+               cerror("tymerge: arg 1");
+
+       bap = typ->n_ap;
+
+       idp->n_type = typ->n_type;
+       idp->n_qual |= typ->n_qual;
+
+       tylkp = &tylnk;
+       tylkp->next = NULL;
+       ntdim = 0;
+
+       tyreduce(idp, &tylkp, &ntdim);
+
+       for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t))
+               if (ISARY(t) || ISFTN(t))
+                       tylkadd(*j++, &tylkp, &ntdim);
+
+       if (ntdim) {
+               union dimfun *a = permalloc(sizeof(union dimfun) * ntdim);
+               dimfuncnt += ntdim;
+               for (i = 0, base = tylnk.next; base; base = base->next, i++)
+                       a[i] = base->df;
+               idp->n_df = a;
+       } else
+               idp->n_df = NULL;
+
+       /* now idp is a single node: fix up type */
+       if ((t = ctype(idp->n_type)) != idp->n_type)
+               idp->n_type = t;
+       
+       if (idp->n_op != NAME) {
+               for (p = idp->n_left; p->n_op != NAME; p = nfree(p))
+                       ;
+               nfree(p);
+               idp->n_op = NAME;
+       }
+       /* carefully not destroy any type attributes */
+       if (idp->n_ap != NULL) {
+               struct attr *ap = idp->n_ap;
+               while (ap->next)
+                       ap = ap->next;
+               ap->next = bap;
+       } else
+               idp->n_ap = bap;
+
+       return(idp);
+}
+
+static NODE *
+argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap)
+{
+       NODE *u, *r = p1alloc();
+
+       r->n_op = NAME;
+       r->n_type = t;
+       r->n_qual = 0; /* XXX */
+       r->n_df = d;
+       r->n_ap = ap;
+
+       u = buildtree(CAST, r, p);
+       nfree(u->n_left);
+       r = u->n_right;
+       nfree(u);
+       return r;
+}
+
+#ifdef PCC_DEBUG
+/*
+ * Print a prototype.
+ */
+static void
+alprint(union arglist *al, int in)
+{
+       TWORD t;
+       int i = 0, j;
+
+       for (; al->type != TNULL; al++) {
+               for (j = in; j > 0; j--)
+                       printf("  ");
+               printf("arg %d: ", i++);
+               t = al->type;
+               tprint(t, 0);
+               while (t > BTMASK) {
+                       if (ISARY(t)) {
+                               al++;
+                               printf(" dim %d ", al->df->ddim);
+                       } else if (ISFTN(t)) {
+                               al++;
+                               if (al->df->dfun) {
+                                       printf("\n");
+                                       alprint(al->df->dfun, in+1);
+                               }
+                       }
+                       t = DECREF(t);
+               }
+               if (ISSOU(t)) {
+                       al++;
+                       printf(" (size %d align %d)", (int)tsize(t, 0, al->sap),
+                           (int)talign(t, al->sap));
+               }
+               printf("\n");
+       }
+       if (in == 0)
+               printf("end arglist\n");
+}
+#endif
+
+int
+suemeq(struct attr *s1, struct attr *s2)
+{
+
+       return (strmemb(s1) == strmemb(s2));
+}
+
+/*
+ * Sanity-check old-style args.
+ */
+static NODE *
+oldarg(NODE *p)
+{
+       if (p->n_op == TYPE)
+               uerror("type is not an argument");
+       if (p->n_type == FLOAT)
+               return cast(p, DOUBLE, p->n_qual);
+       return p;
+}
+
+/*
+ * Do prototype checking and add conversions before calling a function.
+ * Argument f is function and a is a CM-separated list of arguments.
+ * Returns a merged node (via buildtree() of function and arguments.
+ */
+NODE *
+doacall(struct symtab *sp, NODE *f, NODE *a)
+{
+       NODE *w, *r;
+       union arglist *al;
+       struct ap {
+               struct ap *next;
+               NODE *node;
+       } *at, *apole = NULL, *apary = NULL;
+       int i, argidx/* , hasarray = 0*/;
+       TWORD type, arrt;
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("doacall.\n");
+               fwalk(f, eprint, 0);
+               if (a)
+                       fwalk(a, eprint, 0);
+       }
+#endif
+
+       /* First let MD code do something */
+       calldec(f, a);
+/* XXX XXX hack */
+       if ((f->n_op == CALL) &&
+           f->n_left->n_op == ADDROF &&
+           f->n_left->n_left->n_op == NAME &&
+           (f->n_left->n_left->n_type & 0x7e0) == 0x4c0)
+               goto build;
+/* XXX XXX hack */
+
+       /* Check for undefined or late defined enums */
+       if (BTYPE(f->n_type) == ENUMTY) {
+               /* not-yet check if declared enum */
+               struct symtab *sq = strmemb(f->n_ap);
+               if (sq->stype != ENUMTY)
+                       MODTYPE(f->n_type, sq->stype);
+               if (BTYPE(f->n_type) == ENUMTY)
+                       uerror("enum %s not declared", sq->sname);
+       }
+
+       /*
+        * Do some basic checks.
+        */
+       if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) {
+               /*
+                * Handle non-prototype declarations.
+                */
+               if (f->n_op == NAME && f->n_sp != NULL) {
+                       if (strncmp(f->n_sp->sname, "__builtin", 9) != 0 &&
+                           (f->n_sp->sflags & SINSYS) == 0)
+                               warner(Wmissing_prototypes, f->n_sp->sname);
+               } else
+                       warner(Wmissing_prototypes, "<pointer>");
+
+               /* floats must be cast to double */
+               if (a == NULL)
+                       goto build;
+               if (a->n_op != CM) {
+                       a = oldarg(a);
+               } else {
+                       for (w = a; w->n_left->n_op == CM; w = w->n_left)
+                               w->n_right = oldarg(w->n_right);
+                       w->n_left = oldarg(w->n_left);
+                       w->n_right = oldarg(w->n_right);
+               }
+               goto build;
+       }
+       if (al->type == VOID) {
+               if (a != NULL)
+                       uerror("function takes no arguments");
+               goto build; /* void function */
+       } else {
+               if (a == NULL) {
+                       uerror("function needs arguments");
+                       goto build;
+               }
+       }
+#ifdef PCC_DEBUG
+       if (pdebug) {
+               printf("arglist for %s\n",
+                   f->n_sp != NULL ? f->n_sp->sname : "function pointer");
+               alprint(al, 0);
+       }
+#endif
+
+       /*
+        * Create a list of pointers to the nodes given as arg.
+        */
+       for (w = a, i = 1; w->n_op == CM; w = w->n_left)
+               i++;
+       apary = FUNALLO(sizeof(struct ap) * i);
+
+       for (w = a, i = 0; w->n_op == CM; w = w->n_left) {
+               at = &apary[i++];
+               at->node = w->n_right;
+               at->next = apole;
+               apole = at;
+       }
+       at = &apary[i];
+       at->node = w;
+       at->next = apole;
+       apole = at;
+
+       /*
+        * Do the typechecking by walking up the list.
+        */
+       argidx = 1;
+       while (al->type != TNULL) {
+               if (al->type == TELLIPSIS) {
+                       /* convert the rest of float to double */
+                       for (; apole; apole = apole->next) {
+                               if (apole->node->n_type != FLOAT)
+                                       continue;
+                               MKTY(apole->node, DOUBLE, 0, 0);
+                       }
+                       goto build;
+               }
+               if (apole == NULL) {
+                       uerror("too few arguments to function");
+                       goto build;
+               }
+/* al = prototyp, apole = argument till ftn */
+/* type = argumentets typ, arrt = prototypens typ */
+               type = apole->node->n_type;
+               arrt = al->type;
+#if 0
+               if ((hasarray = ISARY(arrt)))
+                       arrt += (PTR-ARY);
+#endif
+               /* Taking addresses of arrays are meaningless in expressions */
+               /* but people tend to do that and also use in prototypes */
+               /* this is mostly a problem with typedefs */
+               if (ISARY(type)) {
+                       if (ISPTR(arrt) && ISARY(DECREF(arrt)))
+                               type = INCREF(type);
+                       else
+                               type += (PTR-ARY);
+               } else if (ISPTR(type) && !ISARY(DECREF(type)) &&
+                   ISPTR(arrt) && ISARY(DECREF(arrt))) {
+                       type += (ARY-PTR);
+                       type = INCREF(type);
+               }
+
+               /* Check structs */
+               if (type <= BTMASK && arrt <= BTMASK) {
+#ifndef NO_COMPLEX
+                       if ((type != arrt) && (ANYCX(apole->node) ||
+                           (arrt == STRTY &&
+                           attr_find(al[1].sap, ATTR_COMPLEX)))) {
+                               cxargfixup(apole->node, arrt, al[1].sap);
+                       } else
+#endif
+                       if (type != arrt) {
+                               if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) {
+incomp:                                        uerror("incompatible types for arg %d",
+                                           argidx);
+                               } else {
+                                       MKTY(apole->node, arrt, 0, 0)
+                               }
+#ifndef NO_COMPLEX
+                       } else if (type == STRTY &&
+                           attr_find(apole->node->n_ap, ATTR_COMPLEX) &&
+                           attr_find(al[1].sap, ATTR_COMPLEX)) {
+                               /* Both are complex */
+                               if (strmemb(apole->node->n_ap)->stype !=
+                                   strmemb(al[1].sap)->stype) {
+                                       /* must convert to correct type */
+                                       w = p1alloc();
+                                       *w = *apole->node;
+                                       w = mkcmplx(w,
+                                           strmemb(al[1].sap)->stype);
+                                       *apole->node = *w;
+                                       nfree(w);
+                               }
+                               goto out;
+#endif
+                       } else if (ISSOU(BTYPE(type))) {
+                               if (!suemeq(apole->node->n_ap, al[1].sap))
+                                       goto incomp;
+                       }
+                       goto out;
+               }
+
+               /* XXX should (recusively) check return type and arg list of
+                  func ptr arg XXX */
+               if (ISFTN(DECREF(arrt)) && ISFTN(type))
+                       type = INCREF(type);
+
+               /* Hereafter its only pointers (or arrays) left */
+               /* Check for struct/union intermixing with other types */
+               if (((type <= BTMASK) && ISSOU(BTYPE(type))) ||
+                   ((arrt <= BTMASK) && ISSOU(BTYPE(arrt))))
+                       goto incomp;
+
+               /* Check for struct/union compatibility */
+               if (type == arrt) {
+                       if (ISSOU(BTYPE(type))) {
+                               if (suemeq(apole->node->n_ap, al[1].sap))
+                                       goto out;
+                       } else
+                               goto out;
+               }
+               if (BTYPE(arrt) == VOID && type > BTMASK)
+                       goto skip; /* void *f = some pointer */
+               if (arrt > BTMASK && BTYPE(type) == VOID)
+                       goto skip; /* some *f = void pointer */
+               if (apole->node->n_op == ICON && glval(apole->node) == 0)
+                       goto skip; /* Anything assigned a zero */
+
+               if ((type & ~BTMASK) == (arrt & ~BTMASK)) {
+                       /* do not complain for pointers with signedness */
+                       if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) &&
+                           (BTYPE(type) != BTYPE(arrt))) {
+                               warner(Wpointer_sign);
+                               goto skip;
+                       }
+               }
+
+               werror("implicit conversion of argument %d due to prototype",
+                   argidx);
+
+skip:          if (ISSOU(BTYPE(arrt))) {
+                       MKTY(apole->node, arrt, 0, al[1].sap)
+               } else {
+                       MKTY(apole->node, arrt, 0, 0)
+               }
+
+out:           al++;
+               if (ISSOU(BTYPE(arrt)))
+                       al++;
+#if 0
+               while (arrt > BTMASK && !ISFTN(arrt))
+                       arrt = DECREF(arrt);
+               if (ISFTN(arrt) || hasarray)
+                       al++;
+#else
+               while (arrt > BTMASK) {
+                       if (ISARY(arrt) || ISFTN(arrt)) {
+                               al++;
+                               break;
+                       }
+                       arrt = DECREF(arrt);
+               }
+#endif
+               apole = apole->next;
+               argidx++;
+       }
+       if (apole != NULL)
+               uerror("too many arguments to function");
+
+build: if (apary)
+               FUNFREE(apary);
+       if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a)))
+               return w;
+       return buildtree(a == NIL ? UCALL : CALL, f, a);
+}
+
+static int
+chk2(TWORD type, union dimfun *dsym, union dimfun *ddef)
+{
+       while (type > BTMASK) {
+               switch (type & TMASK) {
+               case ARY:
+                       /* may be declared without dimension */
+                       if (dsym->ddim == NOOFFSET)
+                               dsym->ddim = ddef->ddim;
+                       if (dsym->ddim < 0 && ddef->ddim < 0)
+                               ; /* dynamic arrays as arguments */
+                       else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim)
+                               return 1;
+                       dsym++, ddef++;
+                       break;
+               case FTN:
+                       /* old-style function headers with function pointers
+                        * will most likely not have a prototype.
+                        * This is not considered an error.  */
+                       if (ddef->dfun == NULL) {
+#ifdef notyet
+                               werror("declaration not a prototype");
+#endif
+                       } else if (chkftn(dsym->dfun, ddef->dfun))
+                               return 1;
+                       dsym++, ddef++;
+                       break;
+               }
+               type = DECREF(type);
+       }
+       return 0;
+}
+
+/*
+ * Compare two function argument lists to see if they match.
+ */
+int
+chkftn(union arglist *usym, union arglist *udef)
+{
+       TWORD t2;
+       int ty, tyn;
+
+       if (usym == NULL)
+               return 0;
+       if (cftnsp != NULL && udef == NULL && usym->type == VOID)
+               return 0; /* foo() { function with foo(void); prototype */
+       if (udef == NULL && usym->type != TNULL)
+               return 1;
+       while (usym->type != TNULL) {
+               if (usym->type == udef->type)
+                       goto done;
+               /*
+                * If an old-style declaration, then all types smaller than
+                * int are given as int parameters.
+                */
+               if (intcompare) {
+                       ty = BTYPE(usym->type);
+                       tyn = BTYPE(udef->type);
+                       if (ty == tyn || ty != INT)
+                               return 1;
+                       if (tyn == CHAR || tyn == UCHAR ||
+                           tyn == SHORT || tyn == USHORT)
+                               goto done;
+                       return 1;
+               } else
+                       return 1;
+
+done:          ty = BTYPE(usym->type);
+               t2 = usym->type;
+               if (ISSOU(ty)) {
+                       usym++, udef++;
+                       if (suemeq(usym->sap, udef->sap) == 0)
+                               return 1;
+               }
+
+               while (!ISFTN(t2) && !ISARY(t2) && t2 > BTMASK)
+                       t2 = DECREF(t2);
+               if (t2 > BTMASK) {
+                       usym++, udef++;
+                       if (chk2(t2, usym->df, udef->df))
+                               return 1;
+               }
+               usym++, udef++;
+       }
+       if (usym->type != udef->type)
+               return 1;
+       return 0;
+}
+
+void
+fixtype(NODE *p, int class)
+{
+       unsigned int t, type;
+       int mod1, mod2;
+       /* fix up the types, and check for legality */
+
+       /* forward declared enums */
+       if (BTYPE(p->n_sp->stype) == ENUMTY) {
+               MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype);
+       }
+
+       if( (type = p->n_type) == UNDEF ) return;
+       if ((mod2 = (type&TMASK))) {
+               t = DECREF(type);
+               while( mod1=mod2, mod2 = (t&TMASK) ){
+                       if( mod1 == ARY && mod2 == FTN ){
+                               uerror( "array of functions is illegal" );
+                               type = 0;
+                               }
+                       else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){
+                               uerror( "function returns illegal type" );
+                               type = 0;
+                               }
+                       t = DECREF(t);
+                       }
+               }
+
+       /* detect function arguments, watching out for structure declarations */
+       if (rpole && ISFTN(type)) {
+               uerror("function illegal in structure or union");
+               type = INCREF(type);
+       }
+       p->n_type = type;
+}
+
+/*
+ * give undefined version of class
+ */
+int
+uclass(int class)
+{
+       if (class == SNULL)
+               return(EXTERN);
+       else if (class == STATIC)
+               return(USTATIC);
+       else
+               return(class);
+}
+
+int
+fixclass(int class, TWORD type)
+{
+       extern int fun_inline;
+
+       /* first, fix null class */
+       if (class == SNULL) {
+               if (fun_inline && ISFTN(type))
+                       return SNULL;
+               if (rpole)
+                       cerror("field8");
+               else if (blevel == 0)
+                       class = EXTDEF;
+               else
+                       class = AUTO;
+       }
+
+       /* now, do general checking */
+
+       if( ISFTN( type ) ){
+               switch( class ) {
+               default:
+                       uerror( "function has illegal storage class" );
+               case AUTO:
+                       class = EXTERN;
+               case EXTERN:
+               case EXTDEF:
+               case TYPEDEF:
+               case STATIC:
+               case USTATIC:
+                       ;
+                       }
+               }
+
+       if (class & FIELD) {
+               cerror("field3");
+       }
+
+       switch (class) {
+
+       case MOS:
+       case MOU:
+               cerror("field4");
+
+       case REGISTER:
+               if (blevel == 0)
+                       uerror("illegal register declaration");
+               if (blevel == 1)
+                       return(PARAM);
+               else
+                       return(REGISTER);
+
+       case AUTO:
+               if( blevel < 2 ) uerror( "illegal ULABEL class" );
+               return( class );
+
+       case EXTERN:
+       case STATIC:
+       case EXTDEF:
+       case TYPEDEF:
+       case USTATIC:
+       case PARAM:
+               return( class );
+
+       default:
+               cerror( "illegal class: %d", class );
+               /* NOTREACHED */
+
+       }
+       return 0; /* XXX */
+}
+
+/*
+ * Generates a goto statement; sets up label number etc.
+ */
+void
+gotolabel(char *name)
+{
+       struct symtab *s = lookup(name, SLBLNAME|STEMP);
+
+       if (s->soffset == 0) {
+               s->soffset = -getlab();
+               s->sclass = STATIC;
+       }
+       branch(s->soffset < 0 ? -s->soffset : s->soffset);
+}
+
+/*
+ * Sets a label for gotos.
+ */
+void
+deflabel(char *name, NODE *p)
+{
+       struct symtab *s = lookup(name, SLBLNAME|STEMP);
+
+#ifdef GCC_COMPAT
+       s->sap = gcc_attr_parse(p);
+#endif
+       if (s->soffset > 0)
+               uerror("label '%s' redefined", name);
+       if (s->soffset == 0) {
+               s->soffset = getlab();
+               s->sclass = STATIC;
+       }
+       if (s->soffset < 0)
+               s->soffset = -s->soffset;
+       plabel( s->soffset);
+}
+
+struct symtab *
+getsymtab(char *name, int flags)
+{
+       struct symtab *s;
+
+       if (flags & SSTMT) {
+               s = stmtalloc(sizeof(struct symtab));
+       } else if (flags & SBLK) {
+               s = blkalloc(sizeof(struct symtab));
+       } else if (flags & STEMP) {
+               s = tmpalloc(sizeof(struct symtab));
+       } else {
+               s = permalloc(sizeof(struct symtab));
+               symtabcnt++;
+       }
+       s->sname = name;
+       s->snext = NULL;
+       s->stype = UNDEF;
+       s->squal = 0;
+       s->sclass = SNULL;
+       s->sflags = (short)(flags & SMASK);
+       s->soffset = 0;
+       s->slevel = (char)blevel;
+       s->sdf = NULL;
+       s->sap = NULL;
+       return s;
+}
+
+int
+fldchk(int sz)
+{
+       if (rpole->rsou != STNAME && rpole->rsou != UNAME)
+               uerror("field outside of structure");
+       if (sz < 0 || sz >= FIELD) {
+               uerror("illegal field size");
+               return 1;
+       }
+       return 0;
+}
+
+#ifdef PCC_DEBUG
+static char *
+ccnames[] = { /* names of storage classes */
+       "SNULL",
+       "AUTO",
+       "EXTERN",
+       "STATIC",
+       "REGISTER",
+       "EXTDEF",
+       "LABEL",
+       "ULABEL",
+       "MOS",
+       "PARAM",
+       "STNAME",
+       "MOU",
+       "UNAME",
+       "TYPEDEF",
+       "FORTRAN",
+       "ENAME",
+       "MOE",
+       "UFORTRAN",
+       "USTATIC",
+       };
+
+char *
+scnames(int c)
+{
+       /* return the name for storage class c */
+       static char buf[12];
+       if( c&FIELD ){
+               snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ );
+               return( buf );
+               }
+       return( ccnames[c] );
+       }
+#endif
+
+#if 0
+static char *stack_chk_fail = "__stack_smash_handler";
+static char *stack_chk_guard = "__guard";
+#else
+static char *stack_chk_fail = "__stack_chk_fail";
+static char *stack_chk_guard = "__stack_chk_guard";
+#endif
+static char *stack_chk_canary = "__stack_chk_canary";
+
+void
+sspinit(void)
+{
+       NODE *p;
+
+       p = block(NAME, NIL, NIL, FTN+VOID, 0, 0);
+       p->n_sp = lookup(stack_chk_fail, SNORMAL);
+       defid(p, EXTERN);
+       nfree(p);
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_sp = lookup(stack_chk_guard, SNORMAL);
+       defid(p, EXTERN);
+       nfree(p);
+}
+
+void
+sspstart(void)
+{
+       NODE *p, *q;
+
+       q = block(NAME, NIL, NIL, INT, 0, 0);
+       q->n_sp = lookup(stack_chk_guard, SNORMAL);
+       q = clocal(q);
+
+       p = block(REG, NIL, NIL, INCREF(INT), 0, 0);
+       slval(p, 0);
+       p->n_rval = FPREG;
+       p = cast(p, INT, 0);
+       q = buildtree(ER, p, q);
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_qual = VOL >> TSHIFT;
+       p->n_sp = lookup(stack_chk_canary, SNORMAL);
+       defid(p, AUTO);
+       p = clocal(p);
+       ecomp(buildtree(ASSIGN, p, q));
+}
+
+void
+sspend(void)
+{
+       NODE *p, *q;
+       TWORD t;
+       int lab;
+
+       if (retlab != NOLAB) {
+               plabel(retlab);
+               retlab = getlab();
+       }
+
+       t = DECREF(cftnsp->stype);
+       if (t == BOOL)
+               t = BOOL_TYPE;
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_sp = lookup(stack_chk_canary, SNORMAL);
+       p = clocal(p);
+
+       q = block(REG, NIL, NIL, INCREF(INT), 0, 0);
+       slval(q, 0);
+       q->n_rval = FPREG;
+       q = cast(q, INT, 0);
+       q = buildtree(ER, p, q);
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_sp = lookup(stack_chk_guard, SNORMAL);
+       p = clocal(p);
+
+       lab = getlab();
+       cbranch(buildtree(EQ, p, q), bcon(lab));
+
+       p = block(NAME, NIL, NIL, FTN+VOID, 0, 0);
+       p->n_sp = lookup(stack_chk_fail, SNORMAL);
+       p = clocal(p);
+
+       q = eve(bdty(STRING, cftnsp->sname, PTR|CHAR));
+       ecomp(buildtree(CALL, p, q));
+
+       plabel(lab);
+}
+
+/*
+ * Fetch pointer to first member in a struct list.
+ */
+struct symtab *
+strmemb(struct attr *ap)
+{
+
+       if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL)
+               cerror("strmemb");
+       return ap->amlist;
+}
+
+#ifndef NO_COMPLEX
+
+static char *real, *imag;
+static struct symtab *cxsp[3], *cxmul[3], *cxdiv[3];
+static char *cxnmul[] = { "__mulsc3", "__muldc3", "__mulxc3" };
+static char *cxndiv[] = { "__divsc3", "__divdc3", "__divxc3" };
+/*
+ * As complex numbers internally are handled as structs, create
+ * these by hand-crafting them.
+ */
+void
+complinit(void)
+{
+       struct attr *ap;
+       struct rstack *rp;
+       NODE *p, *q;
+       char *n[] = { "0f", "0d", "0l" };
+       int i, d_debug;
+
+       d_debug = ddebug;
+       ddebug = 0;
+       real = addname("__real");
+       imag = addname("__imag");
+       p = block(NAME, NIL, NIL, FLOAT, 0, 0);
+       for (i = 0; i < 3; i++) {
+               p->n_type = FLOAT+i;
+               rpole = rp = bstruct(NULL, STNAME, NULL);
+               soumemb(p, real, 0);
+               soumemb(p, imag, 0);
+               q = dclstruct(rp);
+               cxsp[i] = q->n_sp = lookup(addname(n[i]), 0);
+               defid(q, TYPEDEF);
+               ap = attr_new(ATTR_COMPLEX, 0);
+               q->n_sp->sap = attr_add(q->n_sp->sap, ap);
+               nfree(q);
+       }
+       /* create function declarations for external ops */
+       for (i = 0; i < 3; i++) {
+               cxnmul[i] = addname(cxnmul[i]);
+               p->n_sp = cxmul[i] = lookup(cxnmul[i], 0);
+               p->n_type = FTN|STRTY;
+               p->n_ap = cxsp[i]->sap;
+               p->n_df = cxsp[i]->sdf;
+               defid2(p, EXTERN, 0);
+               cxmul[i]->sdf = permalloc(sizeof(union dimfun));
+               dimfuncnt++;
+               cxmul[i]->sdf->dfun = NULL;
+               cxndiv[i] = addname(cxndiv[i]);
+               p->n_sp = cxdiv[i] = lookup(cxndiv[i], 0);
+               p->n_type = FTN|STRTY;
+               p->n_ap = cxsp[i]->sap;
+               p->n_df = cxsp[i]->sdf;
+               defid2(p, EXTERN, 0);
+               cxdiv[i]->sdf = permalloc(sizeof(union dimfun));
+               dimfuncnt++;
+               cxdiv[i]->sdf->dfun = NULL;
+       }
+       nfree(p);
+       ddebug = d_debug;
+}
+
+static TWORD
+maxtt(NODE *p)
+{
+       TWORD t;
+
+       t = ANYCX(p) ? strmemb(p->n_ap)->stype : p->n_type;
+       t = BTYPE(t);
+       if (t == VOID)
+               t = CHAR; /* pointers */
+       if (ISITY(t))
+               t -= (FIMAG - FLOAT);
+       return t;
+}
+
+/*
+ * Return the highest real floating point type.
+ * Known that at least one type is complex or imaginary.
+ */
+static TWORD
+maxtyp(NODE *l, NODE *r)
+{
+       TWORD tl, tr, t;
+
+       tl = maxtt(l);
+       tr = maxtt(r);
+       t = tl > tr ? tl : tr;
+       if (!ISFTY(t))
+               cerror("maxtyp");
+       return t;
+}
+
+/*
+ * Fetch space on stack for complex struct.
+ */
+static NODE *
+cxstore(TWORD t)
+{
+       struct symtab s;
+
+       s = *cxsp[t - FLOAT];
+       s.sclass = AUTO;
+       s.soffset = NOOFFSET;
+       oalloc(&s, &autooff);
+       return nametree(&s);
+}
+
+#define        comop(x,y) buildtree(COMOP, x, y)
+
+/*
+ * Convert node p to complex type dt.
+ */
+static NODE *
+mkcmplx(NODE *p, TWORD dt)
+{
+       NODE *q, *r, *i, *t;
+
+       if (!ANYCX(p)) {
+               /* Not complex, convert to complex on stack */
+               q = cxstore(dt);
+               if (ISITY(p->n_type)) {
+                       p->n_type = p->n_type - FIMAG + FLOAT;
+                       r = bcon(0);
+                       i = p;
+               } else {
+                       if (ISPTR(p->n_type))
+                               p = cast(p, INTPTR, 0);
+                       r = p;
+                       i = bcon(0);
+               }
+               p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r);
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i));
+               p = comop(p, q);
+       } else {
+               if (strmemb(p->n_ap)->stype != dt) {
+                       q = cxstore(dt);
+                       p = buildtree(ADDROF, p, NIL);
+                       t = tempnode(0, p->n_type, p->n_df, p->n_ap);
+                       p = buildtree(ASSIGN, ccopy(t), p);
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, real),
+                           structref(ccopy(t), STREF, real)));
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag),
+                           structref(t, STREF, imag)));
+                       p = comop(p, q);
+               }
+       }
+       return p;
+}
+
+static NODE *
+cxasg(NODE *l, NODE *r)
+{
+       TWORD tl, tr;
+
+       tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0;
+       tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0;
+
+       if (ANYCX(l) && ANYCX(r) && tl != tr) {
+               /* different types in structs */
+               r = mkcmplx(r, tl);
+       } else if (!ANYCX(l))
+               r = structref(r, DOT, ISITY(l->n_type) ? imag : real);
+       else if (!ANYCX(r))
+               r = mkcmplx(r, tl);
+       return buildtree(ASSIGN, l, r);
+}
+
+/*
+ * Fixup complex operations.
+ * At least one operand is complex.
+ */
+NODE *
+cxop(int op, NODE *l, NODE *r)
+{
+       TWORD mxtyp;
+       NODE *p, *q;
+       NODE *ltemp, *rtemp;
+       NODE *real_l, *imag_l;
+       NODE *real_r, *imag_r;
+       real_r = imag_r = NULL; /* bad uninit var warning */
+
+       if (op == ASSIGN)
+               return cxasg(l, r);
+
+       mxtyp = maxtyp(l, r);
+       l = mkcmplx(l, mxtyp);
+       if (op != UMINUS)
+               r = mkcmplx(r, mxtyp);
+
+       if (op == COLON)
+               return buildtree(COLON, l, r);
+
+       /* put a pointer to left and right elements in a TEMP */
+       l = buildtree(ADDROF, l, NIL);
+       ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap);
+       l = buildtree(ASSIGN, ccopy(ltemp), l);
+
+       if (op != UMINUS) {
+               r = buildtree(ADDROF, r, NIL);
+               rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap);
+               r = buildtree(ASSIGN, ccopy(rtemp), r);
+
+               p = comop(l, r);
+       } else
+               p = l;
+
+       /* create the four trees needed for calculation */
+       real_l = structref(ccopy(ltemp), STREF, real);
+       imag_l = structref(ltemp, STREF, imag);
+       if (op != UMINUS) {
+               real_r = structref(ccopy(rtemp), STREF, real);
+               imag_r = structref(rtemp, STREF, imag);
+       }
+
+       /* get storage on stack for the result */
+       q = cxstore(mxtyp);
+
+       switch (op) {
+       case NE:
+       case EQ:
+               tfree(q);
+               p = buildtree(op, comop(p, real_l), real_r);
+               q = buildtree(op, imag_l, imag_r);
+               p = buildtree(op == EQ ? ANDAND : OROR, p, q);
+               return p;
+
+       case ANDAND:
+       case OROR: /* go via EQ to get INT of it */
+               tfree(q);
+               p = buildtree(NE, comop(p, real_l), bcon(0)); /* gets INT */
+               q = buildtree(NE, imag_l, bcon(0));
+               p = buildtree(OR, p, q);
+
+               q = buildtree(NE, real_r, bcon(0));
+               q = buildtree(OR, q, buildtree(NE, imag_r, bcon(0)));
+
+               p = buildtree(op, p, q);
+               return p;
+
+       case UMINUS:
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), 
+                   buildtree(op, real_l, NIL)));
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), 
+                   buildtree(op, imag_l, NIL)));
+               break;
+
+       case PLUS:
+       case MINUS:
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), 
+                   buildtree(op, real_l, real_r)));
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), 
+                   buildtree(op, imag_l, imag_r)));
+               break;
+
+       case MUL:
+       case DIV:
+               /* Complex mul is "complex" */
+               /* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */
+               /* Complex div is even more "complex" */
+               /* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */
+               /* but we need to do it via a subroutine */
+               tfree(q);
+               p = buildtree(CM, comop(p, real_l), imag_l);
+               p = buildtree(CM, p, real_r);
+               p = buildtree(CM, p, imag_r);
+               q = nametree(op == DIV ?
+                   cxdiv[mxtyp-FLOAT] : cxmul[mxtyp-FLOAT]);
+               return buildtree(CALL, q, p);
+               break;
+       default:
+               uerror("illegal operator %s", copst(op));
+       }
+       return comop(p, q);
+}
+
+/*
+ * Fixup imaginary operations.
+ * At least one operand is imaginary, none is complex.
+ */
+NODE *
+imop(int op, NODE *l, NODE *r)
+{
+       NODE *p, *q;
+       TWORD mxtyp;
+       int li, ri;
+
+       li = ri = 0;
+       if (ISITY(l->n_type))
+               li = 1, l->n_type = l->n_type - (FIMAG-FLOAT);
+       if (ISITY(r->n_type))
+               ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT);
+
+       mxtyp = maxtyp(l, r);
+       switch (op) {
+       case ASSIGN:
+               /* if both are imag, store value, otherwise store 0.0 */
+               if (!(li && ri)) {
+                       tfree(r);
+                       r = bcon(0);
+               }
+               p = buildtree(ASSIGN, l, r);
+               p->n_type += (FIMAG-FLOAT);
+               break;
+
+       case PLUS:
+               if (li && ri) {
+                       p = buildtree(PLUS, l, r);
+                       p->n_type += (FIMAG-FLOAT);
+               } else {
+                       /* If one is imaginary and one is real, make complex */
+                       if (li)
+                               q = l, l = r, r = q; /* switch */
+                       q = cxstore(mxtyp);
+                       p = buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, real), l);
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag), r));
+                       p = comop(p, q);
+               }
+               break;
+
+       case MINUS:
+               if (li && ri) {
+                       p = buildtree(MINUS, l, r);
+                       p->n_type += (FIMAG-FLOAT);
+               } else if (li) {
+                       q = cxstore(mxtyp);
+                       p = buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+                           buildtree(UMINUS, r, NIL));
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag), l));
+                       p = comop(p, q);
+               } else /* if (ri) */ {
+                       q = cxstore(mxtyp);
+                       p = buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, real), l);
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag),
+                           buildtree(UMINUS, r, NIL)));
+                       p = comop(p, q);
+               }
+               break;
+
+       case MUL:
+               p = buildtree(MUL, l, r);
+               if (li && ri)
+                       p = buildtree(UMINUS, p, NIL);
+               if (li ^ ri)
+                       p->n_type += (FIMAG-FLOAT);
+               break;
+
+       case DIV:
+               p = buildtree(DIV, l, r);
+               if (ri && !li)
+                       p = buildtree(UMINUS, p, NIL);
+               if (li ^ ri)
+                       p->n_type += (FIMAG-FLOAT);
+               break;
+
+       case EQ:
+       case NE:
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+               if (li ^ ri) { /* always 0 */
+                       tfree(l);
+                       tfree(r);
+                       p = bcon(0);
+               } else
+                       p = buildtree(op, l, r);
+               break;
+
+       default:
+               cerror("imop");
+               p = NULL;
+       }
+       return p;
+}
+
+NODE *
+cxelem(int op, NODE *p)
+{
+
+       if (ANYCX(p)) {
+               p = structref(p, DOT, op == XREAL ? real : imag);
+       } else if (op == XIMAG) {
+               /* XXX  sanitycheck? */
+               tfree(p);
+               p = bcon(0);
+       }
+       return p;
+}
+
+NODE *
+cxconj(NODE *p)
+{
+       NODE *q, *r;
+
+       /* XXX side effects? */
+       q = cxstore(strmemb(p->n_ap)->stype);
+       r = buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+           structref(ccopy(p), DOT, real));
+       r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag),
+           buildtree(UMINUS, structref(p, DOT, imag), NIL)));
+       return comop(r, q);
+}
+
+/*
+ * Prepare for return.
+ * There may be implicit casts to other types.
+ */
+NODE *
+imret(NODE *p, NODE *q)
+{
+       if (ISITY(q->n_type) && ISITY(p->n_type)) {
+               if (p->n_type != q->n_type) {
+                       p->n_type -= (FIMAG-FLOAT);
+                       p = cast(p, q->n_type - (FIMAG-FLOAT), 0);
+                       p->n_type += (FIMAG-FLOAT);
+               }
+       } else {
+               p1tfree(p);
+               if (ISITY(q->n_type)) {
+                       p = block(FCON, 0, 0, q->n_type, 0, 0);
+                       p->n_dcon = fltallo();
+                       *p->n_dcon = *FLOAT_ZERO;
+               } else
+                       p = bcon(0);
+       }
+               
+       return p;
+}
+
+/*
+ * Prepare for return.
+ * There may be implicit casts to other types.
+ */
+NODE *
+cxret(NODE *p, NODE *q)
+{
+       if (ANYCX(q)) { /* Return complex type */
+               p = mkcmplx(p, strmemb(q->n_ap)->stype);
+       } else if (q->n_type < STRTY || ISITY(q->n_type)) { /* real or imag */
+               p = structref(p, DOT, ISITY(q->n_type) ? imag : real);
+               if (p->n_type != q->n_type)
+                       p = cast(p, q->n_type, 0);
+       } else
+               cerror("cxred failing type");
+       return p;
+}
+
+/*
+ * either p1 or p2 is complex, so fixup the remaining type accordingly.
+ */
+NODE *
+cxcast(NODE *p1, NODE *p2)
+{
+       if (ANYCX(p1) && ANYCX(p2)) {
+               if (p1->n_type != p2->n_type)
+                       p2 = mkcmplx(p2, p1->n_type);
+       } else if (ANYCX(p1)) {
+               p2 = mkcmplx(p2, strmemb(p1->n_ap)->stype);
+       } else /* if (ANYCX(p2)) */ {
+               p2 = cast(structref(p2, DOT, real), p1->n_type, 0);
+       }
+       nfree(p1);
+       return p2;
+}
+
+static void
+cxargfixup(NODE *a, TWORD dt, struct attr *ap)
+{
+       NODE *p;
+       TWORD t;
+
+       p = p1alloc();
+       *p = *a;
+       if (dt == STRTY) {
+               /* dest complex */
+               t = strmemb(ap)->stype;
+               p = mkcmplx(p, t);
+       } else {
+               /* src complex, not dest */
+               p = structref(p, DOT, ISFTY(dt) ? real : imag);
+       }
+       *a = *p;
+       nfree(p);
+}
+#endif
+
+/*
+ * Allocations:
+ *     permalloc() Never freed. in pass2.
+ *     tmpalloc() during a function lifetime, then freed. in pass2.
+ *     blkalloc() during a block lifetime.  Variables etc.  In pass1.
+ *     stmtalloc() during a statement lifetime.  Expression trees.  In pass1.
+ */
+
+/*
+ * Short-time allocations during statements.
+ */
+#define MEMCHUNKSZ 8192 /* 8k per allocation */
+struct balloc {
+        char a1;
+        union {
+                long long l;
+                long double d;
+        } a2;
+};
+#define ALIGNMENT offsetof(struct balloc, a2)
+#define ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1))
+
+#define        MAXSZ   MEMCHUNKSZ-sizeof(struct xalloc *)
+struct xalloc {
+       struct xalloc *next;
+       union {
+               long long b; /* for initial alignment */
+               long double d;
+               char elm[MAXSZ];
+       };
+} *sapole, *bkpole;
+int cstp, cbkp;
+
+void *
+stmtalloc(size_t size)
+{
+       struct xalloc *xp;
+       void *rv;
+
+       size = ROUNDUP(size);
+       if (size > MAXSZ)
+               cerror("stmtalloc");
+       if (sapole == 0 || (size + cstp) > MAXSZ) {
+               xp = xmalloc(sizeof(struct xalloc));
+               xp->next = sapole;
+               sapole = xp;
+               cstp = 0;
+       }
+       rv = &sapole->elm[cstp];
+       cstp += size;
+       return rv;
+}
+
+void
+stmtfree(void)
+{
+       extern P1ND *frelink;
+       extern int usdnodes;
+       struct xalloc *x1;
+
+       if (usdnodes != 0)
+               cerror("stmtfree: usdnodes %d", usdnodes);
+       frelink = NULL;
+
+       while (sapole) {
+               x1 = sapole->next;
+               free(sapole);
+               sapole = x1;
+       }
+       cstp = 0;
+}
+
+void *
+blkalloc(size_t size)
+{
+       struct xalloc *xp;
+       void *rv;
+
+       if (blevel < 2)
+               return permalloc(size);
+
+       size = ROUNDUP(size);
+       if (size > MAXSZ)
+               cerror("blkalloc");
+       if (bkpole == 0 || (size + cbkp) > MAXSZ) {
+               xp = xmalloc(sizeof(struct xalloc));
+               xp->next = bkpole;
+               bkpole = xp;
+               cbkp = 0;
+       }
+       rv = &bkpole->elm[cbkp];
+       cbkp += size;
+       return rv;
+}
+
+void
+blkfree(void)
+{
+       struct xalloc *x1;
+
+       while (bkpole) {
+               x1 = bkpole->next;
+               free(bkpole);
+               bkpole = x1;
+       }
+       cbkp = 0;
+}
+
diff --git a/lang/pcc/pcc/cc/ccom/scan.l b/lang/pcc/pcc/cc/ccom/scan.l
new file mode 100644 (file)
index 0000000..31a8961
--- /dev/null
@@ -0,0 +1,958 @@
+%{
+/*     $Id: scan.l,v 1.147 2016/03/08 18:17:45 ragge Exp $     */
+
+/*
+ * Copyright (c) 2002 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+%}
+
+
+B                      [0-1]
+D                      [0-9]
+L                      [a-zA-Z_]
+H                      [a-fA-F0-9]
+E                      [Ee][+-]?{D}+
+P                      [Pp][+-]?{D}+
+FS                     ((f|F|l|L)?i|i?(f|F|l|L))
+IS                     (u|U|l|L|i)*
+UL                     ({L}|[\x80-\xFF])
+UC                     (L|u|U)
+US                     (L|u|U|u8)
+
+%{
+#include <stdlib.h>
+#include <errno.h>  
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "pass1.h"
+#include "cgram.h"
+#include "unicode.h"
+
+#define        bdebug flexbdebug
+
+static P1ND *cvtdig(int radix);
+static P1ND *charcon(void);
+static P1ND *wcharcon(void);
+static void control(int);
+static void pragma(void);
+int notype, parbal, inattr, parlvl, nodinit, inoso;
+int kwdecode(struct symtab *s);
+
+#define        CPP_IDENT       2
+#define        CPP_LINE        3
+#define        CPP_HASH        4
+
+#ifdef STABS
+#define        STABS_LINE(x) if (gflag && cftnsp) stabs_line(x)
+#else
+#define STABS_LINE(x)
+#endif
+#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31
+/* Hack to avoid unnecessary warnings */
+FILE *yyget_in  (void);
+FILE *yyget_out  (void);
+int yyget_leng  (void);
+char *yyget_text  (void);
+void yyset_in (FILE *);
+void yyset_out (FILE *);
+int yyget_debug  (void);
+void yyset_debug (int);
+int yylex_destroy  (void);
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+#endif
+
+%}
+
+%%
+
+{UL}({UL}|{D})*        {       struct symtab *s;
+                       int i = 0;
+
+                       yylval.strp = addname(yytext);
+                       if ((s = lookup(yylval.strp, SNOCREAT)) != NULL &&
+                           s->sclass == KEYWORD)
+                               return kwdecode(s);
+
+#ifdef GCC_COMPAT
+                       if (doing_init && nodinit == 0) {
+                               /* check for name: for old gcc compat */
+                               while ((i = input()) == ' ' || i == '\t')
+                                       ;
+                               if (i == ':')
+                                       return(GCC_DESIG);
+                               unput(i);
+                       }
+                       if ((i = gcc_keyword(yylval.strp)) > 0) {
+                               if (i == PCC_OFFSETOF)
+                                       inoso = 1;
+                               return i;
+                       }
+#endif
+                       if (i == 0) {
+                               if (notype)
+                                       return(C_NAME);
+                               return s && s->sclass == TYPEDEF ?
+                                   notype=1, C_TYPENAME : C_NAME;
+                       }
+               }
+
+0[xX]{H}+{IS}?         { yylval.nodep = cvtdig(16); return(C_ICON); }
+0{D}+{IS}?             { yylval.nodep = cvtdig(8); return(C_ICON); }
+0[bB]{B}+{IS}?         { yylval.nodep = cvtdig(2); return(C_ICON); }
+{D}+{IS}?              { yylval.nodep = cvtdig(10); return(C_ICON); }
+{UC}'(\\.|[^\\'])*'    { yylval.nodep = wcharcon(); return(C_ICON); }
+'(\\.|[^\\'])*'                { yylval.nodep = charcon(); return(C_ICON); }
+
+{D}+{E}{FS}?           { yylval.flt = floatcon(yytext); return(C_FCON); }
+{D}*"."{D}+({E})?{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); }
+{D}+"."{D}*({E})?{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); }
+0[xX]{H}*"."{H}+{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+"."{P}{FS}?   { yylval.flt = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+{P}{FS}?      { yylval.flt = fhexcon(yytext); return(C_FCON); }
+
+{US}?\"(\\.|[^\\"])*\" { yylval.strp = yytext; return C_STRING; }
+
+"..."                  { return(C_ELLIPSIS); }
+">>="                  { yylval.intval = RSEQ; return(C_ASOP); }
+"<<="                  { yylval.intval = LSEQ; return(C_ASOP); }
+"+="                   { yylval.intval = PLUSEQ; return(C_ASOP); }
+"-="                   { yylval.intval = MINUSEQ; return(C_ASOP); }
+"*="                   { yylval.intval = MULEQ; return(C_ASOP); }
+"/="                   { yylval.intval = DIVEQ; return(C_ASOP); }
+"%="                   { yylval.intval = MODEQ; return(C_ASOP); }
+"&="                   { yylval.intval = ANDEQ; return(C_ASOP); }
+"^="                   { yylval.intval = EREQ; return(C_ASOP); }
+"|="                   { yylval.intval = OREQ; return(C_ASOP); }
+">>"                   { yylval.intval = RS; return(C_SHIFTOP); }
+"<<"                   { yylval.intval = LS; return(C_SHIFTOP); }
+"++"                   { yylval.intval = INCR; return(C_INCOP); }
+"--"                   { yylval.intval = DECR; return(C_INCOP); }
+"->"                   { yylval.intval = STREF; return(C_STROP); }
+"&&"                   { yylval.intval = ANDAND; return(C_ANDAND); }
+"||"                   { yylval.intval = OROR; return(C_OROR); }
+"<="                   { yylval.intval = LE; return(C_RELOP); }
+">="                   { yylval.intval = GE; return(C_RELOP); }
+"=="                   { yylval.intval = EQ; return(C_EQUOP); }
+"!="                   { yylval.intval = NE; return(C_EQUOP); }
+";"                    { notype = 0; return(';'); }
+("{"|"<%")             { notype = 0; return('{'); }
+("}"|"%>")             { if (rpole) notype = 1; return('}'); }
+","                    { if (parbal && !inoso) notype = 0;
+                               if (parbal == 0) notype = 1; return(','); }
+":"                    { if (doing_init) nodinit--; return(':'); }
+"="                    { return('='); }
+"("                    { parbal++; notype = 0; return('('); }
+")"                    {       parbal--;
+                               inoso = 0;
+                               if (parbal==0) { notype = 0; }
+                               if (inattr && parlvl == parbal)
+                                       inattr = 0;
+                               return(')'); }
+("["|"<:")             { return('['); }
+("]"|":>")             { return(']'); }
+"."                    { yylval.intval = DOT; return(C_STROP); }
+"&"                    { return('&'); }
+"!"                    { yylval.intval = NOT; return(C_UNOP); }
+"~"                    { yylval.intval = COMPL; return(C_UNOP); }
+"-"                    { return('-'); }
+"+"                    { return('+'); }
+"*"                    { if (parbal && notype == 0) notype = 1; return('*'); }
+"/"                    { yylval.intval = DIV; return(C_DIVOP); }
+"%"                    { yylval.intval = MOD; return(C_DIVOP); }
+"<"                    { yylval.intval = LT; return(C_RELOP); }
+">"                    { yylval.intval = GT; return(C_RELOP); }
+"^"                    { return('^'); }
+"|"                    { return('|'); }
+"?"                    { if (doing_init) nodinit++; return('?'); }
+^#pragma[ \t].*                { pragma(); }
+^#ident[ \t].*         { control(CPP_IDENT); }
+^#line[ \t].*          { control(CPP_LINE); }
+^#.*                   { control(CPP_HASH); }
+
+[ \t\v\f]              { }
+"\n"                   { ++lineno; STABS_LINE(lineno); }
+.                      { /* ignore bad characters */ }
+
+%%
+
+int lineno, issyshdr;
+
+int
+yywrap(void)
+{
+       if (0) unput(0); /* quiet gcc */
+       return(1);
+}
+
+#define        DEFKW   500
+#define        KWFUNC  501
+#define        KWNOT   502
+
+struct keywords {
+       char *name;
+       int cword, wclass;
+} keywords[] = {
+       { "__func__", 0, KWFUNC },
+       { "_Alignas", C_ALIGNAS, DEFKW },
+       { "_Alignof", C_ALIGNOF, DEFKW },
+       { "_Atomic", C_ATOMIC, DEFKW },
+       { "asm", C_ASM, DEFKW },
+       { "auto", AUTO, C_CLASS },
+       { "_Bool", BOOL, C_TYPE },
+       { "break", C_BREAK, DEFKW },
+       { "case", C_CASE, DEFKW },
+       { "char", CHAR, C_TYPE },
+       { "continue", C_CONTINUE, DEFKW },
+       { "_Complex", COMPLEX, C_TYPE },
+       { "const", CON, C_QUALIFIER },
+       { "default", C_DEFAULT, DEFKW },
+       { "do", C_DO, DEFKW },
+       { "double", DOUBLE, C_TYPE },
+       { "else", C_ELSE, DEFKW },
+       { "enum", C_ENUM, KWNOT },
+       { "extern", EXTERN, C_CLASS },
+       { "float", FLOAT, C_TYPE },
+       { "for", C_FOR, DEFKW },
+       { "_Generic", C_GENERIC, DEFKW },
+       { "goto", C_GOTO, KWNOT },
+       { "if", C_IF, DEFKW },
+       { "_Imaginary", IMAG, C_TYPE },
+       { "inline", INLINE, C_FUNSPEC },
+       { "int", INT, C_TYPE },
+       { "long", LONG, C_TYPE },
+       { "_Noreturn", NORETURN, C_FUNSPEC },
+       { "register", REGISTER, C_CLASS },
+       { "restrict", 0, C_QUALIFIER },
+       { "return", C_RETURN, DEFKW },
+       { "short", SHORT, C_TYPE },
+       { "signed", SIGNED, C_TYPE },
+       { "sizeof", C_SIZEOF, DEFKW },
+       { "static", STATIC, C_CLASS },
+       { "_Static_assert", C_STATICASSERT, DEFKW },
+       { "struct", STNAME, C_STRUCT },
+       { "switch", C_SWITCH, DEFKW },
+       { "_Thread_local", THLOCAL, C_CLASS },
+       { "typedef", TYPEDEF, C_CLASS },
+       { "union", UNAME, C_STRUCT },
+       { "unsigned", UNSIGNED, C_TYPE },
+       { "void", VOID, C_TYPE },
+       { "volatile", VOL, C_QUALIFIER },
+       { "while", C_WHILE, DEFKW },
+};
+       
+
+void
+kwinit(void)
+{
+       struct symtab *s;
+       int i, n = sizeof(keywords) / sizeof(keywords[0]);
+
+       for (i = 0; i < n; i++) {
+               s = lookup(addname(keywords[i].name), 0);
+               s->sclass = KEYWORD;
+               s->soffset = i;
+       }
+}
+
+int
+kwdecode(struct symtab *s)
+{
+       struct keywords *kw = &keywords[s->soffset];
+
+       if (inattr && kw->cword != C_SIZEOF)
+               return C_NAME;
+
+       switch (kw->wclass) {
+       case C_TYPE:
+               yylval.type = kw->cword;
+               notype=1;
+               break;
+
+       case C_CLASS:
+               if (kw->cword == THLOCAL)
+                       uerror("_Thread_local not supported");
+               yylval.type = kw->cword;
+               break;
+
+       case C_QUALIFIER:
+               yylval.type = kw->cword;
+               break;
+
+       case C_FUNSPEC:
+               yylval.type = kw->cword;
+               break;
+
+       case DEFKW:
+               return kw->cword;
+
+       case KWFUNC:
+               if (cftnsp == NULL)
+                       uerror("__func__ outside function");
+               yylval.strp = cftnsp->sname;
+               return(C_STRING);
+
+       case KWNOT:
+               notype = 1;
+               return kw->cword;
+
+       case C_STRUCT:
+               notype = 1;
+               yylval.intval = kw->cword;
+               break;
+
+       default:
+               cerror("keyword %s not found", kw->name);
+       }
+       return kw->wclass;
+}
+
+static long double
+typround(long double dc, char *e, TWORD *tw)
+{
+       int im = 0;
+
+       *tw = DOUBLE;
+       for (; *e; e++) {
+               switch (*e) {
+               case 'f':
+               case 'F':
+                       *tw = FLOAT;
+                       dc = (float)dc;
+                       break;
+               case 'l':
+               case 'L':
+                       *tw = ctype(LDOUBLE);
+                       break;
+               case 'i':
+               case 'I':
+                       im = 1;
+                       break;
+               }
+       }
+       if (*tw == DOUBLE)
+               dc = (double)dc;
+#ifndef NO_COMPLEX
+       if (im)
+               *tw += (FIMAG-FLOAT);
+#endif
+       return dc;
+}
+
+/*
+ * Return which type current fp string has.
+ */
+static TWORD
+endtyp(char *s)
+{
+       TWORD tw = DOUBLE;
+
+       for (; *s; s++)
+               ;
+       s--;
+       if (*s == 'i' || *s == 'I')
+               tw += (FIMAG-FLOAT), s--;
+       if (*s == 'f' || *s == 'F')
+               tw--, s--;
+       else if (*s == 'l' || *s == 'L')
+               tw++, s--;
+       if ((*s == 'i' || *s == 'I') && ISFTY(tw))
+               tw += (FIMAG-FLOAT), s--;
+/* XXX complain */
+       return tw;
+}
+
+FLT *
+floatcon(char *s)
+{
+       FLT *flt;
+       TWORD tw;
+
+       flt = stmtalloc(sizeof(FLT));
+#ifdef NATIVE_FLOATING_POINT
+#ifdef HAVE_STRTOLD
+       flt->fp = strtold(s, NULL);
+#else
+       flt->fp = strtod(s, NULL);
+#endif
+#else
+       flt->sf = strtosf(s);           /* parse number */
+#endif
+       flt->t = tw = endtyp(s);
+       if (ISITY(tw))
+               tw -= (FIMAG-FLOAT);
+       return flt;
+}
+
+static int
+h2n(int ch)
+{
+       if (ch >= '0' && ch <= '9')
+               return ch - '0';
+       if (ch >= 'a' && ch <= 'f')
+               return ch - 'a' + 10;
+       return ch - 'A' + 10;
+       
+}
+
+/*
+ * Get exponent.  Max size is 16 bits.
+ */
+static int
+fdecl(char *c, char **ep)
+{
+       int minus = 0;
+       int val = 0;
+
+       if (*c == '+')
+               c++;
+       else if (*c == '-')
+               minus = 1, c++;
+
+       while (isdigit((int)*c)) {
+               val *= 10;
+               val += *c++ - '0';
+               if (val > 32769)
+                       val = 32769;
+       }
+       if (minus)
+               val = -val;
+       *ep = c;
+       return val;
+}
+
+FLT *
+fhexcon(char *c)
+{
+       FLT *flt;
+       TWORD tw;
+       char *ep;
+       long double d;
+       int i, ed;
+
+       d = 0.0;
+       ed = 0;
+       c+= 2; /* skip 0x */
+#define FSET(n) { d *= 2; if (i & n) d += 1.0; }
+       for (; *c != '.' && *c != 'p' && *c != 'P'; c++) {
+               i = h2n(*c);
+               FSET(8); FSET(4); FSET(2); FSET(1);
+       }
+       if (*c != '.' && *c != 'p' && *c != 'P')
+               cerror("fhexcon");
+       if (*c == '.') {
+               c++;
+               for (; *c != 'p' && *c != 'P'; c++) {
+                       i = h2n(*c);
+                       FSET(8); FSET(4); FSET(2); FSET(1);
+                       ed -= 4;
+               }
+       }
+       if (*c != 'P' && *c != 'p')
+               cerror("fhexcon2");
+       c++;
+       ed += fdecl(c, &ep);
+
+       /* avoid looping in vain. Idea from Fred J. Tydeman */
+       if (ed > 32769) ed = 32769;
+       if (ed < -32769) ed = -32769;
+
+       while (ed > 0)
+               d *= 2, ed--;
+       while (ed < 0)
+               d /= 2, ed++;
+       d = typround(d, ep, &tw);
+       flt = stmtalloc(sizeof(FLT));
+       flt->fp = d;
+       flt->t = tw;
+       return flt;
+}
+
+P1ND *
+cvtdig(int radix)
+{
+       P1ND *p;
+       TWORD ntype;
+       unsigned long long v;
+       char *ch = yytext;
+       int n, numl, numu;
+
+       if (radix == 16 || radix == 2)
+               ch += 2; /* Skip 0x or 0b */
+
+       v = 0;
+       while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') ||
+           (*ch >= 'A' && *ch <= 'F')) {
+               v *= radix;
+               n = *ch;
+               n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10);
+               ch++;
+               v += n;
+       }
+       /* Parse trailing chars */
+       ntype = INT;
+       numl = numu = 0;
+       for (n = 0; n < 3; n++) {
+               if (*ch == 0)
+                       break;
+               if ((*ch == 'l' || *ch == 'L') && numl < 2)
+                       ntype+=2, numl++;
+               else if ((*ch == 'u' || *ch == 'U') && numu < 1)
+                       ntype = ENUNSIGN(ntype), numu++;
+               else if (*ch == 'i')
+                       ntype = DOUBLE;
+               else
+                       break;
+               ch++;
+       }
+       if (*ch)
+               uerror("constant has too many '%c'", *ch);
+
+       switch (ntype) {
+       case DOUBLE: /* special case */
+               p = block(FCON, NULL, NULL, IMAG, 0, 0);
+               p->n_dcon = stmtalloc(sizeof(FLT));
+               FLOAT_INT2FP(p->n_dcon, v, ULONGLONG);
+               FLOAT_FP2FP(p->n_dcon, DOUBLE);
+               return p;
+
+       case INT:
+       case LONG:
+       case LONGLONG:
+               if (radix == 10) {
+                       if (ntype == LONGLONG)
+                               break;
+                       if (v > MAX_LONG)
+                               ntype = LONGLONG;
+                       else if (v > MAX_INT)
+                               ntype = LONG;
+               } else {
+                       if (v > MAX_LONGLONG) {
+                               ntype = ULONGLONG;
+                       } else if (v > MAX_ULONG) {
+                               if (ntype < LONGLONG)
+                                       ntype = LONGLONG;
+                       } else if (v > MAX_LONG) {
+                               if (ntype < ULONG)
+                                       ntype = ULONG;
+                       } else if (v > MAX_UNSIGNED) {
+                               if (ntype < LONG)
+                                       ntype = LONG;
+                       } else if (v > MAX_INT) {
+                               if (ntype < UNSIGNED)
+                                       ntype = UNSIGNED;
+                       }
+               }
+               break;
+       case UNSIGNED:
+       case ULONG:
+               if (v > MAX_ULONG) {
+                       ntype = ULONGLONG;
+               } else if (v > MAX_UNSIGNED)
+                       ntype = ULONG;
+               break;  
+       }       
+
+       ntype = ctype(ntype);
+       p = xbcon(v, NULL, ntype);
+       ASGLVAL(p->n_slval, v);
+
+       return p;
+}
+
+/*
+ * return value of escaped character constant
+ */
+unsigned int
+esccon(char **sptr)
+{
+       unsigned int val;
+       char *wr = *sptr;
+       char c;
+
+       wr++;   /* skip \ */
+       switch (c = *wr++) {
+       case 'a': val = '\a'; break;
+       case 'b': val = '\b'; break;
+#ifdef GCC_COMPAT
+       case 'e': val = '\033'; break;
+#endif
+       case 'f': val = '\f'; break;
+       case 'n': val = '\n'; break;
+       case 'r': val = '\r'; break;
+       case 't': val = '\t'; break;
+       case 'v': val = '\v'; break;
+
+       case '\"': val = '\"'; break;
+       case '\'': val = '\''; break;
+       case '\?': val = '\?'; break;
+       case '\\': val = '\\'; break;
+
+       case 'x':
+               val = 0;
+               for (;;) {
+                       c = *wr;
+                       if (c >= '0' && c <= '9')
+                               c = c - '0';
+                       else if (c >= 'a' && c <= 'f')
+                               c = c - 'a' + 10;
+                       else if (c >= 'A' && c <= 'F')
+                               c = c - 'A' + 10;
+                       else
+                               break;
+
+                       val = (val << 4) + c;
+                       wr++;
+               }
+               break;
+
+       case '0': case '1': case '2': case '3':
+       case '4': case '5': case '6': case '7':
+               val = (c - '0');
+               c = *wr;
+               if (c >= '0' && c <= '7') {
+                       wr++;
+                       val = (val << 3) + (c - '0');
+                       c = *wr;
+                       if (c >= '0' && c <= '7') {
+                               wr++;
+                               val = (val << 3) + (c - '0');
+                       }
+               }
+               break;
+
+       default:
+               werror("unknown escape sequence \\%c", c);
+               val = c;
+               break;
+       }
+
+       *sptr = wr;
+       return val;
+}
+
+/*
+ * Convert (one) character constant to an int.
+ * Handle as unsigned except if only one character and char is signed.
+ */
+P1ND *
+charcon(void)
+{
+       unsigned int val = 0, i = 0;
+       char *pp = yytext;
+
+       pp++;   /* skip ' */
+       while (*pp != '\'') {
+               val <<= SZCHAR; /* XXX big endian? */
+               if (*pp == '\\')
+                       val |= esccon(&pp);
+               else
+                       val |= (*pp++ & ((1 << SZCHAR)-1));
+               i++;
+       }
+
+       if (i == 0)
+               uerror("empty character constant");
+       else if (i == 1 && xuchar == 0)
+               val = (signed char)val; /* XXX other sizes of char? */
+       else if (i > 1)
+               werror("too many characters in character constant");
+
+       return bcon(val);
+}
+
+/*
+ * Convert a wide-character constant to an unsigned int
+ */
+P1ND *
+wcharcon(void)
+{
+       unsigned int val = 0, i = 0;
+       char *pp = yytext;
+
+       pp++;   /* skip L */
+       pp++;   /* skip ' */
+       while (*pp != '\'') {
+               /*
+                * although u82cp() does handle escaped values, we deal
+                * with them directly since otherwise you can't process
+                * values which might be valid utf8 prefix
+                */
+               if (*pp == '\\')
+                       val = esccon(&pp);
+               else
+                       val = u82cp(&pp);
+
+               i++;
+       }
+
+       if (i == 0)
+               uerror("empty wide-character constant");
+       else if (i > 1)
+               werror("too many characters in wide-character constant");
+
+       return xbcon(val, NULL, ctype(UNSIGNED));
+}
+
+void
+control(int t)
+{
+       char *wr = yytext;
+       char *eptr;
+       int val;
+
+       wr++;   /* Skip initial '#' */
+       switch (t) {
+       case CPP_IDENT:
+               return; /* Just skip these for now. */
+
+       case CPP_LINE:
+               wr += 4;
+               /* FALLTHROUGH */
+       case CPP_HASH:
+               val = strtol(wr, &eptr, 10);
+               if (wr == eptr) /* Illegal string */
+                       goto bad;
+               wr = eptr;
+               lineno = val - 1;
+               while (*wr && *wr != '\"')
+                       wr++;
+               if (*wr == 0)
+                       return;
+               if (*wr++ != '\"')
+                       goto bad;
+               eptr = wr;
+               while (*wr && *wr != '\"')
+                       wr++;
+               if (*wr != '\"')
+                       goto bad;
+               *wr++ = 0;
+               free(ftitle);
+               ftitle = xstrdup(eptr);
+               while (*wr == ' ')
+                       wr++;
+               issyshdr = 0;
+               if (*wr == '3')
+                       issyshdr = 1;
+#ifdef DWARF
+               if (gflag)
+                       dwarf_file(ftitle);
+#endif
+#ifdef STABS
+               if (gflag)
+                       stabs_file(ftitle);
+#endif
+       }
+       return;
+bad:
+       werror("%s: illegal control", yytext);
+}
+
+int pragma_allpacked;
+int pragma_packed, pragma_aligned;
+
+static int
+pragmas_weak(char *str)
+{
+       struct symtab *sp;
+       char *s1, *s2;
+
+       if ((s1 = pragtok(NULL)) == NULL)
+               return 1;
+       if ((s2 = pragtok(NULL)) == NULL) {
+               sp = lookup(addname(s1), SNORMAL);
+#ifdef GCC_COMPAT
+               sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak")));
+#else
+               sp->sap = NULL;
+#endif
+       } else if (*s2 == '=') {
+               if ((s2 = pragtok(NULL)) == NULL)
+                       return 1;
+               sp = lookup(addname(s2), SNORMAL);
+#ifdef GCC_COMPAT
+               sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL,
+                   bdty(NAME, "aliasweak"), bdty(STRING, s1, 0))));
+#else
+               sp->sap = NULL;
+#endif
+       } else
+               return 1;
+       return 0;
+}
+
+char *pragstore;
+
+/* trivial tokenizer for pragmas */
+#define ps pragstore
+char *
+pragtok(char *sin)
+{
+       static char ss[2];
+       char *rv;
+
+       if (sin)
+               ps = sin;
+
+       for (; isspace((int)*ps); ps++)
+               ;
+       if (*ps == 0)
+               return NULL;
+       for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++)
+               ;
+       ss[0] = *ps;
+       if (rv == ps) {
+               rv = ss, ps++;
+       } else {
+               *ps = 0;
+               rv = tmpstrdup(rv);
+               *ps = ss[0];
+       }
+       return rv;
+}
+
+/* return 1 on error */
+int
+eat(int ch)
+{
+       char *s = pragtok(0);
+       return (s == 0 || *s != ch);
+}
+
+static int
+pragmas_alpack(char *t)
+{
+       char *s;
+       int ap;
+
+       ap = (s = pragtok(0)) ? atoi(s) : 1;
+       if (strcmp(t, "packed") == 0)
+               pragma_packed = ap;
+       else
+               pragma_aligned = ap;
+       return 0;
+}
+
+
+/*
+ * Packing control.
+ */
+static int
+pragmas_pack(char *t)
+{
+#define        PACKSTKSZ 10
+       static int packstk[PACKSTKSZ], packptr;
+       char *s;
+
+       if (eat('('))
+               return 1;
+       s = pragtok(0);
+       if (*s == ')')
+               return pragma_allpacked = 0;
+       if (strcmp(s, "push") == 0) {
+               if (packptr == PACKSTKSZ)
+                       uerror("too many push");
+               packstk[packptr++] = pragma_allpacked;
+               s = pragtok(0);
+               if (*s == ')')
+                       return 0;
+               if (*s != ',')
+                       return 1;
+               s = pragtok(0);
+       } else if (strcmp(s, "pop") == 0) {
+               if (packptr == 0)
+                       uerror("stack empty");
+               pragma_allpacked = packstk[--packptr];
+               return eat(')');
+       }
+
+       if (*s < '0' || *s > '9') /* no number */
+               return 1;
+       pragma_allpacked = atoi(s);
+       return eat(')');
+}
+
+static int      
+pragmas_unsupp(char *t) 
+{ 
+       werror("#pragma %s unsupported", t);
+       return 0; /* Just ignore */
+}
+
+static int
+pragmas_stdc(char *t)
+{
+       return 0; /* Just ignore */
+}
+
+struct pragmas {
+       char *name;
+       int (*fun)(char *);
+} pragmas[] = {
+       { "pack", pragmas_pack },
+       { "packed", pragmas_alpack },
+       { "aligned", pragmas_alpack },
+       { "rename", pragmas_unsupp },
+#ifdef GCC_COMPAT
+       { "GCC", pragmas_gcc },
+#endif
+       { "STDC", pragmas_stdc },
+       { "weak", pragmas_weak },
+       { "ident", NULL },
+       { 0 },
+};
+
+/*
+ * got a full pragma line.  Split it up here.
+ */
+static void
+pragma(void)
+{
+       struct pragmas *p;
+       char *t, *pt;
+
+       if ((t = pragtok(&yytext[7])) != NULL) {
+               pt = ps;
+               for (p = pragmas; p->name; p++) {
+                       if (strcmp(t, p->name) == 0) {
+                               if (p->fun && (*p->fun)(t))
+                                       uerror("bad argument to #pragma");
+                               return;
+                       }
+               }
+               ps = pt;
+               if (mypragma(t))
+                       return;
+       }
+       warner(Wunknown_pragmas, t, ps);
+}
+
+void
+cunput(char c)
+{
+       unput(c);
+}
diff --git a/lang/pcc/pcc/cc/ccom/softfloat.c b/lang/pcc/pcc/cc/ccom/softfloat.c
new file mode 100644 (file)
index 0000000..12f1758
--- /dev/null
@@ -0,0 +1,359 @@
+/*     $Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp $  */
+
+/*
+ * Copyright (c) 2008 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef SOFTFLOAT
+
+#include "pass1.h"
+
+
+/*
+ * Floating point emulation to be used when cross-compiling.
+ * Currently only supports F- and D-float, used in DEC machines.
+ * Should be trivial to add other emulations.
+ *
+ * XXX - assumes that:
+ *     - long long is (at least) 64 bits
+ *     - int is at least 32 bits.
+ *     - short is 16 bits.
+ */
+
+#ifdef FDFLOAT
+
+/*
+ * Useful macros to manipulate the float.
+ */
+#define DSIGN(w)       (((w).fd1 >> 15) & 1)
+#define DSIGNSET(w,s)  ((w).fd1 = (s << 15) | ((w).fd1 & 077777))
+#define DEXP(w)                (((w).fd1 >> 7) & 0377)
+#define DEXPSET(w,e)   ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177))
+#define DMANTH(w)      ((w).fd1 & 0177)
+#define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600))
+
+typedef unsigned int lword;
+typedef unsigned long long dword;
+
+#define MAXMANT 0x100000000000000LL
+
+/*
+ * Returns a zero dfloat.
+ */
+static SF
+nulldf(void)
+{
+       SF rv;
+
+       rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0;
+       return rv;
+}
+
+/*
+ * Convert a (u)longlong to dfloat.
+ * XXX - fails on too large (> 55 bits) numbers.
+ */
+SF
+soft_cast(CONSZ ll, TWORD t)
+{
+       int i;
+       SF rv;
+
+       rv = nulldf();
+       if (ll == 0)
+               return rv;  /* fp is zero */
+       if (ll < 0)
+               DSIGNSET(rv,1), ll = -ll;
+       for (i = 0; ll > 0; i++, ll <<= 1)
+               ;
+       DEXPSET(rv, 192-i);
+       DMANTHSET(rv, ll >> 56);
+       rv.fd2 = ll >> 40;
+       rv.fd3 = ll >> 24;
+       rv.fd4 = ll >> 8;
+       return rv;
+}
+
+/*
+ * multiply two dfloat. Use chop, not round.
+ */
+SF
+soft_mul(SF p1, SF p2)
+{
+       SF rv;
+       lword a1[2], a2[2], res[4];
+       dword sum;
+
+       res[0] = res[1] = res[2] = res[3] = 0;
+
+       /* move mantissa into lwords */
+       a1[0] = p1.fd4 | (p1.fd3 << 16);
+       a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000;
+
+       a2[0] = p2.fd4 | (p2.fd3 << 16);
+       a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000;
+
+#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \
+       res[r] = sum; sum >>= 32;
+
+       sum = 0;
+       MULONE(0, 0, 0);
+       MULONE(1, 0, 1);
+       res[2] = sum;
+       sum = 0;
+       MULONE(0, 1, 1);
+       MULONE(1, 1, 2);
+       res[3] = sum;
+
+       rv.fd1 = 0;
+       DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2));
+       DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128);
+       if (res[3] & 0x8000) {
+               res[3] = (res[3] << 8) | (res[2] >> 24);
+               res[2] = (res[2] << 8) | (res[1] >> 24);
+       } else {
+               DEXPSET(rv, DEXP(rv) - 1);
+               res[3] = (res[3] << 9) | (res[2] >> 23);
+               res[2] = (res[2] << 9) | (res[1] >> 23);
+       }
+       DMANTHSET(rv, res[3] >> 16);
+       rv.fd2 = res[3];
+       rv.fd3 = res[2] >> 16;
+       rv.fd4 = res[2];
+       return rv;
+}
+
+SF
+soft_div(SF t, SF n)
+{
+       SF rv;
+       dword T, N, K;
+       int c;
+
+#define SHL(x,b) ((dword)(x) << b)
+       T = SHL(1,55) | SHL(DMANTH(t), 48) |
+           SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4;
+       N = SHL(1,55) | SHL(DMANTH(n), 48) |
+           SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4;
+
+       c = T > N;
+       for (K = 0; (K & 0x80000000000000ULL) == 0; ) {
+               if (T >= N) {
+                       T -= N;
+                       K |= 1;
+               }
+               T <<= 1;
+               K <<= 1;
+       }
+       rv.fd1 = 0;
+       DSIGNSET(rv, DSIGN(t) ^ DSIGN(n));
+       DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c);
+       DMANTHSET(rv, K >> 48);
+       rv.fd2 = K >> 32;
+       rv.fd3 = K >> 16;
+       rv.fd4 = K;
+       return rv;
+}
+
+/*
+ * Negate a float number. Easy.
+ */
+SF
+soft_neg(SF sf)
+{
+       int sign = DSIGN(sf) == 0;
+       DSIGNSET(sf, sign);
+       return sf;
+}
+
+/*
+ * Return true if fp number is zero.
+ */
+int
+soft_isz(SF sf)
+{
+       return (DEXP(sf) == 0);
+}
+
+int
+soft_cmp_eq(SF x1, SF x2)
+{
+       cerror("soft_cmp_eq");
+       return 0;
+}
+
+int
+soft_cmp_ne(SF x1, SF x2)
+{
+       cerror("soft_cmp_ne");
+       return 0;
+}
+
+int
+soft_cmp_le(SF x1, SF x2)
+{
+       cerror("soft_cmp_le");
+       return 0;
+}
+
+int
+soft_cmp_lt(SF x1, SF x2)
+{
+       cerror("soft_cmp_lt");
+       return 0;
+}
+
+int
+soft_cmp_ge(SF x1, SF x2)
+{
+       cerror("soft_cmp_ge");
+       return 0;
+}
+
+int
+soft_cmp_gt(SF x1, SF x2)
+{
+       cerror("soft_cmp_gt");
+       return 0;
+}
+
+/*
+ * Convert a fp number to a CONSZ.
+ */
+CONSZ
+soft_val(SF sf)
+{
+       CONSZ mant;
+       int exp = DEXP(sf) - 128;
+
+       mant = SHL(1,55) | SHL(DMANTH(sf), 48) |
+            SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4;
+
+       while (exp < 0)
+               mant >>= 1, exp++;
+       while (exp > 0)
+               mant <<= 1, exp--;
+       return mant;
+}
+
+SF
+soft_plus(SF x1, SF x2)
+{
+       cerror("soft_plus");
+       return x1;
+}
+
+SF
+soft_minus(SF x1, SF x2)
+{
+       cerror("soft_minus");
+       return x1;
+}
+
+/*
+ * Convert a hex constant to floating point number.
+ */
+NODE *
+fhexcon(char *s)
+{
+       cerror("fhexcon");
+       return NULL;
+}
+
+/*
+ * Convert a floating-point constant to D-float and store it in a NODE.
+ */
+NODE *
+floatcon(char *s)
+{
+       NODE *p;
+       dword mant;
+       SF fl, flexp, exp5;
+       int exp, negexp, bexp;
+
+       exp = 0;
+       mant = 0;
+#define ADDTO(sum, val) sum = sum * 10 + val - '0'
+       for (; *s >= '0' && *s <= '9'; s++) {
+               if (mant<MAXMANT)
+                       ADDTO(mant, *s);
+               else
+                       exp++;
+       }
+       if (*s == '.') {
+               for (s++; *s >= '0' && *s <= '9'; s++) {
+                       if (mant<MAXMANT) {
+                               ADDTO(mant, *s);
+                               exp--;
+                       }
+               }
+       }
+
+       if ((*s == 'E') || (*s == 'e')) {
+               int eexp = 0, sign = 0;
+               s++;
+               if (*s == '+')
+                       s++;
+               else if (*s=='-')
+                       sign = 1, s++;
+
+               for (; *s >= '0' && *s <= '9'; s++)
+                       ADDTO(eexp, *s);
+               if (sign)
+                       eexp = -eexp;
+               exp = exp + eexp;
+       }
+
+       negexp = 1;
+       if (exp<0) {
+               negexp = -1;
+               exp = -exp;
+       }
+
+
+       flexp = soft_cast(1, INT);
+       exp5 = soft_cast(5, INT);
+       bexp = exp;
+       fl = soft_cast(mant, INT);
+
+       for (; exp; exp >>= 1) {
+               if (exp&01)
+                       flexp = soft_mul(flexp, exp5);
+               exp5 = soft_mul(exp5, exp5);
+       }
+       if (negexp<0)
+               fl = soft_div(fl, flexp);
+       else
+               fl = soft_mul(fl, flexp);
+
+       DEXPSET(fl, DEXP(fl) + negexp*bexp);
+       p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */
+       p->n_dcon = fl;
+       return p;
+}
+#else
+#error missing softfloat definition
+#endif
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/stabs.c b/lang/pcc/pcc/cc/ccom/stabs.c
new file mode 100644 (file)
index 0000000..51c745c
--- /dev/null
@@ -0,0 +1,458 @@
+/*     $Id: stabs.c,v 1.35 2015/09/15 20:01:10 ragge Exp $     */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Simple implementation of the "stabs" debugging format.
+ * Not complete but at least makes it possible to set breakpoints,
+ * examine simple variables and do stack traces.
+ * Based on the stabs documentation that follows gdb.
+ */
+
+#include "pass1.h"
+
+#ifdef STABS
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define        STABHASH        256
+#define        INTNUM          1       /* internal number of type "int" */
+#undef BIT2BYTE /* from external.h */
+#define        BIT2BYTE(x)     ((x)/SZCHAR)
+
+#ifndef STABLBL
+#error macdefs.h must define STABLBL
+#endif
+
+/* defines taken from BSD <stab.h> */
+#define N_GSYM          0x20    /* global symbol */
+#define N_FUN           0x24    /* procedure name */
+#define N_LCSYM         0x28    /* bss segment variable */
+#define N_RSYM          0x40    /* register variable */
+#define N_SLINE         0x44    /* text segment line number */
+#define N_SO            0x64    /* main source file name */
+#define N_LSYM          0x80    /* stack variable */
+#define N_SOL           0x84    /* included source file name */
+#define N_PSYM          0xa0    /* parameter variable */
+#define N_LBRAC         0xc0    /* left bracket */
+#define N_RBRAC         0xe0    /* right bracket */
+
+/*
+ * Local type mapping
+ * Types are defined as a typeword, a dimension pointer (in the case
+ * of arrays) and struct/union/enum declarations.
+ * Function prototypes are ignored.
+ */
+static struct stabtype {
+       struct stabtype *next;  /* linked list */
+       TWORD type;             /* pcc type number */
+       union dimfun *df;       /* dimension of arrays */
+       struct attr *ap;        /* struct/union/enum declarations */
+       int num;                /* local type number */
+} *stabhash[STABHASH];
+static int ntypes;
+static char *curfun;
+static int stablbl = 10;
+extern int inftn;
+
+void ptype(char *name, int num, int inhnum, long long min, long long max);
+struct stabtype *addtype(TWORD, union dimfun *, struct attr *);
+struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue);
+void printtype(struct symtab *s, char *str, int len);
+void cprint(int p2, char *fmt, ...);
+
+#define        MAXPSTR 100
+
+extern int isinlining;
+
+/*
+ * Output type definitions for the stab debugging format.
+ * Note that "int" is always internal number 1.
+ */
+void
+stabs_init(void)
+{
+       struct stabtype *st;
+
+#define        ADDTYPE(y) addtype(y, NULL, 0)
+
+       ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT);
+
+       st = ADDTYPE(CHAR);
+       ptype("char", st->num, st->num, 0, MAX_CHAR);
+       ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT);
+       ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG);
+       ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM,
+            MIN_LONGLONG, MAX_LONGLONG);
+       ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR);
+       ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT);
+       ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED);
+       ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG);
+       ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM,
+           0, MAX_ULONGLONG);
+
+       ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0);
+       ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0);
+       ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0);
+       st = ADDTYPE(VOID);
+       cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n",
+           st->num, st->num, N_LSYM);
+
+}
+
+/*
+ * Print a type in stabs format
+ */
+void
+ptype(char *name, int num, int inhnum, long long min, long long max)
+{
+       cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n",
+           name, num, inhnum, min, max, N_LSYM);
+}
+
+/*
+ * Add a new local type to the hash table.
+ * The search key is the (type, df, sue) triple.
+ */
+struct stabtype *
+addtype(TWORD t, union dimfun *df, struct attr *ap)
+{
+       struct stabtype *st;
+
+       st = permalloc(sizeof(struct stabtype));
+       st->type = t;
+       st->df = df;
+       st->ap = ap;
+       st->num = ++ntypes;
+       st->next = stabhash[t & (STABHASH-1)];
+       stabhash[t & (STABHASH-1)] = st;
+       return st;
+}
+
+/*
+ * Search for a given type and return a type pointer (or NULL).
+ */
+struct stabtype *
+findtype(TWORD t, union dimfun *df, struct attr *ap)
+{
+       struct stabtype *st;
+       union dimfun *dw, *dx;
+       TWORD tw;
+
+       st = stabhash[t & (STABHASH-1)];
+       for (; st; st = st->next) {
+               if (t != st->type || ap != st->ap)
+                       continue;
+               /* Ok, type and sue matches, check dimensions */
+               if (st->df == NULL)
+                       return st; /* no arrays, got match */
+               dw = st->df;
+               dx = df;
+               tw = t;
+               for (; tw > BTMASK; tw = DECREF(tw)) {
+                       if (ISARY(tw)) {
+                               if (dw->ddim == dx->ddim)
+                                       dw++, dx++;
+                               else
+                                       break;
+                       }
+               }
+               if (tw <= BTMASK)
+                       return st;
+       }
+       return NULL;
+}
+
+/*
+ * Print current line number.
+ */
+void
+stabs_line(int line)
+{
+       if (inftn == 0)
+               return; /* ignore */
+#ifdef STAB_LINE_ABSOLUTE
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+           N_SLINE, line, stablbl, stablbl);
+#else
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+           N_SLINE, line, stablbl, curfun, stablbl);
+#endif
+       stablbl++;
+}
+
+/*
+ * Start of block.
+ */
+void
+stabs_lbrac(int blklvl)
+{
+#ifdef STAB_LINE_ABSOLUTE
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+           N_LBRAC, blklvl, stablbl, stablbl);
+#else
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+           N_LBRAC, blklvl, stablbl, curfun, stablbl);
+#endif
+       stablbl++;
+}
+
+/*
+ * End of block.
+ */
+void
+stabs_rbrac(int blklvl)
+{
+#ifdef STAB_LINE_ABSOLUTE
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+           N_RBRAC, blklvl, stablbl, stablbl);
+#else
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+           N_RBRAC, blklvl, stablbl, curfun, stablbl);
+#endif
+       stablbl++;
+}
+
+static char *mainfile;
+
+/*
+ * Print current file and set mark.
+ */
+void
+stabs_file(char *fname)
+{
+       if (mainfile == NULL)
+               mainfile = fname; /* first call */
+       cprint(inftn, "\t.stabs \"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+           fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+       stablbl++;
+}
+
+/*
+ * Print end mark
+ */
+void
+stabs_efile(char *fname)
+{
+       cprint(inftn, "\t.stabs \"\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+           fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+       stablbl++;
+}
+
+/*
+ * Print beginning of function.
+ */
+void
+stabs_func(struct symtab *s)
+{
+       char str[MAXPSTR];
+
+       curfun = getexname(s);
+       printtype(s, str, sizeof(str));
+       cprint(1, "\t.stabs     \"%s:%c%s\",%d,0,%d,%s\n",
+           curfun, s->sclass == STATIC ? 'f' : 'F', str,
+           N_FUN, 0, curfun);
+}
+
+/*
+ * Print a (complex) type.
+ * Will also create subtypes.
+ * Printed string is like "20=*21=*1".
+ */
+void
+printtype(struct symtab *s, char *ostr, int len)
+{
+       struct stabtype *st;
+       union dimfun *df = s->sdf;
+       struct attr *ap = s->sap;
+       TWORD t = s->stype;
+       int op = 0;
+
+       /* Print out not-yet-found types */
+       if (ISFTN(t))
+               t = DECREF(t);
+       st = findtype(t, df, ap);
+       while (st == NULL && t > BTMASK) {
+               st = addtype(t, df, ap);
+               op+=snprintf(ostr+op, len - op, "%d=", st->num);
+               if (ISFTN(t))
+                       ostr[op++] = 'f';
+               else if (ISPTR(t))
+                       ostr[op++] = '*';
+               else if (ISARY(t)) {
+                       op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1);
+               } else
+                       cerror("printtype: notype");
+               if (ISARY(t))
+                       df++;
+               t = DECREF(t);
+               st = findtype(t, df, ap);
+               if (op > MAXPSTR-10)
+                       cerror("printtype: too difficult expression");
+       }
+       /* print out basic type. may have to be entered in case of sue */
+       snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num);
+       /* snprintf here null-terminated the string */
+}
+
+void
+stabs_newsym(struct symtab *s)
+{
+       extern int fun_inline;
+       char *sname;
+       char ostr[MAXPSTR];
+       OFFSZ suesize, sz;
+
+       if (ISFTN(s->stype))
+               return; /* functions are handled separate */
+
+       if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS ||
+           s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE ||
+           s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype))
+               return; /* XXX - fix structs */
+
+       sname = getexname(s);
+       sz = tsize(s->stype, s->sdf, s->sap);
+       suesize = BIT2BYTE(sz);
+       if (suesize > 32767)
+               suesize = 32767;
+       else if (suesize < -32768)
+               suesize = -32768;
+
+       printtype(s, ostr, sizeof(ostr));
+       switch (s->sclass) {
+       case PARAM:
+               cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n",
+                   sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
+               break;
+
+       case AUTO:
+               cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n",
+                   sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
+               break;
+
+       case STATIC:
+               if (blevel)
+                       cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n",
+                           sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset);
+               else
+                       cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n",
+                           sname, ostr, N_LCSYM, (CONSZ)suesize, sname);
+               break;
+
+       case EXTERN:
+       case EXTDEF:
+               cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n",
+                   sname, ostr, N_GSYM, (CONSZ)suesize);
+               break;
+
+       case REGISTER:
+               cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n",
+                   sname, ostr, N_RSYM, 1, s->soffset);
+               break;
+
+       case SNULL:
+               if (fun_inline)
+                       break;
+               /* FALLTHROUGH */
+       default:
+               cerror("fix stab_newsym; class %d", s->sclass);
+       }
+}
+
+void
+stabs_chgsym(struct symtab *s)
+{
+}
+
+/*
+ * define a struct.
+ */
+void
+stabs_struct(struct symtab *p, struct attr *ap)
+{
+}
+
+struct stabsv {
+       SLIST_ENTRY(stabsv) next;
+       char *str;
+} ;
+static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw };
+
+/*
+ * Global variable debug info is printed out directly.
+ * For functions and their declarations, both the labels and 
+ * the debug info is put into ASM nodes and follows their statements
+ * into pass2.  
+ * Due to the possible unsync between pass1 and 2 and where the 
+ * stabs info for text is sent over the following syncing is used:
+ * curfun == 0
+ *     print out everything; only data will be.
+ * curfun != 0 && inftn == 0
+ *     save in linked list
+ * curfun != 0 && inftn != 0
+ *     print linked list first, empty it, then arg.
+ */
+void
+cprint(int p2, char *fmt, ...)
+{
+#define        CPBSZ   200
+       char buf[CPBSZ];
+       struct stabsv *w;
+       va_list ap;
+       char *str;
+
+       if (isinlining)
+               return; /* XXX do not save any inline functions currently */
+
+       va_start(ap, fmt);
+       if (p2) {
+               if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ)
+                       werror("stab symbol line too long, truncating");
+               str = tmpstrdup(buf);
+               if (inftn == 0) {
+                       w = tmpalloc(sizeof(struct stabsv));
+                       w->str = str;
+                       SLIST_INSERT_LAST(&stpole, w, next);
+               } else {
+                       if (stpole.q_last != &stpole.q_forw) {
+                               SLIST_FOREACH(w, &stpole, next) {
+                                       send_passt(IP_ASM, w->str);
+                               }
+                               SLIST_INIT(&stpole);
+                       }
+                       send_passt(IP_ASM, str);
+               }
+       } else
+               vprintf(fmt, ap);
+       va_end(ap);
+}
+
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/symtabs.c b/lang/pcc/pcc/cc/ccom/symtabs.c
new file mode 100644 (file)
index 0000000..d3a5e91
--- /dev/null
@@ -0,0 +1,660 @@
+/*     $Id: symtabs.c,v 1.38 2015/09/15 20:01:10 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+#include "unicode.h"
+#include <stdlib.h>
+
+#define        NODE P1ND
+#define        fwalk p1fwalk
+
+/*
+ * These definitions are used in the patricia tree that stores
+ * the strings.
+ */
+#define        LEFT_IS_LEAF            0x80000000
+#define        RIGHT_IS_LEAF           0x40000000
+#define        IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
+#define        IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
+#define        BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
+#define        CHECKBITS               8
+
+struct tree {
+       int bitno;
+       struct tree *lr[2];
+};
+
+extern int dimfuncnt;
+static struct tree *firstname;
+int nametabs, namestrlen;
+static struct tree *firststr;
+int strtabs, strstrlen, symtreecnt;
+static char *symtab_add(char *key, struct tree **, int *, int *);
+int lastloc = NOSEG;
+int treestrsz = sizeof(struct tree);
+
+#define        P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
+#define        getree() permalloc(sizeof(struct tree))
+
+char *
+addname(char *key)      
+{
+       return symtab_add(key, &firstname, &nametabs, &namestrlen);
+}
+
+char *
+addstring(char *key)
+{
+       return symtab_add(key, &firststr, &strtabs, &strstrlen);
+}
+
+/*
+ * Add a name to the name stack (if its non-existing),
+ * return its address.
+ * This is a simple patricia implementation.
+ */
+static char *
+symtab_add(char *key, struct tree **first, int *tabs, int *stlen)
+{
+       struct tree *w, *new, *last;
+       int cix, bit, fbit, svbit, ix, bitno, len;
+       char *m, *k, *sm;
+
+       /* Count full string length */
+       for (k = key, len = 0; *k; k++, len++)
+               ;
+       
+       switch (*tabs) {
+       case 0:
+               *first = (struct tree *)newstring(key, len);
+               *stlen += (len + 1);
+               (*tabs)++;
+               return (char *)*first;
+
+       case 1:
+               m = (char *)*first;
+               svbit = 0; /* XXX why? */
+               break;
+
+       default:
+               w = *first;
+               bitno = len * CHECKBITS;
+               for (;;) {
+                       bit = BITNO(w->bitno);
+                       fbit = bit > bitno ? 0 : P_BIT(key, bit);
+                       svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+                           IS_LEFT_LEAF(w->bitno);
+                       w = w->lr[fbit];
+                       if (svbit) {
+                               m = (char *)w;
+                               break;
+                       }
+               }
+       }
+
+       sm = m;
+       k = key;
+
+       /* Check for correct string and return */
+       for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
+               ;
+       if (*m == 0 && *k == 0)
+               return sm;
+
+       ix = *m ^ *k;
+       while ((ix & 1) == 0)
+               ix >>= 1, cix++;
+
+       /* Create new node */
+       new = getree();
+       bit = P_BIT(key, cix);
+       new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       new->lr[bit] = (struct tree *)newstring(key, len);
+       *stlen += (len + 1);
+
+       if ((*tabs)++ == 1) {
+               new->lr[!bit] = *first;
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+               *first = new;
+               return (char *)new->lr[bit];
+       }
+
+
+       w = *first;
+       last = NULL;
+       for (;;) {
+               fbit = w->bitno;
+               bitno = BITNO(w->bitno);
+               if (bitno == cix)
+                       cerror("bitno == cix");
+               if (bitno > cix)
+                       break;
+               svbit = P_BIT(key, bitno);
+               last = w;
+               w = w->lr[svbit];
+               if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+                       break;
+       }
+
+       new->lr[!bit] = w;
+       if (last == NULL) {
+               *first = new;
+       } else {
+               last->lr[svbit] = new;
+               last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       }
+       if (bitno < cix)
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+       return (char *)new->lr[bit];
+}
+
+static struct tree *sympole[NSTYPES];
+static struct symtab *tmpsyms[NSTYPES];
+int numsyms[NSTYPES];
+
+/*
+ * Inserts a symbol into the symbol tree.
+ * Returns a struct symtab.
+ */
+struct symtab *
+lookup(char *key, int stype)
+{
+       struct symtab *sym;
+       struct tree *w, *new, *last;
+       int cix, bit, fbit, svbit, bitno;
+       int type, uselvl;
+       intptr_t ix, match, code = (intptr_t)key;
+
+       type = stype & SMASK;
+       uselvl = (blevel > 0 && type != SSTRING);
+
+       /*
+        * The local symbols are kept in a simple linked list.
+        * Check this list first.
+        */
+       if (blevel > 0)
+               for (sym = tmpsyms[type]; sym; sym = sym->snext)
+                       if (sym->sname == key)
+                               return sym;
+
+       switch (numsyms[type]) {
+       case 0:
+               if (stype & SNOCREAT)
+                       return NULL;
+               if (uselvl) {
+                       if (type == SNORMAL)
+                               stype |= SBLK;
+                       sym = getsymtab(key, stype);
+                       sym->snext = tmpsyms[type];
+                       tmpsyms[type] = sym;
+                       return sym;
+               }
+               sympole[type] = (struct tree *)getsymtab(key, stype);
+               numsyms[type]++;
+               return (struct symtab *)sympole[type];
+
+       case 1:
+               w = (struct tree *)sympole[type];
+               svbit = 0; /* XXX why? */
+               break;
+
+       default:
+               w = sympole[type];
+               for (;;) {
+                       bit = BITNO(w->bitno);
+                       fbit = (code >> bit) & 1;
+                       svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+                           IS_LEFT_LEAF(w->bitno);
+                       w = w->lr[fbit];
+                       if (svbit)
+                               break;
+               }
+       }
+
+       sym = (struct symtab *)w;
+       match = (intptr_t)sym->sname;
+
+       ix = code ^ match;
+       if (ix == 0)
+               return sym;
+       else if (stype & SNOCREAT)
+               return NULL;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("        adding %s as %s at level %d\n",
+                   key, uselvl ? "temp" : "perm", blevel);
+#endif
+
+       /*
+        * Insert into the linked list, if feasible.
+        */
+       if (uselvl) {
+               sym = getsymtab(key, stype|STEMP);
+               sym->snext = tmpsyms[type];
+               tmpsyms[type] = sym;
+               return sym;
+       }
+
+       /*
+        * Need a new node. If type is SNORMAL and inside a function
+        * the node must be allocated as permanent anyway.
+        * This could be optimized by adding a remove routine, but it
+        * may be more trouble than it is worth.
+        */
+       if (stype == (STEMP|SNORMAL))
+               stype = SNORMAL;
+
+       for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++)
+               ;
+
+       new = (symtreecnt++, permalloc(sizeof(struct tree)));
+       bit = (code >> cix) & 1;
+       new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       new->lr[bit] = (struct tree *)getsymtab(key, stype);
+       if (numsyms[type]++ == 1) {
+               new->lr[!bit] = sympole[type];
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+               sympole[type] = new;
+               return (struct symtab *)new->lr[bit];
+       }
+
+
+       w = sympole[type];
+       last = NULL;
+       for (;;) {
+               fbit = w->bitno;
+               bitno = BITNO(w->bitno);
+               if (bitno == cix)
+                       cerror("bitno == cix");
+               if (bitno > cix)
+                       break;
+               svbit = (code >> bitno) & 1;
+               last = w;
+               w = w->lr[svbit];
+               if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+                       break;
+       }
+
+       new->lr[!bit] = w;
+       if (last == NULL) {
+               sympole[type] = new;
+       } else {
+               last->lr[svbit] = new;
+               last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       }
+       if (bitno < cix)
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+       return (struct symtab *)new->lr[bit];
+}
+
+void
+symclear(int level)
+{
+       struct symtab *s;
+       int i;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("symclear(%d)\n", level);
+#endif
+       if (level < 1) {
+               for (i = 0; i < NSTYPES; i++) {
+                       s = tmpsyms[i];
+                       tmpsyms[i] = 0;
+                       if (i != SLBLNAME)
+                               continue;
+                       while (s != NULL) {
+                               if (s->soffset < 0)
+                                       uerror("label '%s' undefined",s->sname);
+                               s = s->snext;
+                       }
+               }
+       } else {
+               for (i = 0; i < NSTYPES; i++) {
+                       if (i == SLBLNAME)
+                               continue; /* function scope */
+                       while (tmpsyms[i] != NULL &&
+                           tmpsyms[i]->slevel > level) {
+                               tmpsyms[i] = tmpsyms[i]->snext;
+                       }
+               }
+       }
+}
+
+struct symtab *
+hide(struct symtab *sym)
+{
+       struct symtab *new;
+       int typ = sym->sflags & SMASK;
+
+       new = getsymtab(sym->sname, typ|STEMP);
+       new->snext = tmpsyms[typ];
+       tmpsyms[typ] = new;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("\t%s hidden at level %d (%p -> %p)\n",
+                   sym->sname, blevel, sym, new);
+#endif
+       return new;
+}
+
+/*
+ * Extract correct segment for the specified symbol and call
+ * target routines to print it out.
+ * If symtab entry is specified, output alignment as well.
+ */
+void
+locctr(int seg, struct symtab *sp)
+{
+#ifdef GCC_COMPAT
+       struct attr *ga;
+#endif
+
+       if (seg == NOSEG) {
+               ;
+       } else if (sp == NULL) {
+               if (lastloc != seg)
+                       setseg(seg, NULL);
+#ifdef GCC_COMPAT
+       } else if ((ga = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL) {
+               setseg(NMSEG, ga->sarg(0));
+               seg = NOSEG;
+#endif
+       } else {
+               if (seg == DATA) {
+                       if (ISCON(cqual(sp->stype, sp->squal)))
+                               seg = RDATA;
+                       else if (sp->sclass == STATIC)
+                               seg = LDATA;
+               }
+               if (sp->sflags & STLS) {
+                       if (seg == DATA || seg == LDATA)
+                               seg = TLSDATA;
+                       if (seg == UDATA) seg = TLSUDATA;
+               } else if (kflag) {
+                       if (seg == DATA) seg = PICDATA;
+                       if (seg == RDATA) seg = PICRDATA;
+                       if (seg == LDATA) seg = PICLDATA;
+               }
+               if (lastloc != seg)
+                       setseg(seg, NULL);
+       }
+       lastloc = seg;
+
+       /* setup alignment */
+#ifndef ALFTN
+#define        ALFTN   ALINT
+#endif
+       if (sp) {
+               int al;
+
+               if (ISFTN(sp->stype)) {
+                       al = ALFTN;
+               } else
+                       al = talign(sp->stype, sp->sap);
+               defalign(al);
+               symdirec(sp);
+       }
+}
+
+#ifndef MYALIGN
+void
+defalign(int al)
+{
+#ifdef HASP2ALIGN
+#define        P2ALIGN(x)      ispow2(x)
+#else
+#define        P2ALIGN(x)      (x)
+#endif
+       if (al != ALCHAR)
+               printf(PRTPREF "\t.align %d\n", P2ALIGN(al/ALCHAR));
+}
+#endif
+
+#ifndef MYDIREC
+/*
+ * Directives given as attributes to symbols.
+ */
+void
+symdirec(struct symtab *sp)
+{
+#ifdef GCC_COMPAT
+       struct attr *ga;
+       char *name;
+
+       name = getexname(sp);
+       if ((ga = attr_find(sp->sap, GCC_ATYP_WEAK)) != NULL)
+               printf(PRTPREF "\t.weak %s\n", name);
+       if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
+           strcmp(ga->sarg(0), "default"))
+               printf(PRTPREF "\t.%s %s\n", ga->sarg(0), name);
+       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIASWEAK))) {
+               printf(PRTPREF "\t.weak %s\n", ga->sarg(0));
+               printf(PRTPREF "\t.set %s,%s\n", ga->sarg(0), name);
+       }
+#endif
+}
+#endif
+
+char *
+getexname(struct symtab *sp)
+{
+       struct attr *ap = attr_find(sp->sap, ATTR_SONAME);
+
+       return (ap ? ap->sarg(0) : addname(exname(sp->sname)));
+}
+
+static char *csbuf;
+static int csbufp, cssz, strtype;
+#ifndef NO_STRING_SAVE
+static struct symtab *strpole;
+#endif
+#define        STCHNK  128
+
+static void
+savch(int ch)
+{
+       if (csbufp == cssz) {
+               cssz += STCHNK;
+               csbuf = realloc(csbuf, cssz);
+       }
+       csbuf[csbufp++] = ch;
+}
+
+/*
+ * save value as 3-digit octal escape sequence
+ */
+static void
+voct(unsigned int v)
+{
+       savch('\\');
+       savch(((v & 0700) >> 6) + '0');
+       savch(((v & 0070) >> 3) + '0');
+       savch((v & 0007) + '0');
+}
+
+
+/*
+ * Add string new to string old.  
+ * String new must come directly after old.
+ * new is expected to be utf-8.  Will be cleaned slightly here.
+ */
+char *
+stradd(char *old, char *new)
+{
+       if (old == NULL) {
+               strtype = 0;
+               csbufp = 0;
+       } else if (old != csbuf)
+               cerror("string synk error");
+
+       /* special hack for function names */
+       for (old = new; *old; old++)
+               ;
+       if (old[-1] != '\"') {
+               do {
+                       savch(*new);
+               } while (*new++);
+               return csbuf;
+       }
+
+       if (*new != '\"') {
+               int ny = *new++;
+               if (ny == 'u' && *new == '8')
+                       ny = '8', new++;
+               if (strtype && ny != strtype)
+                       uerror("clash in string types");
+               strtype = ny;
+       }
+       if (*new++ != '\"')
+               cerror("snuff synk error");
+
+       while (*new != '\"') {
+               if (*new == '\\') {
+                       voct(esccon(&new));
+               } else if (*new < ' ' || *new > '~') {
+                       voct(*(unsigned char *)new++);
+               } else {
+                       savch(*new++);
+               }
+       }
+       savch(0);
+       csbufp--;
+       return csbuf;
+}
+
+TWORD
+styp(void)
+{
+       TWORD t;
+
+       if (strtype == 0 || strtype == '8')
+               t = xuchar ? UCHAR+ARY : CHAR+ARY;
+       else if (strtype == 'u')
+               t = ctype(USHORT)+ARY;
+       else if (strtype == 'L')
+               t = WCHAR_TYPE+ARY;
+       else
+               t = ctype(SZINT < 32 ? ULONG : UNSIGNED)+ARY;
+       return t;
+}
+
+/*
+ * Create a string struct.
+ */
+static void
+strst(struct symtab *sp, TWORD t)
+{
+       char *wr;
+       int i;
+
+       sp->sclass = STATIC;
+       sp->slevel = 1;
+       sp->soffset = getlab();
+       sp->squal = (CON >> TSHIFT);
+#ifndef NO_STRING_SAVE
+       sp->sdf = permalloc(sizeof(union dimfun));
+#else
+       sp->sdf = stmtalloc(sizeof(union dimfun));
+#endif
+       dimfuncnt++;
+       sp->stype = t;
+
+       for (wr = sp->sname, i = 1; *wr; i++) {
+               if (strtype == 'L' || strtype == 'U' || strtype == 'u')
+                       (void)u82cp(&wr);
+               else if (*wr == '\\')
+                       (void)esccon(&wr);
+               else
+                       wr++;
+       }
+       sp->sdf->ddim = i;
+#ifndef NO_STRING_SAVE
+       sp->snext = strpole;
+       strpole = sp;
+#endif
+}
+
+/*
+ * Save string (if needed) and return NODE for it.
+ * String is already in utf-8 format.
+ */
+NODE *
+strend(char *s, TWORD t)
+{
+       struct symtab *sp, *sp2;
+       NODE *p;
+
+#ifdef NO_STRING_SAVE
+       sp = getsymtab(s, SSTRING|SSTMT);
+#else
+       s = addstring(s);
+       sp = lookup(s, SSTRING);
+#endif
+
+       if (sp->soffset && sp->stype != t) {
+               /* same string stored but different type */
+               /* This is uncommon, create a new symtab struct for it */
+               sp2 = permalloc(sizeof(*sp));
+               *sp2 = *sp;
+               strst(sp2, t);
+               sp = sp2;
+       } else if (sp->soffset == 0) { /* No string */
+               strst(sp, t);
+       }
+       if (cssz > STCHNK) {
+               cssz = STCHNK;
+               csbuf = realloc(csbuf, cssz);
+       }
+#ifdef NO_STRING_SAVE
+       instring(sp);
+#endif
+       p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+       p->n_sp = sp;
+       return(clocal(p));
+}
+
+#ifndef NO_STRING_SAVE
+/*
+ * Print out strings that have been referenced.
+ */
+void
+strprint(void)
+{
+       struct symtab *sp;
+
+       for (sp = strpole; sp; sp = sp->snext) {
+               if ((sp->sflags & SASG) == 0)
+                       continue; /* not referenced */
+               instring(sp);
+       }
+}
+#endif
diff --git a/lang/pcc/pcc/cc/ccom/trees.c b/lang/pcc/pcc/cc/ccom/trees.c
new file mode 100644 (file)
index 0000000..e7edeba
--- /dev/null
@@ -0,0 +1,3568 @@
+/*     $Id: trees.c,v 1.373 2016/03/05 15:49:36 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Some of the changes from 32V include:
+ * - Understand "void" as type.
+ * - Handle enums as ints everywhere.
+ * - Convert some C-specific ops into branches.
+ */
+
+# include "pass1.h"
+# include "pass2.h"
+
+# include <stdarg.h>
+# include <string.h>
+# include <stdlib.h>
+
+static void chkpun(P1ND *p);
+static int opact(P1ND *p);
+static int moditype(TWORD);
+static P1ND *strargs(P1ND *);
+static void rmcops(P1ND *p);
+static P1ND *tymatch(P1ND *p);
+static P1ND *rewincop(P1ND *p1, P1ND *p2, int op);
+static int has_se(P1ND *p);
+static struct symtab *findmember(struct symtab *, char *);
+int inftn; /* currently between epilog/prolog */
+P1ND *cstknode(TWORD t, union dimfun *df, struct attr *ap);
+
+static char *tnames[] = {
+       "undef",
+       "farg",
+       "char",
+       "unsigned char",
+       "short",
+       "unsigned short",
+       "int",
+       "unsigned int",
+       "long",
+       "unsigned long",
+       "long long",
+       "unsigned long long",
+       "float",
+       "double",
+       "long double",
+       "strty",
+       "unionty",
+       "enumty",
+       "moety",
+       "void",
+       "signed", /* pass1 */
+       "bool", /* pass1 */
+       "fimag", /* pass1 */
+       "dimag", /* pass1 */
+       "limag", /* pass1 */
+       "fcomplex", /* pass1 */
+       "dcomplex", /* pass1 */
+       "lcomplex", /* pass1 */
+       "enumty", /* pass1 */
+       "?", "?"
+};
+
+/*     some special actions, used in finding the type of nodes */
+# define NCVT 01
+# define PUN 02
+# define TYPL 04
+# define TYPR 010
+# define TYMATCH 040
+# define LVAL 0100
+# define CVTO 0200
+# define CVTL 0400
+# define CVTR 01000
+# define PTMATCH 02000
+# define OTHER 04000
+# define NCVTR 010000
+# define PROML 020000  /* promote left operand */
+
+/* node conventions:
+
+       NAME:   rval>0 is stab index for external
+               rval<0 is -inlabel number
+               lval is offset in bits
+       ICON:   lval has the value
+               rval has the STAB index, or - label number,
+                       if a name whose address is in the constant
+               rval = NONAME means no name
+       REG:    rval is reg. identification cookie
+
+       */
+
+/* negatives of relationals */
+int p1negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE };
+
+/* Have some defaults for most common targets */
+#ifndef WORD_ADDRESSED
+#define        offcon(o,t,d,ap) xbcon((o/SZCHAR), NULL, INTPTR)
+#define        VBLOCK(p,b,t,d,a) buildtree(DIV, p, b)
+#define        MBLOCK(p,b,t,d,a) buildtree(MUL, p, b)
+#else
+#define        VBLOCK(p,b,t,d,a) block(PVCONV, p, b, t, d, a)
+#define        MBLOCK(p,b,t,d,a) block(PMCONV, p, b, t, d, a)
+#endif
+
+P1ND *
+buildtree(int o, P1ND *l, P1ND *r)
+{
+       P1ND *p, *q;
+       int actions;
+       int opty, n;
+       struct symtab *sp = NULL; /* XXX gcc */
+       P1ND *lr, *ll;
+
+#ifdef PCC_DEBUG
+       if (bdebug) {
+               printf("buildtree(%s, %p, %p)\n", copst(o), l, r);
+               if (l) p1fwalk(l, eprint, 0);
+               if (r) p1fwalk(r, eprint, 0);
+       }
+#endif
+       opty = coptype(o);
+
+       /* check for constants */
+
+       if (o == ANDAND || o == OROR || o == NOT) {
+               if (l->n_op == FCON) {
+                       p = bcon(!FLOAT_ISZERO(l->n_dcon));
+                       p1nfree(l);
+                       l = p;
+               }
+               if (o != NOT && r->n_op == FCON) {
+                       p = bcon(!FLOAT_ISZERO(r->n_dcon));
+                       p1nfree(r);
+                       r = p;
+               }
+       }
+
+       if( opty == UTYPE && l->n_op == ICON ){
+
+               switch( o ){
+
+               case NOT:
+               case UMINUS:
+               case COMPL:
+                       if( conval( l, o, l ) ) return(l);
+                       break;
+               }
+       } else if (o == NOT && l->n_op == FCON) {
+               l = clocal(block(SCONV, l, NULL, INT, 0, 0));
+       } else if( o == UMINUS && l->n_op == FCON ){
+                       FLOAT_NEG(l->n_dcon);
+                       return(l);
+
+       } else if( o==QUEST &&
+           (l->n_op==ICON || (l->n_op==NAME && ISARY(l->n_type)))) {
+               CONSZ c = glval(l);
+               if (l->n_op==NAME)
+                       c = 1; /* will become constant later */
+               p1nfree(l);
+               if (c) {
+                       p1walkf(r->n_right, putjops, 0);
+                       p1tfree(r->n_right);
+                       l = r->n_left;
+               } else {
+                       p1walkf(r->n_left, putjops, 0);
+                       p1tfree(r->n_left);
+                       l = r->n_right;
+               }
+               p1nfree(r);
+               return(l);
+       } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){
+
+               switch( o ){
+
+               case PLUS:
+               case MINUS:
+               case MUL:
+               case DIV:
+               case MOD:
+                       /*
+                        * Do type propagation for simple types here.
+                        * The constant value is correct anyway.
+                        * Maybe this op shortcut should be removed?
+                        */
+                       if (l->n_sp == NULL && r->n_sp == NULL &&
+                           l->n_type < BTMASK && r->n_type < BTMASK) {
+                               if (l->n_type > r->n_type)
+                                       r->n_type = l->n_type;
+                               else
+                                       l->n_type = r->n_type;
+                       }
+                       /* FALLTHROUGH */
+               case ULT:
+               case UGT:
+               case ULE:
+               case UGE:
+               case LT:
+               case GT:
+               case LE:
+               case GE:
+               case EQ:
+               case NE:
+               case ANDAND:
+               case OROR:
+               case AND:
+               case OR:
+               case ER:
+               case LS:
+               case RS:
+                       if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) {
+                               if( conval( l, o, r ) ) {
+                                       p1nfree(r);
+                                       return(l);
+                               }
+                       }
+                       break;
+               }
+       } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) &&
+           (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS ||
+           o == MUL || o == DIV || (o >= EQ && o <= GT) )) {
+               /* at least one side is FCON */
+
+#ifndef CC_DIV_0
+               if (o == DIV &&
+                   ((r->n_op == ICON && glval(r) == 0) ||
+                    (r->n_op == FCON && FLOAT_EQ(r->n_dcon, FLOAT_ZERO))))
+                               goto runtime; /* HW dependent */
+#endif
+               if (l->n_op == ICON) {
+                       if (!concast(l, r->n_type))
+                               cerror("fail cast const");
+               } else if (r->n_op == ICON) {
+                       if (!concast(r, l->n_type))
+                               cerror("fail cast const");
+               }
+
+               switch(o){
+               case PLUS:
+               case MINUS:
+               case MUL:
+               case DIV:
+                       switch (o) {
+                       case PLUS:
+                               FLOAT_PLUS(l, r);
+                               break;
+                       case MINUS:
+                               FLOAT_MINUS(l, r);
+                               break;
+                       case MUL:
+                               FLOAT_MUL(l, r);
+                               break;
+                       case DIV:
+                               FLOAT_DIV(l, r);
+                               break;
+                       }
+                       p1nfree(r);
+                       return(l);
+               case EQ:
+               case NE:
+               case LE:
+               case LT:
+               case GE:
+               case GT:
+                       switch (o) {
+                       case EQ:
+                               n = FLOAT_EQ(l->n_dcon, r->n_dcon);
+                               break;
+                       case NE:
+                               n = FLOAT_NE(l->n_dcon, r->n_dcon);
+                               break;
+                       case LE:
+                               n = FLOAT_LE(l->n_dcon, r->n_dcon);
+                               break;
+                       case LT:
+                               n = FLOAT_LT(l->n_dcon, r->n_dcon);
+                               break;
+                       case GE:
+                               n = FLOAT_GE(l->n_dcon, r->n_dcon);
+                               break;
+                       case GT:
+                               n = FLOAT_GT(l->n_dcon, r->n_dcon);
+                               break;
+                       default:
+                               n = 0; /* XXX flow analysis */
+                       }
+                       p1nfree(r);
+                       p1nfree(l);
+                       return bcon(n);
+               }
+       } else if ((cdope(o)&ASGOPFLG) && o != RETURN && o != CAST) {
+               if (l->n_op == SCONV && l->n_left->n_op == FLD)
+                       l = p1nfree(l);
+               /*
+                * Handle side effects by storing address in temporary q.
+                * Side effect nodes always have an UMUL.
+                */
+               if (has_se(l)) {
+                       ll = l->n_left;
+
+                       q = cstknode(ll->n_type, ll->n_df, ll->n_ap);
+                       l->n_left = p1tcopy(q);
+                       q = buildtree(ASSIGN, q, ll);
+               } else 
+                       q = bcon(0); /* No side effects */
+
+               /*
+                * Modify the trees so that the compound op is rewritten.
+                */
+               /* avoid casting of LHS */
+               if ((cdope(o) & SIMPFLG) && ISINTEGER(l->n_type) && 
+                   l->n_type != BOOL) 
+                       r = ccast(r, l->n_type, l->n_qual, l->n_df, l->n_ap);
+
+               r = buildtree(UNASG o, p1tcopy(l), r);
+               r = buildtree(ASSIGN, l, r);
+               l = q;
+               o = COMOP;
+       } else if (o == INCR || o == DECR) {
+               if (l->n_op == SCONV && l->n_left->n_op == FLD)
+                       l = p1nfree(l);
+               /*
+                * Rewrite to (t=d,d=d+1,t)
+                */
+               if (has_se(l)) {
+                       ll = l->n_left;
+
+                       q = cstknode(ll->n_type, ll->n_df, ll->n_ap);
+                       l->n_left = p1tcopy(q);
+                       q = buildtree(ASSIGN, q, ll);
+               } else 
+                       q = bcon(0); /* No side effects */
+
+               /* Boolean has special syntax. */
+               if (l->n_type == BOOL) {
+                       r = rewincop(l, r, o == INCR ? ASSIGN : EREQ);
+               } else
+                       r = rewincop(l, r, o == INCR ? PLUSEQ : MINUSEQ);
+               l = q;
+               o = COMOP;
+       } else if (o == ASSIGN && l->n_op == SCONV && l->n_left->n_op == FLD) {
+               l = p1nfree(l);
+       }
+
+
+#ifndef CC_DIV_0
+runtime:
+#endif
+       /* its real; we must make a new node */
+
+       p = block(o, l, r, INT, 0, 0);
+
+       actions = opact(p);
+
+       if (actions & PROML)
+               p->n_left = intprom(p->n_left);
+
+       if (actions & LVAL) { /* check left descendent */
+               if (notlval(p->n_left)) {
+                       uerror("lvalue required");
+                       p1nfree(p);
+                       return l;
+#ifdef notyet
+               } else {
+                       if ((l->n_type > BTMASK && ISCON(l->n_qual)) ||
+                           (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT)))
+                               if (blevel > 0)
+                                       uerror("lvalue is declared const");
+#endif
+               }
+       }
+
+       if( actions & NCVTR ){
+               p->n_left = pconvert( p->n_left );
+               }
+       else if( !(actions & NCVT ) ){
+               switch( opty ){
+
+               case BITYPE:
+                       p->n_right = pconvert( p->n_right );
+                       /* FALLTHROUGH */
+               case UTYPE:
+                       p->n_left = pconvert( p->n_left );
+
+                       }
+               }
+
+       if ((actions&PUN) && (o!=CAST))
+               chkpun(p);
+
+       if( actions & (TYPL|TYPR) ){
+
+               q = (actions&TYPL) ? p->n_left : p->n_right;
+
+               p->n_type = q->n_type;
+               p->n_qual = q->n_qual;
+               p->n_df = q->n_df;
+               p->n_ap = q->n_ap;
+               }
+
+       if( actions & CVTL ) p = convert( p, CVTL );
+       if( actions & CVTR ) p = convert( p, CVTR );
+       if( actions & TYMATCH ) p = tymatch(p);
+       if( actions & PTMATCH ) p = ptmatch(p);
+
+       if( actions & OTHER ){
+               struct symtab *sp1;
+
+               l = p->n_left;
+               r = p->n_right;
+
+               switch(o){
+
+               case NAME:
+                       cerror("buildtree NAME");
+
+               case STREF:
+                       /* p->x turned into *(p+offset) */
+                       /* rhs must be a name; check correctness */
+
+                       /* Find member symbol struct */
+                       if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){
+                               uerror("struct or union required");
+                               break;
+                       }
+
+                       if ((sp1 = strmemb(l->n_ap)) == NULL) {
+                               uerror("undefined struct or union");
+                               break;
+                       }
+
+                       if ((sp = findmember(sp1, r->n_name)) == NULL) {
+                               uerror("member '%s' not declared", r->n_name);
+                               break;
+                       }
+
+                       r->n_sp = sp;
+                       p = stref(p);
+                       break;
+
+               case UMUL:
+                       if (l->n_op == ADDROF) {
+                               p1nfree(p);
+                               p = p1nfree(l);
+                       }
+                       if( !ISPTR(l->n_type))uerror("illegal indirection");
+                       p->n_type = DECREF(l->n_type);
+                       p->n_qual = DECREF(l->n_qual);
+                       p->n_df = l->n_df;
+                       p->n_ap = l->n_ap;
+                       break;
+
+               case ADDROF:
+                       switch( l->n_op ){
+
+                       case UMUL:
+                               p1nfree(p);
+                               p = p1nfree(l);
+                               /* FALLTHROUGH */
+                       case TEMP:
+                       case NAME:
+                               p->n_type = INCREF(l->n_type);
+                               p->n_qual = INCQAL(l->n_qual);
+                               p->n_df = l->n_df;
+                               p->n_ap = l->n_ap;
+                               break;
+
+                       case COMOP:
+                               p1nfree(p);
+                               lr = buildtree(ADDROF, l->n_right, NULL);
+                               p = buildtree( COMOP, l->n_left, lr );
+                               p1nfree(l);
+                               break;
+
+                       case QUEST:
+                               lr = buildtree( ADDROF, l->n_right->n_right, NULL );
+                               ll = buildtree( ADDROF, l->n_right->n_left, NULL );
+                               p1nfree(p); p1nfree(l->n_right);
+                               p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) );
+                               p1nfree(l);
+                               break;
+
+                       default:
+                               uerror("unacceptable operand of &: %d", l->n_op );
+                               break;
+                               }
+                       break;
+
+               case LS:
+               case RS: /* must make type size at least int... */
+                       if (p->n_type == CHAR || p->n_type == SHORT) {
+                               p->n_left = makety(l, INT, 0, 0, 0);
+                       } else if (p->n_type == UCHAR || p->n_type == USHORT) {
+                               p->n_left = makety(l, UNSIGNED, 0, 0, 0);
+                       }
+                       l = p->n_left;
+                       p->n_type = l->n_type;
+                       p->n_qual = l->n_qual;
+                       p->n_df = l->n_df;
+                       p->n_ap = l->n_ap;
+                       if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT)
+                               p->n_right = makety(r, INT, 0, 0, 0);
+                       break;
+
+               case RETURN:
+               case ASSIGN:
+               case CAST:
+                       /* structure assignment */
+                       /* take the addresses of the two sides; then make an
+                        * operator using STASG and
+                        * the addresses of left and right */
+
+                       if (strmemb(l->n_ap) != strmemb(r->n_ap))
+                               uerror("assignment of different structures");
+
+                       r = buildtree(ADDROF, r, NULL);
+
+                       l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap);
+                       l = clocal(l);
+
+                       if( o == RETURN ){
+                               p1nfree(p);
+                               p = l;
+                               break;
+                       }
+
+                       p->n_op = UMUL;
+                       p->n_left = l;
+                       p->n_right = NULL;
+                       break;
+
+               case QUEST: /* fixup types of : */
+                       if (r->n_left->n_type != p->n_type)
+                               r->n_left = makety(r->n_left, p->n_type,
+                                   p->n_qual, p->n_df, p->n_ap);
+                       if (r->n_right->n_type != p->n_type)
+                               r->n_right = makety(r->n_right, p->n_type,
+                                   p->n_qual, p->n_df, p->n_ap);
+                       break;
+
+               case COLON:
+                       /* structure colon */
+
+                       if (strmemb(l->n_ap) != strmemb(r->n_ap))
+                               uerror( "type clash in conditional" );
+                       break;
+
+               case CALL:
+                       p->n_right = r = strargs(p->n_right);
+                       p = funcode(p);
+                       /* FALLTHROUGH */
+               case UCALL:
+                       if (!ISPTR(l->n_type))
+                               uerror("illegal function");
+                       p->n_type = DECREF(l->n_type);
+                       if (!ISFTN(p->n_type))
+                               uerror("illegal function");
+                       p->n_type = DECREF(p->n_type);
+                       p->n_df = l->n_df+1; /* add one for prototypes */
+                       p->n_ap = l->n_ap;
+                       if (p->n_type == STRTY || p->n_type == UNIONTY) {
+                               /* function returning structure */
+                               /*  make function really return ptr to str., with * */
+
+                               p->n_op += STCALL-CALL;
+                               p->n_type = INCREF(p->n_type);
+                               p = clocal(p); /* before recursing */
+                               p = buildtree(UMUL, p, NULL);
+
+                               }
+                       break;
+
+               default:
+                       cerror( "other code %d", o );
+               }
+       }
+
+       /* fixup type in bit-field assignment */
+       if (p->n_op == ASSIGN && l->n_op == FLD && UPKFSZ(l->n_rval) < SZINT)
+               p = makety(p, INT, 0, 0, 0);
+
+       /*
+        * Allow (void)0 casts.
+        * XXX - anything on the right side must be possible to cast.
+        * XXX - remove void types further on.
+        */
+       if (p->n_op == CAST && p->n_type == VOID &&
+           p->n_right->n_op == ICON)
+               p->n_right->n_type = VOID;
+
+       if (actions & CVTO)
+               p = oconvert(p);
+       p = clocal(p);
+
+#ifdef PCC_DEBUG
+       if (bdebug) {
+               printf("End of buildtree:\n");
+               p1fwalk(p, eprint, 0);
+       }
+#endif
+
+       return(p);
+
+       }
+
+/*                      
+ * Rewrite ++/-- to (t=p, p++, t) ops on types that do not act act as usual.
+ */
+static P1ND *
+rewincop(P1ND *p1, P1ND *p2, int op)
+{
+       P1ND *t, *r;
+               
+       t = cstknode(p1->n_type, p1->n_df, p1->n_ap);
+       r = buildtree(ASSIGN, p1tcopy(t), p1tcopy(p1));
+       r = buildtree(COMOP, r, buildtree(op, p1, eve(p2)));
+       return buildtree(COMOP, r, t);
+}
+
+
+/* Find a member in a struct or union. May be an unnamed member */
+static struct symtab *
+findmember(struct symtab *sp, char *s)
+{
+       struct symtab *sp2, *sp3;
+
+       for (; sp != NULL; sp = sp->snext) {
+               if (sp->sname[0] == '*') {
+                       /* unnamed member, recurse down */
+                       if ((sp2 = findmember(strmemb(sp->sap), s))) {
+                               sp3 = tmpalloc(sizeof (struct symtab));
+                               *sp3 = *sp2;
+                               sp3->soffset += sp->soffset;
+                               return sp3;
+                       }
+               } else if (sp->sname == s)
+                       return sp;
+       }
+       return NULL;
+}
+
+
+/*
+ * Check if there will be a lost label destination inside of a ?:
+ * It cannot be reached so just print it out.
+ */
+void
+putjops(P1ND *p, void *arg)
+{
+       if (p->n_op == COMOP && p->n_left->n_op == GOTO)
+               plabel((int)glval(p->n_left->n_left)+2);
+}
+
+/*
+ * Build a name node based on a symtab entry.
+ * broken out from buildtree().
+ */
+P1ND *
+nametree(struct symtab *sp)
+{
+       P1ND *p;
+
+       p = block(NAME, NULL, NULL, sp->stype, sp->sdf, sp->sap);
+       p->n_qual = sp->squal;
+       p->n_sp = sp;
+
+#ifndef NO_C_BUILTINS
+       if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0)
+               return p;  /* do not touch builtins here */
+       
+#endif
+
+       if (sp->sflags & STNODE) {
+               /* Generated for optimizer */
+               p->n_op = TEMP;
+               p->n_rval = sp->soffset;
+       }
+
+#ifdef GCC_COMPAT
+       /* Get a label name */
+       if (sp->sflags == SLBLNAME)
+               sp->stype = p->n_type = VOID;
+#endif
+       if (sp->stype == UNDEF) {
+               uerror("%s undefined", sp->sname);
+               /* make p look reasonable */
+               p->n_type = INT;
+               p->n_df = NULL;
+               defid(p, SNULL);
+       }
+       if (sp->sclass == MOE) {
+               p->n_op = ICON;
+               slval(p, sp->soffset);
+               p->n_df = NULL;
+               p->n_sp = NULL;
+       }
+       return clocal(p);
+}
+
+/*
+ * Cast a node to another type by inserting a cast.
+ * Just a nicer interface to buildtree.
+ * Returns the new tree.
+ */
+P1ND *
+cast(P1ND *p, TWORD t, TWORD u)
+{
+       P1ND *q;
+
+       q = block(NAME, NULL, NULL, t, 0, 0);
+       q->n_qual = u;
+       q = buildtree(CAST, q, p);
+       p = q->n_right;
+       p1nfree(q->n_left);
+       p1nfree(q);
+       return p;
+}
+
+/*
+ * Cast and complain if necessary by not inserining a cast.
+ */
+P1ND *
+ccast(P1ND *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap)
+{
+       P1ND *q;
+
+       /* let buildtree do typechecking (and casting) */ 
+       q = block(NAME, NULL, NULL, t, df, ap);
+       p = buildtree(ASSIGN, q, p);
+       p1nfree(p->n_left);
+       q = optim(p->n_right);
+       p1nfree(p);
+       return q;
+}
+
+/*
+ * Do an actual cast of a constant (if possible).
+ * Routine assumes 2-complement.  p is cast to type t.
+ * Returns 1 if handled, 0 otherwise.
+ */
+int
+concast(P1ND *p, TWORD t)
+{
+       extern short sztable[];
+       CONSZ val;
+
+       if (p->n_op != ICON && p->n_op != FCON) /* only constants */
+               return 0;
+       if (p->n_op == ICON && p->n_sp != NULL) { /* no addresses */
+               if (t == BOOL) {
+                       slval(p, 1), p->n_type = BOOL, p->n_sp = NULL;
+                       return 1;
+               }
+               return 0;
+       }
+       if (((p->n_type & TMASK) && t != BOOL) || (t & TMASK)) /* no pointers */
+               return 0;
+
+//printf("concast till %d\n", t);
+//fwalk(p, eprint, 0);
+
+#define        TYPMSK(y) ((((1LL << (y-1))-1) << 1) | 1)
+       if (p->n_op == ICON) {
+               val = glval(p);
+
+               if (t == BOOL) {
+                       if (val)
+                               slval(p, 1);
+               } else if (t <= ULONGLONG) {
+                       slval(p, val & TYPMSK(sztable[t]));
+                       if (!ISUNSIGNED(t)) {
+                               if (val & (1LL << (sztable[t]-1)))
+                                       slval(p, glval(p) | ~TYPMSK(sztable[t]));
+                       }
+               } else if (t <= LDOUBLE) {
+                       p->n_op = FCON;
+                       p->n_dcon = fltallo();
+                       FLOAT_INT2FP(p->n_dcon, val, p->n_type);
+               }
+       } else { /* p->n_op == FCON */
+               if (t == BOOL) {
+                       p->n_op = ICON;
+                       slval(p, FLOAT_NE(p->n_dcon, FLOAT_ZERO));
+                       p->n_sp = NULL;
+               } else if (t <= ULONGLONG) {
+                       p->n_op = ICON;
+                       FLOAT_FP2INT(glval(p), p->n_dcon, t);
+                       p->n_sp = NULL;
+               } else {
+                       FLOAT_FP2FP(p->n_dcon, t);
+               }
+       }
+       p->n_type = t;
+//fwalk(p, eprint, 0);
+       return 1;
+}
+
+/*
+ * Do a conditional branch.
+ */
+void
+cbranch(P1ND *p, P1ND *q)
+{
+       p = buildtree(CBRANCH, p, q);
+       if (p->n_left->n_op == ICON) {
+               if (glval(p->n_left) != 0) {
+                       branch((int)glval(q)); /* branch always */
+                       reached = 0;
+               }
+               p1tfree(p);
+               return;
+       }
+       ecomp(p);
+}
+
+P1ND *
+strargs(register P1ND *p)
+{
+       /* rewrite structure flavored arguments */
+
+       if( p->n_op == CM ){
+               p->n_left = strargs( p->n_left );
+               p->n_right = strargs( p->n_right );
+               return( p );
+               }
+
+       if( p->n_type == STRTY || p->n_type == UNIONTY ){
+               p = block(STARG, p, NULL, p->n_type, p->n_df, p->n_ap);
+               p->n_left = buildtree( ADDROF, p->n_left, NULL );
+               p = clocal(p);
+               }
+       return( p );
+}
+
+/*
+ * apply the op o to the lval part of p; if binary, rhs is val
+ */
+int
+conval(P1ND *p, int o, P1ND *q)
+{
+       TWORD tl = p->n_type, tr = q->n_type, td;
+       int i, u;
+       CONSZ val;
+       U_CONSZ v1, v2;
+
+       val = glval(q);
+
+       /* make both sides same type */
+       if (tl < BTMASK && tr < BTMASK) {
+               td = tl > tr ? tl : tr;
+               if (td < INT)
+                       td = INT;
+               u = ISUNSIGNED(td);
+               if (tl != td)
+                       p = makety(p, td, 0, 0, 0);
+               if (tr != td)
+                       q = makety(q, td, 0, 0, 0);
+       } else
+               u = ISUNSIGNED(tl) || ISUNSIGNED(tr);
+       if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE);
+
+       if (p->n_sp != NULL && q->n_sp != NULL)
+               return(0);
+       if (q->n_sp != NULL && o != PLUS)
+               return(0);
+       if (p->n_sp != NULL && o != PLUS && o != MINUS)
+               return(0);
+
+       v1 = glval(p);
+       v2 = glval(q);
+       if (v2 == 0 && (cdope(o) & DIVFLG))
+               return 0; /* leave division by zero to runtime */
+       switch( o ){
+
+       case PLUS:
+               slval(p, (glval(p) + val));
+               if (p->n_sp == NULL) {
+                       p->n_right = q->n_right;
+                       p->n_type = q->n_type;
+               }
+               break;
+       case MINUS:
+               slval(p, (glval(p) - val));
+               break;
+       case MUL:
+               slval(p, (glval(p) * val));
+               break;
+       case DIV:
+               if (u) {
+                       v1 /= v2;
+                       slval(p, v1);
+               } else
+                       slval(p, (glval(p) / val));
+               break;
+       case MOD:
+               if (u) {
+                       v1 %= v2;
+                       slval(p, v1);
+               } else
+                       slval(p, (glval(p) % val));
+               break;
+       case AND:
+               slval(p, (glval(p) & val));
+               break;
+       case OR:
+               slval(p, (glval(p) | val));
+               break;
+       case ER:
+               slval(p, (glval(p) ^ val));
+               break;
+       case LS:
+               i = (int)val;
+               slval(p, glval(p) << i);
+               break;
+       case RS:
+               i = (int)val;
+               if (u) {
+                       v1 = v1 >> i;
+                       slval(p, v1);
+               } else {
+                       slval(p, glval(p) >> i);
+               }
+               break;
+
+       case UMINUS:
+               slval(p, (-glval(p)));
+               break;
+       case COMPL:
+               slval(p, (~glval(p)));
+               break;
+       case NOT:
+               slval(p, (!glval(p)));
+               p->n_type = INT;
+               break;
+       case LT:
+               slval(p, (glval(p) < val));
+               break;
+       case LE:
+               slval(p, (glval(p) <= val));
+               break;
+       case GT:
+               slval(p, (glval(p) > val));
+               break;
+       case GE:
+               slval(p, (glval(p) >= val));
+               break;
+       case ULT:
+               slval(p, (v1 < v2));
+               break;
+       case ULE:
+               slval(p, (v1 <= v2));
+               break;
+       case UGT:
+               slval(p, (v1 > v2));
+               break;
+       case UGE:
+               slval(p, (v1 >= v2));
+               break;
+       case EQ:
+               slval(p, (glval(p) == val));
+               break;
+       case NE:
+               slval(p, (glval(p) != val));
+               break;
+       case ANDAND:
+               slval(p, (glval(p) && val));
+               break;
+       case OROR:
+               slval(p, (glval(p) || val));
+               break;
+       default:
+               return(0);
+               }
+       /* Do the best in making everything type correct after calc */
+       if (clogop(o))
+               p->n_type = INT;
+       if (p->n_sp == NULL && q->n_sp == NULL) {
+               slval(p, valcast(glval(p), p->n_type));
+       }
+       return(1);
+       }
+
+/*
+ * Ensure that v matches the type t; sign- or zero-extended
+ * as suitable to CONSZ.
+ * Only to be used for integer types.
+ */
+CONSZ
+valcast(CONSZ v, TWORD t)
+{
+       CONSZ r;
+       int sz;
+
+       if (t < CHAR || t > ULONGLONG)
+               return v; /* cannot cast */
+
+       if (t >= LONGLONG)
+               return v; /* already largest */
+
+#define M(x)   ((((1ULL << ((x)-1)) - 1) << 1) + 1)
+#define        NOTM(x) (~M(x))
+#define        SBIT(x) (1ULL << ((x)-1))
+
+       sz = (int)tsize(t, NULL, NULL);
+       r = v & M(sz);
+       if (!ISUNSIGNED(t) && (SBIT(sz) & r))
+               r = r | NOTM(sz);
+       return r;
+}
+
+/*
+ * Checks p for the existence of a pun.  This is called when the op of p
+ * is ASSIGN, RETURN, CAST, COLON, or relational.
+ * One case is when enumerations are used: this applies only to lint.
+ * In the other case, one operand is a pointer, the other integer type
+ * we check that this integer is in fact a constant zero...
+ * in the case of ASSIGN, any assignment of pointer to integer is illegal
+ * this falls out, because the LHS is never 0.
+ * XXX - check for COMOPs in assignment RHS?
+ */
+void
+chkpun(P1ND *p)
+{
+       union dimfun *d1, *d2;
+       P1ND *q;
+       int t1, t2;
+
+       t1 = p->n_left->n_type;
+       t2 = p->n_right->n_type;
+
+       switch (p->n_op) {
+       case RETURN:
+               /* return of void allowed but nothing else */
+               if (t1 == VOID && t2 == VOID)
+                       return;
+               if (t1 == VOID) {
+                       werror("returning value from void function");
+                       return;
+               }
+               if (t2 == VOID) {
+                       uerror("using void value");
+                       return;
+               }
+               break;
+       case COLON:
+               if (t1 == VOID && t2 == VOID)
+                       return;
+               break;
+       default:
+               if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) {
+                       uerror("value of void expression used");
+                       return;
+               }
+               break;
+       }
+
+       /* allow void pointer assignments in any direction */
+       if (BTYPE(t1) == VOID && (t2 & TMASK))
+               return;
+       if (BTYPE(t2) == VOID && (t1 & TMASK))
+               return;
+
+       /* boolean have special syntax */
+       if (t1 == BOOL) {
+               if (!ISARY(t2)) /* Anything scalar */
+                       return;
+       }
+
+       if (ISPTR(t1) || ISARY(t1))
+               q = p->n_right;
+       else
+               q = p->n_left;
+
+       if (!ISPTR(q->n_type) && !ISARY(q->n_type)) {
+               if (q->n_op != ICON || glval(q) != 0)
+                       werror("illegal combination of pointer and integer");
+       } else {
+               if (t1 == t2) {
+                       if (ISSOU(BTYPE(t1)) &&
+                           !suemeq(p->n_left->n_ap, p->n_right->n_ap))
+                               werror("illegal structure pointer combination");
+                       return;
+               }
+               d1 = p->n_left->n_df;
+               d2 = p->n_right->n_df;
+               for (;;) {
+                       if (ISARY(t1) || ISPTR(t1)) {
+                               if (!ISARY(t2) && !ISPTR(t2))
+                                       break;
+                               if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) {
+                                       werror("illegal array size combination");
+                                       return;
+                               }
+                               if (ISARY(t1))
+                                       ++d1;
+                               if (ISARY(t2))
+                                       ++d2;
+                       } else if (ISFTN(t1)) {
+                               if (chkftn(d1->dfun, d2->dfun)) {
+                                       werror("illegal function "
+                                           "pointer combination");
+                                       return;
+                               }
+                               ++d1;
+                               ++d2;
+                       } else
+                               break;
+                       t1 = DECREF(t1);
+                       t2 = DECREF(t2);
+               }
+               if (DEUNSIGN(t1) != DEUNSIGN(t2))
+                       werror("illegal pointer combination");
+               else if (t1 != t2)
+                       warner(Wpointer_sign);
+       }
+}
+
+static P1ND *
+offplus(P1ND *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) {
+       if (off != 0) {
+               p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap);
+               p->n_qual = q;
+               p = optim(p);
+       }
+
+       return buildtree(UMUL, p, NULL);
+}
+
+P1ND *
+stref(P1ND *p)
+{
+       P1ND *r;
+       struct attr *ap, *xap, *yap;
+       union dimfun *d;
+       TWORD t, q;
+       int dsc, fsz;
+       OFFSZ off;
+       struct symtab *s;
+
+       /* make p->x */
+       /* this is also used to reference automatic variables */
+
+       s = p->n_right->n_sp;
+       p1nfree(p->n_right);
+       r = p1nfree(p);
+#ifdef GCC_COMPAT
+       xap = attr_find(r->n_ap, GCC_ATYP_PACKED);
+#else
+       xap = NULL;
+#endif
+
+       p = pconvert(r);
+
+       /* make p look like ptr to x */
+
+       if (!ISPTR(p->n_type))
+               p->n_type = PTR+UNIONTY;
+
+       t = INCREF(s->stype);
+       q = INCQAL(s->squal);
+       d = s->sdf;
+       ap = s->sap;
+#ifdef GCC_COMPAT
+       if ((yap = attr_find(ap, GCC_ATYP_PACKED)) != NULL)
+               xap = yap;
+       else if (xap != NULL)
+               ap = attr_add(ap, attr_dup(xap));
+       /* xap set if packed struct */
+#else
+       yap = NULL;
+#endif
+
+       p = makety(p, t, q, d, ap);
+
+       /* compute the offset to be added */
+
+       off = s->soffset;
+       dsc = s->sclass;
+
+       if (dsc & FIELD) {
+               TWORD ftyp = s->stype;
+               int fal = talign(ftyp, ap);
+               fsz = dsc&FLDSIZ;
+               off = (off/fal)*fal;
+               p = offplus(p, off, t, q, d, ap);
+               p = block(FLD, p, NULL, ftyp, 0, ap);
+               p->n_qual = q;
+               p->n_rval = PKFIELD(fsz, s->soffset%fal);
+               /* make type int or some other signed type */
+               if (fsz < SZINT)
+                       ftyp = INT;
+               else if (fsz > SZINT && fsz < SZLONG && ftyp < LONG)
+                       ftyp = LONG;
+               else if (fsz > SZLONG && fsz < SZLONGLONG && ftyp < LONGLONG)
+                       ftyp = LONGLONG;
+               if (ftyp != p->n_type)
+                       p = makety(p, ftyp, 0, 0, 0);
+       } else {
+               p = offplus(p, off, t, q, d, ap);
+#ifndef CAN_UNALIGN
+               /* if target cannot handle unaligned addresses, fix here */
+#endif
+       }
+
+       p = clocal(p);
+       return p;
+}
+
+int
+notlval(register P1ND *p)
+{
+       /* return 0 if p an lvalue, 1 otherwise */
+
+       again:
+
+       switch( p->n_op ){
+
+       case FLD:
+               p = p->n_left;
+               goto again;
+
+       case NAME:
+       case OREG:
+       case UMUL:
+               if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1);
+               /* FALLTHROUGH */
+       case TEMP:
+       case REG:
+               return(0);
+
+       default:
+               return(1);
+       }
+}
+
+/* make a constant node with value i */
+P1ND *
+bcon(int i)
+{
+       return xbcon(i, NULL, INT);
+}
+
+P1ND *
+xbcon(CONSZ val, struct symtab *sp, TWORD type)
+{
+       P1ND *p;
+
+       p = block(ICON, NULL, NULL, type, 0, 0);
+       slval(p, val);
+       p->n_sp = sp;
+       return clocal(p);
+}
+
+P1ND *
+bpsize(P1ND *p)
+{
+       int isdyn(struct symtab *sp);
+       struct symtab s;
+       P1ND *q, *r;
+       TWORD t;
+       int sz;
+
+       s.stype = DECREF(p->n_type);
+       s.sdf = p->n_df;
+       if (isdyn(&s)) {
+               q = bcon(1);
+               for (t = s.stype; t > BTMASK; t = DECREF(t)) {
+                       if (ISPTR(t))
+                               return buildtree(MUL, q, bcon(SZPOINT(t)));
+                       if (ISARY(t)) {
+                               if (s.sdf->ddim < 0)
+                                       r = tempnode(-s.sdf->ddim, INT, 0, 0);
+                               else
+                                       r = bcon(s.sdf->ddim/SZCHAR);
+                               q = buildtree(MUL, q, r);
+                               s.sdf++;
+                       }
+               }
+               sz = (int)tsize(t, s.sdf, p->n_ap);
+               p = buildtree(MUL, q, bcon(sz/SZCHAR));
+       } else
+               p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap));
+       return p;
+}
+
+/*
+ * p is a node of type pointer; psize returns the
+ * size of the thing pointed to
+ */
+OFFSZ
+psize(P1ND *p)
+{
+
+       if (!ISPTR(p->n_type)) {
+               uerror("pointer required");
+               return(SZINT);
+       }
+       /* note: no pointers to fields */
+       return(tsize(DECREF(p->n_type), p->n_df, p->n_ap));
+}
+
+/*
+ * convert an operand of p
+ * f is either CVTL or CVTR
+ * operand has type int, and is converted by the size of the other side
+ * convert is called when an integer is to be added to a pointer, for
+ * example in arrays or structures.
+ */
+P1ND *
+convert(P1ND *p, int f)
+{
+       union dimfun *df;
+       TWORD ty, ty2;
+       P1ND *q, *r, *s, *rv;
+
+       if (f == CVTL) {
+               q = p->n_left;
+               s = p->n_right;
+       } else {
+               q = p->n_right;
+               s = p->n_left;
+       }
+       ty2 = ty = DECREF(s->n_type);
+       while (ISARY(ty))
+               ty = DECREF(ty);
+
+       r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap);
+       ty = ty2;
+       rv = bcon(1);
+       df = s->n_df;
+       while (ISARY(ty)) {
+               rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) :
+                   tempnode(-df->ddim, INT, 0, 0));
+               df++;
+               ty = DECREF(ty);
+       }
+       rv = clocal(MBLOCK(rv, r, INT, 0, 0));
+       rv = optim(rv);
+
+       r = MBLOCK(q, rv, INT, 0, 0);
+       r = clocal(r);
+       /*
+        * Indexing is only allowed with integer arguments, so insert
+        * SCONV here if arg is not an integer.
+        * XXX - complain?
+        */
+       if (r->n_type != INTPTR)
+               r = clocal(makety(r, INTPTR, 0, 0, 0));
+       if (f == CVTL)
+               p->n_left = r;
+       else
+               p->n_right = r;
+       return(p);
+}
+
+P1ND *
+pconvert(register P1ND *p)
+{
+       /* if p should be changed into a pointer, do so */
+
+       if( ISARY( p->n_type) ){
+               p->n_type = DECREF( p->n_type );
+               ++p->n_df;
+               return( buildtree( ADDROF, p, NULL ) );
+       }
+       if( ISFTN( p->n_type) )
+               return( buildtree( ADDROF, p, NULL ) );
+
+       return( p );
+}
+
+P1ND *
+oconvert(register P1ND *p)
+{
+       /* convert the result itself: used for pointer and unsigned */
+
+       switch(p->n_op) {
+
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+               if(ISUNSIGNED(p->n_left->n_type) ||
+                   ISUNSIGNED(p->n_right->n_type) ||
+                   ISPTR(p->n_left->n_type) ||
+                   ISPTR(p->n_right->n_type))
+                        p->n_op += (ULE-LE);
+               /* FALLTHROUGH */
+       case EQ:
+       case NE:
+               return( p );
+
+       case MINUS:
+               p->n_type = INTPTR;
+               p->n_ap = NULL;
+               return(clocal(VBLOCK(p, bpsize(p->n_left), INT, 0, 0)));
+               }
+
+       cerror( "illegal oconvert: %d", p->n_op );
+
+       return(p);
+}
+
+/*
+ * makes the operands of p agree; they are
+ * either pointers or integers, by this time
+ * with MINUS, the sizes must be the same
+ * with COLON, the types must be the same
+ */
+P1ND *
+ptmatch(P1ND *p)
+{
+       struct attr *ap, *ap2;
+       union dimfun *d, *d2;
+       TWORD t1, t2, t, q1, q2, q;
+       int o;
+
+       o = p->n_op;
+       t = t1 = p->n_left->n_type;
+       q = q1 = p->n_left->n_qual;
+       t2 = p->n_right->n_type;
+       q2 = p->n_right->n_qual;
+       d = p->n_left->n_df;
+       d2 = p->n_right->n_df;
+       ap = p->n_left->n_ap;
+       ap2 = p->n_right->n_ap;
+
+       switch( o ){
+
+       case ASSIGN:
+       case RETURN:
+               {  break; }
+
+       case CAST:
+               if (t == VOID) {
+                       /* just paint over */
+                       p->n_right = block(SCONV, p->n_right, NULL, VOID, 0, 0);
+                       return p;
+               }
+               break;
+
+       case MINUS: {
+               int isdyn(struct symtab *sp);
+               struct symtab s1, s2;
+
+               s1.stype = DECREF(t);
+               s1.sdf = d;
+               s2.stype = DECREF(t2);
+               s2.sdf = d2;
+               if (isdyn(&s1) || isdyn(&s2))
+                       ; /* We don't know */
+               else if (psize(p->n_left) != psize(p->n_right))
+                       uerror("illegal pointer subtraction");
+               break;
+               }
+
+       case COLON:
+               if (t1 != t2) {
+                       /*
+                        * Check for void pointer types. They are allowed
+                        * to cast to/from any pointers; 6.5.15 #6.
+                        * XXX qualified versions of void?
+                        */
+                       if (ISPTR(t1) && ISPTR(t2)) {
+                               if (BTYPE(t1) == VOID) {
+                                       t = t2;
+                                       d = d2;
+                                       ap = ap2;
+                                       break;
+                               }
+                               if (BTYPE(t2) == VOID)
+                                       break;
+                       }
+                       uerror("illegal types in :");
+               }
+               break;
+
+       default:  /* must work harder: relationals or comparisons */
+
+               if( !ISPTR(t1) ){
+                       t = t2;
+                       q = q2;
+                       d = d2;
+                       ap = ap2;
+                       break;
+                       }
+               if( !ISPTR(t2) ){
+                       break;
+                       }
+
+               /* both are pointers */
+               if( talign(t2,ap2) < talign(t,ap) ){
+                       t = t2;
+                       q = q2;
+                       ap = ap2;
+                       }
+               break;
+               }
+
+       p->n_left = makety( p->n_left, t, q, d, ap );
+       p->n_right = makety( p->n_right, t, q, d, ap );
+       if( o!=MINUS && !clogop(o) ){
+
+               p->n_type = t;
+               p->n_qual = q;
+               p->n_df = d;
+               p->n_ap = ap;
+               }
+
+       return(clocal(p));
+}
+
+/*
+ * Satisfy the types of various arithmetic binary ops.
+ *
+ * rules are:
+ *  if assignment, type of LHS
+ *  if any doubles, make double
+ *  else if any float make float
+ *  else if any longlongs, make long long
+ *  else if any longs, make long
+ *  else etcetc.
+ *
+ *  If the op with the highest rank is unsigned, this is the resulting type.
+ *  See:  6.3.1.1 rank order equal of signed and unsigned types
+ *        6.3.1.8 Usual arithmetic conversions
+ */
+static P1ND *
+tymatch(P1ND *p)
+{
+       TWORD tl, tr, t;
+       P1ND *l, *r;
+       int o;
+
+       o = p->n_op;
+       r = p->n_right;
+       l = p->n_left;
+
+       tl = l->n_type;
+       tr = r->n_type;
+
+       if (tl == BOOL) tl = BOOL_TYPE;
+       if (tr == BOOL) tr = BOOL_TYPE;
+
+       if (casgop(o)) {
+               if (r->n_op != ICON && tl < FLOAT && tr < FLOAT &&
+                   DEUNSIGN(tl) < DEUNSIGN(tr) && o != CAST)
+                       warner(Wtruncate, tnames[tr], tnames[tl]);
+               if (l->n_type == BOOL && r->n_type != BOOL) {
+                       /* must create a ?: */
+                       p->n_right = buildtree(QUEST, p->n_right,
+                            buildtree(COLON, bcon(1), bcon(0)));
+               }
+               p->n_right = makety(p->n_right, l->n_type, 0, 0, 0);
+               t = p->n_type = l->n_type;
+               p->n_ap = l->n_ap;
+       } else {
+               t = tl > tr ? tl : tr; /* MAX */
+               /* This depends on ctype() called early */
+               if (o != COLON && t < INT)
+                       t = INT;
+               if (tl != t) p->n_left = makety(p->n_left, t, 0, 0, 0);
+               if (tr != t) p->n_right = makety(p->n_right, t, 0, 0, 0);
+               if (o == COLON && l->n_type == BOOL && r->n_type == BOOL)
+                       t = p->n_type = BOOL;
+               else if (!clogop(o))
+                       p->n_type = t;
+       }
+#ifdef PCC_DEBUG
+       if (tdebug) {
+               printf("tymatch(%p): ", p);
+               tprint(tl, 0);
+               printf(" %s ", copst(o));
+               tprint(tr, 0);
+               printf(" => ");
+               tprint(t, 0);
+               printf("\n");
+               p1fwalk(p, eprint, 0);
+       }
+#endif
+       return p;
+}
+
+/*
+ * make p into type t by inserting a conversion
+ */
+P1ND *
+makety(P1ND *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap)
+{
+
+       if (t == p->n_type) {
+               p->n_df = d;
+               p->n_ap = ap;
+               p->n_qual = q;
+               return(p);
+       }
+
+       if (ISITY(t) || ISCTY(t) || ISITY(p->n_type) || ISCTY(p->n_type))
+               cerror("makety");
+
+       if (concast(p, t))
+               return clocal(p);
+
+       p = block(t & TMASK ? PCONV : SCONV, p, NULL, t, d, ap);
+       p->n_qual = q;
+       return clocal(p);
+}
+
+P1ND *
+block(int o, P1ND *l, P1ND *r, TWORD t, union dimfun *d, struct attr *ap)
+{
+       register P1ND *p;
+
+       p = p1alloc();
+       p->n_rval = 0;
+       p->n_op = o;
+       slval(p, 0);
+       p->n_left = l;
+       p->n_right = r;
+       p->n_type = t;
+       p->n_qual = 0;
+       p->n_df = d;
+       p->n_ap = ap;
+       return(p);
+}
+
+/*
+ * Return the constant value from an ICON.
+ */
+CONSZ
+icons(P1ND *p)
+{
+       /* if p is an integer constant, return its value */
+       CONSZ val;
+
+       if (p->n_op != ICON || p->n_sp != NULL) {
+               uerror( "constant expected");
+               val = 1;
+       } else
+               val = glval(p);
+       p1tfree(p);
+       return(val);
+}
+
+/* 
+ * the intent of this table is to examine the
+ * operators, and to check them for
+ * correctness.
+ * 
+ * The table is searched for the op and the
+ * modified type (where this is one of the
+ * types INT (includes char and short), LONG,
+ * DOUBLE (includes FLOAT), and POINTER
+ * 
+ * The default action is to make the node type integer
+ * 
+ * The actions taken include:
+ *     PUN       check for puns
+ *     CVTL      convert the left operand
+ *     CVTR      convert the right operand
+ *     TYPL      the type is determined by the left operand
+ *     TYPR      the type is determined by the right operand
+ *     TYMATCH   force type of left and right to match,by inserting conversions
+ *     PTMATCH   like TYMATCH, but for pointers
+ *     LVAL      left operand must be lval
+ *     CVTO      convert the op
+ *     NCVT      do not convert the operands
+ *     OTHER     handled by code
+ *     NCVTR     convert the left operand, not the right...
+ * 
+ */
+
+# define MINT 01       /* integer */
+# define MDBI 02       /* integer or double */
+# define MSTR 04       /* structure */
+# define MPTR 010      /* pointer */
+# define MPTI 020      /* pointer or integer */
+
+int
+opact(P1ND *p)
+{
+       int mt12, mt1, mt2, o;
+
+       mt1 = mt2 = mt12 = 0;
+
+       switch (coptype(o = p->n_op)) {
+       case BITYPE:
+               mt12=mt2 = moditype(p->n_right->n_type);
+               /* FALLTHROUGH */
+       case UTYPE:
+               mt12 &= (mt1 = moditype(p->n_left->n_type));
+               break;
+       }
+
+       switch( o ){
+
+       case NAME :
+       case ICON :
+       case FCON :
+       case CALL :
+       case UCALL:
+       case UMUL:
+               {  return( OTHER ); }
+       case UMINUS:
+               if( mt1 & MDBI ) return( TYPL+PROML );
+               break;
+
+       case COMPL:
+               if( mt1 & MINT ) return( TYPL+PROML );
+               break;
+
+       case ADDROF:
+               return( NCVT+OTHER );
+       case NOT:
+               return( PROML );
+
+/*     case INIT: */
+       case CM:
+       case CBRANCH:
+       case ANDAND:
+       case OROR:
+               return( 0 );
+
+       case MUL:
+       case DIV:
+               if( mt12 & MDBI ) return( TYMATCH );
+               break;
+
+       case MOD:
+       case AND:
+       case OR:
+       case ER:
+               if( mt12 & MINT ) return( TYMATCH );
+               break;
+
+       case LS:
+       case RS:
+               if( mt12 & MINT ) return( TYPL+OTHER+PROML );
+               break;
+
+       case EQ:
+       case NE:
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+               if( mt12 & MDBI ) return( TYMATCH+CVTO );
+               else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO );
+               else if( mt12 & MPTI ) return( PTMATCH+PUN );
+               else break;
+
+       case QUEST:
+               return( TYPR+OTHER );
+       case COMOP:
+               return( TYPR );
+
+       case STREF:
+               return( NCVTR+OTHER );
+
+       case FORCE:
+               return( TYPL );
+
+       case COLON:
+               if( mt12 & MDBI ) return( TYMATCH );
+               else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN );
+               else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN );
+               else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN );
+               else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER );
+               break;
+
+       case ASSIGN:
+       case RETURN:
+               if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER );
+               /* FALLTHROUGH */
+       case CAST:
+               if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH );
+               else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN );
+               else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN );
+               break;
+
+       case MINUS:
+               if (mt12 & MPTR)
+                       return(CVTO+PTMATCH+PUN);
+               if (mt2 & MPTR)
+                       break;
+               /* FALLTHROUGH */
+       case PLUS:
+               if (mt12 & MDBI)
+                       return(TYMATCH);
+               else if ((mt1&MPTR) && (mt2&MINT))
+                       return(TYPL+CVTR);
+               else if ((mt1&MINT) && (mt2&MPTR))
+                       return(TYPR+CVTL);
+
+       }
+       uerror("operands of %s have incompatible types", copst(o));
+       return(NCVT);
+}
+
+int
+moditype(TWORD ty)
+{
+       switch (ty) {
+
+       case STRTY:
+       case UNIONTY:
+               return( MSTR );
+
+       case BOOL:
+       case CHAR:
+       case SHORT:
+       case UCHAR:
+       case USHORT:
+       case UNSIGNED:
+       case ULONG:
+       case ULONGLONG:
+       case INT:
+       case LONG:
+       case LONGLONG:
+               return( MINT|MDBI|MPTI );
+       case FLOAT:
+       case DOUBLE:
+       case LDOUBLE:
+#ifndef NO_COMPLEX
+       case FCOMPLEX:
+       case COMPLEX:
+       case LCOMPLEX:
+       case FIMAG:
+       case IMAG:
+       case LIMAG:
+#endif
+               return( MDBI );
+       default:
+               return( MPTR|MPTI );
+
+       }
+}
+
+int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100;
+
+/*
+ * Returns a TEMP node with temp number nr.
+ * If nr == 0, return a node with a new number.
+ */
+P1ND *
+tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap)
+{
+       P1ND *r;
+
+       if (tvaloff == -NOOFFSET)
+               tvaloff++; /* Skip this for array indexing */
+       r = block(TEMP, NULL, NULL, type, df, ap);
+       regno(r) = nr ? nr : tvaloff;
+       tvaloff += szty(type);
+       return r;
+}
+
+/*
+ * Do sizeof on p.
+ */
+P1ND *
+doszof(P1ND *p)
+{
+       extern P1ND *arrstk[10];
+       extern int arrstkp;
+       union dimfun *df;
+       TWORD ty;
+       P1ND *rv, *q;
+       int astkp;
+
+       if (p->n_op == FLD)
+               uerror("can't apply sizeof to bit-field");
+
+       /*
+        * Arrays may be dynamic, may need to make computations.
+        */
+
+       rv = bcon(1);
+       df = p->n_df;
+       ty = p->n_type;
+       astkp = 0;
+       while (ISARY(ty)) {
+               if (df->ddim == NOOFFSET)
+                       uerror("sizeof of incomplete type");
+               if (df->ddim < 0) {
+                       if (arrstkp)
+                               q = arrstk[astkp++];
+                       else
+                               q = tempnode(-df->ddim, INT, 0, 0);
+               } else
+                       q = bcon(df->ddim);
+               rv = buildtree(MUL, rv, q);
+               df++;
+               ty = DECREF(ty);
+       }
+       rv = buildtree(MUL, rv, 
+           xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR));
+       p1tfree(p);
+       arrstkp = 0; /* XXX - may this fail? */
+       return rv;
+}
+
+#ifdef PCC_DEBUG
+void
+eprint(P1ND *p, int down, int *a, int *b)
+{
+       int ty;
+
+       *a = *b = down+1;
+       while( down > 1 ){
+               printf( "\t" );
+               down -= 2;
+               }
+       if( down ) printf( "    " );
+
+       ty = coptype( p->n_op );
+
+       printf("%p) %s, ", p, copst(p->n_op));
+       if (p->n_op == XARG || p->n_op == XASM)
+               printf("id '%s', ", p->n_name);
+       if (ty == LTYPE) {
+               printf(CONFMT, glval(p));
+               if (p->n_op == NAME || p->n_op == ICON)
+                       printf(", %p, ", p->n_sp);
+               else if (p->n_op == FCON)
+                       printf(", %Lf, ", p->n_dcon->fp);
+               else
+                       printf(", %d, ", p->n_rval);
+       }
+       tprint(p->n_type, p->n_qual);
+       printf( ", %p, ", p->n_df);
+#ifdef GCC_COMPAT
+       dump_attr(p->n_ap);
+#endif
+}
+# endif
+
+/*
+ * Emit everything that should be emitted on the left side 
+ * of a comma operator, and remove the operator.
+ * Do not traverse through QUEST, ANDAND and OROR.
+ * Enable this for all targets when stable enough.
+ */
+static void
+comops(P1ND *p)
+{
+       int o;
+       P1ND *q;
+
+       while (p->n_op == COMOP) {
+               /* XXX hack for GCC ({ }) ops */
+               if (p->n_left->n_op == GOTO) {
+                       int v = (int)glval(p->n_left->n_left);
+                       ecomp(p->n_left);
+                       plabel(v+2);
+               } else
+                       ecomp(p->n_left); /* will recurse if more COMOPs */
+               q = p->n_right;
+               *p = *q;
+               p1nfree(q);
+       }
+       o = coptype(p->n_op);
+       if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR)
+               o = UTYPE;
+       if (o != LTYPE)
+               comops(p->n_left);
+       if (o == BITYPE)
+               comops(p->n_right);
+}
+
+/*
+ * Walk up through the tree from the leaves,
+ * removing constant operators.
+ */
+static void
+logwalk(P1ND *p)
+{
+       int o = coptype(p->n_op);
+       P1ND *l, *r;
+
+       l = p->n_left;
+       r = p->n_right;
+       switch (o) {
+       case LTYPE:
+               return;
+       case BITYPE:
+               logwalk(r);
+               /* FALLTHROUGH */
+       case UTYPE:
+               logwalk(l);
+       }
+       if (!clogop(p->n_op))
+               return;
+       if (p->n_op == NOT && l->n_op == ICON) {
+               slval(p, (glval(l) == 0));
+               p1nfree(l);
+               p->n_op = ICON;
+       }
+       if (l->n_op == ICON && r->n_op == ICON) {
+               if (conval(l, p->n_op, r) == 0) {
+                       /*
+                        * people sometimes tend to do really odd compares,
+                        * like "if ("abc" == "def")" etc.
+                        * do it runtime instead.
+                        */
+               } else {
+                       slval(p, glval(l));
+                       p->n_op = ICON;
+                       p1nfree(l);
+                       p1nfree(r);
+               }
+       }
+}
+
+/*
+ * Removes redundant logical operators for branch conditions.
+ */
+static void
+fixbranch(P1ND *p, int label)
+{
+
+       logwalk(p);
+
+       if (p->n_op == ICON) {
+               if (glval(p) != 0)
+                       branch(label);
+               p1nfree(p);
+       } else {
+               if (!clogop(p->n_op)) /* Always conditional */
+                       p = buildtree(NE, p, bcon(0));
+               ecode(buildtree(CBRANCH, p, bcon(label)));
+       }
+}
+
+/*
+ * Write out logical expressions as branches.
+ */
+static void
+andorbr(P1ND *p, int true, int false)
+{
+       P1ND *q;
+       int o, lab;
+
+       lab = -1;
+       switch (o = p->n_op) { 
+       case EQ:
+       case NE:
+               /*
+                * Remove redundant EQ/NE nodes.
+                */
+               while (((o = p->n_left->n_op) == EQ || o == NE) && 
+                   p->n_right->n_op == ICON) {
+                       o = p->n_op;
+                       q = p->n_left;
+                       if (glval(p->n_right) == 0) {
+                               p1nfree(p->n_right);
+                               *p = *q;
+                               p1nfree(q);
+                               if (o == EQ)
+                                       p->n_op = p1negrel[p->n_op - EQ];
+#if 0
+                                       p->n_op = NE; /* toggla */
+#endif
+                       } else if (glval(p->n_right) == 1) {
+                               p1nfree(p->n_right);
+                               *p = *q;
+                               p1nfree(q);
+                               if (o == NE)
+                                       p->n_op = p1negrel[p->n_op - EQ];
+#if 0
+                                       p->n_op = EQ; /* toggla */
+#endif
+                       } else
+                               break; /* XXX - should always be false */
+                       
+               }
+               /* FALLTHROUGH */
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+calc:          if (true < 0) {
+                       p->n_op = p1negrel[p->n_op - EQ];
+                       true = false;
+                       false = -1;
+               }
+
+               rmcops(p->n_left);
+               rmcops(p->n_right);
+               fixbranch(p, true);
+               if (false >= 0)
+                       branch(false);
+               break;
+
+       case ULE:
+       case UGT:
+               /* Convert to friendlier ops */
+               if (nncon(p->n_right) && glval(p->n_right) == 0)
+                       p->n_op = o == ULE ? EQ : NE;
+               goto calc;
+
+       case UGE:
+       case ULT:
+               /* Already true/false by definition */
+               if (nncon(p->n_right) && glval(p->n_right) == 0) {
+                       if (true < 0) {
+                               o = o == ULT ? UGE : ULT;
+                               true = false;
+                       }
+                       rmcops(p->n_left);
+                       ecode(p->n_left);
+                       rmcops(p->n_right);
+                       ecode(p->n_right);
+                       p1nfree(p);
+                       if (o == UGE) /* true */
+                               branch(true);
+                       break;
+               }
+               goto calc;
+
+       case ANDAND:
+               lab = false<0 ? getlab() : false ;
+               andorbr(p->n_left, -1, lab);
+               comops(p->n_right);
+               andorbr(p->n_right, true, false);
+               if (false < 0)
+                       plabel( lab);
+               p1nfree(p);
+               break;
+
+       case OROR:
+               lab = true<0 ? getlab() : true;
+               andorbr(p->n_left, lab, -1);
+               comops(p->n_right);
+               andorbr(p->n_right, true, false);
+               if (true < 0)
+                       plabel( lab);
+               p1nfree(p);
+               break;
+
+       case NOT:
+               andorbr(p->n_left, false, true);
+               p1nfree(p);
+               break;
+
+       default:
+               rmcops(p);
+               if (true >= 0)
+                       fixbranch(p, true);
+               if (false >= 0) {
+                       if (true >= 0)
+                               branch(false);
+                       else
+                               fixbranch(buildtree(EQ, p, bcon(0)), false);
+               }
+       }
+}
+
+/*
+ * Create a node for either TEMP or on-stack storage.
+ */
+P1ND *
+cstknode(TWORD t, union dimfun *df, struct attr *ap)
+{
+       struct symtab *sp;
+
+       /* create a symtab entry suitable for this type */
+       sp = getsymtab("0hej", SSTMT);
+       sp->stype = t;
+       sp->sdf = df;
+       sp->sap = ap;
+       sp->sclass = AUTO;
+       sp->soffset = NOOFFSET;
+       oalloc(sp, &autooff);
+       return nametree(sp);
+
+}
+
+/*
+ * Massage the output trees to remove C-specific nodes:
+ *     COMOPs are split into separate statements.
+ *     QUEST/COLON are rewritten to branches.
+ *     ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation.
+ *     CBRANCH conditions are rewritten for lazy-evaluation.
+ */
+static void
+rmcops(P1ND *p)
+{
+       TWORD type;
+       P1ND *q, *r, *tval;
+       int o, ty, lbl, lbl2;
+
+       tval = NULL;
+       o = p->n_op;
+       ty = coptype(o);
+       if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */
+               struct symtab *sp = strmemb(p->n_ap);
+               MODTYPE(p->n_type, sp->stype);
+               /*
+                * XXX may fail if these are true:
+                * - variable-sized enums
+                * - non-byte-addressed targets.
+                */
+               if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type))
+                       MODTYPE(p->n_type, INT); /* INT ok? */
+       }
+       switch (o) {
+       case QUEST:
+
+               /*
+                * Create a branch node from ?:
+                * || and && must be taken special care of.
+                */
+               type = p->n_type;
+               andorbr(p->n_left, -1, lbl = getlab());
+
+               /* Make ASSIGN node */
+               /* Only if type is not void */
+               q = p->n_right->n_left;
+               comops(q);
+               if (type != VOID) {
+                       tval = cstknode(q->n_type, q->n_df, q->n_ap);
+                       q = buildtree(ASSIGN, p1tcopy(tval), q);
+               }
+               rmcops(q);
+               ecode(q); /* Done with assign */
+               branch(lbl2 = getlab());
+               plabel( lbl);
+
+               q = p->n_right->n_right;
+               comops(q);
+               if (type != VOID) {
+                       q = buildtree(ASSIGN, p1tcopy(tval), q);
+               }
+               rmcops(q);
+               ecode(q); /* Done with assign */
+
+               plabel( lbl2);
+
+               p1nfree(p->n_right);
+               if (p->n_type != VOID) {
+                       *p = *tval;
+                       p1nfree(tval);
+               } else {
+                       p->n_op = ICON;
+                       slval(p, 0);
+                       p->n_sp = NULL;
+               }
+               break;
+
+       case ULE:
+       case ULT:
+       case UGE:
+       case UGT:
+       case EQ:
+       case NE:
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+       case ANDAND:
+       case OROR:
+       case NOT:
+#ifdef SPECIAL_CCODES
+#error fix for private CCODES handling
+#else
+               r = p1alloc();
+               *r = *p;
+               andorbr(r, -1, lbl = getlab());
+
+               tval = cstknode(p->n_type, p->n_df, p->n_ap);
+
+               ecode(buildtree(ASSIGN, p1tcopy(tval), bcon(1)));
+               branch(lbl2 = getlab());
+               plabel( lbl);
+               ecode(buildtree(ASSIGN, p1tcopy(tval), bcon(0)));
+               plabel( lbl2);
+
+               *p = *tval;
+               p1nfree(tval);
+
+#endif
+               break;
+       case CBRANCH:
+               andorbr(p->n_left, glval(p->n_right), -1);
+               p1nfree(p->n_right);
+               p->n_op = ICON; p->n_type = VOID;
+               break;
+       case COMOP:
+               cerror("COMOP error");
+
+       default:
+               if (ty == LTYPE)
+                       return;
+               rmcops(p->n_left);
+               if (ty == BITYPE)
+                       rmcops(p->n_right);
+       }
+}
+
+/*
+ * Return 1 if an assignment is found.
+ */
+static int
+has_se(P1ND *p)
+{
+       if (p->n_op == COMOP && p->n_left->n_op == GOTO)
+               return 1;
+       if (cdope(p->n_op) & ASGFLG)
+               return 1;
+       if (coptype(p->n_op) == LTYPE)
+               return 0;
+       if (has_se(p->n_left))
+               return 1;
+       if (coptype(p->n_op) == BITYPE)
+               return has_se(p->n_right);
+       return 0;
+}
+
+#ifndef FIELDOPS
+
+/* avoid promotion to int */
+#define        TYPMOD(o, p, n, t)      clocal(block(o, p, n, t, 0, 0))
+#define        TYPLS(p, n, t)  TYPMOD(LS, p, n, t)
+#define        TYPRS(p, n, t)  TYPMOD(RS, p, n, t)
+#define        TYPOR(p, q, t)  TYPMOD(OR, p, q, t)
+#define        TYPAND(p, q, t) TYPMOD(AND, p, q, t)
+
+/*
+ * Read an unaligned bitfield from position pointed to by p starting at
+ * off and size fsz and return a tree of type t with resulting data.
+ * ct is the type we must use to read data.
+ */
+static P1ND *
+rdualfld(P1ND *p, TWORD t, TWORD ct, int off, int fsz)
+{
+       int t2f, inbits, tsz, ctsz;
+       P1ND *q, *r;
+
+       ct = ENUNSIGN(ct);
+       ctsz = (int)tsize(ct, 0, 0);
+
+       /* traverse until first data byte */
+       for (t2f = 0; off >= ctsz; t2f++, off -= ctsz)
+               ;
+#ifdef UNALIGNED_ACCESS
+       /* try to squeeze it into an int */
+       if (off + fsz > ctsz && off + fsz <= SZINT) {
+               ct = UNSIGNED;
+               ctsz = SZINT;
+       }
+#endif
+       p = makety(p, PTR|ct, 0, 0, 0);
+       if (off + fsz <= ctsz) {
+               /* only one operation needed */
+               q = buildtree(UMUL, buildtree(PLUS, p, bcon(t2f)), 0);
+               if (!ISUNSIGNED(t)) {
+                       ct = DEUNSIGN(ct);
+                       q = makety(q, ct, 0, 0, 0);
+               }
+               q = TYPLS(q, bcon(ctsz-fsz-off), ct);
+               q = TYPRS(q, bcon(ctsz-fsz), ct);
+               q = makety(q, t, 0, 0, 0);
+       } else {
+               q = buildtree(UMUL, buildtree(PLUS, p1tcopy(p), bcon(t2f)), 0);
+               q = makety(TYPRS(q, bcon(off), ct), t, 0, 0, 0);
+               inbits = ctsz - off;
+               t2f++;
+
+               while (fsz > inbits) {
+                       r = buildtree(UMUL,
+                           buildtree(PLUS, p1tcopy(p), bcon(t2f)), 0);
+                       r = makety(r, t, 0, 0, 0);
+                       r = TYPLS(r, bcon(inbits), t);
+                       q = TYPOR(q, r, t);
+                       inbits += ctsz;
+                       t2f++;
+               }
+               /* sign/zero extend XXX - RS must sign extend */
+               tsz = (int)tsize(t, 0, 0);
+               if (!ISUNSIGNED(t)) {
+                       t = DEUNSIGN(t);
+                       q = makety(q, t, 0, 0, 0);
+               }
+               q = TYPLS(q, bcon(tsz-fsz), t);
+               q = TYPRS(q, bcon(tsz-fsz), t);
+               p1tfree(p);
+       }
+
+       return q;
+}
+
+/*
+ * Write val to a (unaligned) bitfield with length fsz positioned off bits  
+ * from d. Bitfield type is t, and type to use when writing is ct.
+ * neither f nor d should have any side effects if copied.
+ * Multiples of ct are supposed to be written without problems.
+ * Both val and d are free'd after use.
+ */
+static P1ND *
+wrualfld(P1ND *val, P1ND *d, TWORD t, TWORD ct, int off, int fsz)
+{ 
+       P1ND *p, *q, *r, *rn, *s;
+       int ctsz, t2f, inbits;
+       ctsz = (int)tsize(ct, 0, 0);
+  
+       ct = ENUNSIGN(ct);
+       d = makety(d, PTR|ct, 0, 0, 0);
+
+       for (t2f = 0; off >= ctsz; t2f++, off -= ctsz)
+               ;
+       if (off + fsz <= ctsz) {
+               r = tempnode(0, ct, 0, 0);
+
+               /* only one operation needed */
+               d = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0);  
+               p = p1tcopy(d); 
+               p = TYPAND(p, xbcon(~(SZMASK(fsz) << off), 0, ct), ct);
+
+               val = makety(val, ct, 0, 0, 0);
+               q = TYPAND(val, xbcon(SZMASK(fsz), 0, ct), ct);
+               q = buildtree(ASSIGN, p1tcopy(r), q);
+
+               q = TYPLS(q, bcon(off), ct);   
+               p = TYPOR(p, q, ct);
+               p = makety(p, t, 0, 0, 0);     
+               rn = buildtree(ASSIGN, d, p);
+               rn = buildtree(COMOP, rn, makety(r, t, 0, 0, 0));
+       } else {
+               s = makety(p1tcopy(val), t, 0, 0, 0);
+               s = TYPAND(s, xbcon(SZMASK(fsz), 0, t), t);
+
+               r = buildtree(UMUL, buildtree(PLUS, p1tcopy(d), bcon(t2f)), 0);
+               p = p1tcopy(r);
+               p = TYPAND(p, xbcon(SZMASK(off), 0, ct), ct);
+               q = p1tcopy(val); 
+               q = TYPLS(q, bcon(off), t);  
+               q = makety(q, ct, 0, 0, 0);
+               p = TYPOR(p, q, ct);
+               rn = buildtree(ASSIGN, r, p);
+               inbits = ctsz - off;
+               t2f++;
+
+               while (fsz > inbits+ctsz) {
+                       r = buildtree(UMUL,
+                           buildtree(PLUS, p1tcopy(d), bcon(t2f)), 0);
+                       q = p1tcopy(val);
+                       q = TYPRS(q, bcon(inbits), t);
+                       q = makety(q, ct, 0, 0, 0);
+                       rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, q));
+                       t2f++;
+                       inbits += ctsz;
+               }
+
+               r = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0);
+               p = p1tcopy(r);
+               p = TYPAND(p, makety(xbcon(~SZMASK(fsz-inbits), 0, ct),
+                   ct, 0, 0, 0), ct);
+               q = TYPRS(val, bcon(inbits), t);
+               q = TYPAND(q, xbcon(SZMASK(fsz-inbits), 0, t), t);
+               q = makety(q, ct, 0, 0, 0);
+               p = TYPOR(p, q, ct);
+               rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, p));
+               rn = buildtree(COMOP, rn, s);
+       }
+       return rn;
+}
+
+/*
+ * Rewrite bitfield operations to shifts.
+ */
+static P1ND *
+rmfldops(P1ND *p)
+{
+       TWORD t, ct;
+       P1ND *q, *r, *t1, *t2, *bt;
+       int fsz, foff;
+
+       if (p->n_op == FLD) {
+               /* Rewrite a field read operation */
+               fsz = UPKFSZ(p->n_rval);
+               foff = UPKFOFF(p->n_rval);
+               q = buildtree(ADDROF, p->n_left, NULL);
+
+               ct = t = p->n_type;
+#ifdef GCC_COMPAT
+               if (attr_find(p->n_ap, GCC_ATYP_PACKED) &&
+                   coptype(q->n_op) != LTYPE) {
+                       t1 = tempnode(0, q->n_type, 0, 0);
+                       bt = buildtree(ASSIGN, p1tcopy(t1), q);
+                       q = t1;
+#ifndef UNALIGNED_ACCESS
+                       ct = UCHAR;
+#endif
+               } else
+#endif
+                       bt = bcon(0);
+#if TARGET_ENDIAN == TARGET_BE
+               foff = (int)tsize(t, 0, 0) - fsz - foff;
+#endif
+               q = rdualfld(q, t, ct, foff, fsz);
+               if (fsz < SZINT)
+                       q = makety(q, INT, 0, 0, 0);
+               if (p->n_type != INT)
+                       q = makety(q, p->n_type, 0, 0, 0);
+               p->n_left = bt;
+               p->n_right = q;
+               p->n_op = COMOP;
+       } else if (((cdope(p->n_op)&ASGOPFLG) || p->n_op == ASSIGN ||
+           p->n_op == INCR || p->n_op == DECR) && p->n_left->n_op == FLD) {
+               /*
+                * Rewrite a field write operation
+                * More difficult than a read op since we must care
+                * about side effects.
+                */
+               q = p->n_left;
+               fsz = UPKFSZ(q->n_rval);
+               foff = UPKFOFF(q->n_rval);
+               t = q->n_left->n_type;
+#if TARGET_ENDIAN == TARGET_BE
+               foff = (int)tsize(t, 0, 0) - fsz - foff;
+#endif
+               bt = NULL;
+               if (p->n_right->n_op != ICON && p->n_right->n_op != NAME) {
+                       t2 = tempnode(0, p->n_right->n_type, 0, 0);
+                       bt = buildtree(ASSIGN, p1tcopy(t2), p->n_right);
+               } else
+                       t2 = p->n_right;
+
+               ct = t;
+#ifdef GCC_COMPAT
+#ifndef UNALIGNED_ACCESS
+               if (attr_find(q->n_ap, GCC_ATYP_PACKED))
+                       ct = UCHAR;
+#endif
+#endif
+               /* t2 is what we have to write (RHS of ASSIGN) */
+               /* bt is (eventually) something that must be written */
+
+               if (q->n_left->n_op == UMUL) {
+                       /* LHS of assignment may have side effects */
+                       q = q->n_left;
+                       t1 = tempnode(0, q->n_left->n_type, 0, 0);
+                       r = buildtree(ASSIGN, p1tcopy(t1), q->n_left);
+                       
+                       bt = bt ? block(COMOP, bt, r, INT, 0, 0) : r;
+                       q->n_left = t1;
+               }
+               t1 = buildtree(ADDROF, p->n_left->n_left, 0);
+
+               /* t1 is lval where to write (and read) */
+
+               if (p->n_op == ASSIGN) {
+                       q = wrualfld(t2, t1, t, ct, foff, fsz);
+                       if (bt)
+                               q = block(COMOP, bt, q, t, 0, 0);
+                       p1nfree(p->n_left);
+                       p->n_left = bcon(0);
+                       p->n_right = q;
+                       p->n_op = COMOP;
+               } else
+                       cerror("NOTASSIGN!");
+
+               t = p->n_type;
+               if (ISUNSIGNED(p->n_type)) {
+                       /* mask away unwanted bits */
+                       if ((t == LONGLONG && fsz == SZLONGLONG-1) ||
+                           (t == LONG && fsz == SZLONG-1) ||
+                           (t == INT && fsz == SZINT-1))
+                               p = buildtree(AND, p,
+                                   xbcon((1LL << fsz)-1, 0, t));
+               } else {
+                       /* Correct value in case of signed bitfield.  */
+                       if (t == LONGLONG)
+                               fsz = SZLONGLONG - fsz;
+                       else if (t == LONG)
+                               fsz = SZLONG - fsz;
+                       else
+                               fsz = SZINT - fsz;
+                       p = buildtree(LS, p, bcon(fsz));
+#ifdef RS_DIVIDES
+                       p = buildtree(RS, p, bcon(fsz));
+#else
+                       {
+                               p = buildtree(DIV, p, xbcon(1LL << fsz, 0, t));
+                               /* avoid wrong sign if divisor gets negative */
+                               if ((t == LONGLONG && fsz == SZLONGLONG-1) ||
+                                   (t == LONG && fsz == SZLONG-1) ||
+                                   (t == INT && fsz == SZINT-1))
+                                       p = buildtree(UMINUS, p, NULL);
+                       }
+#endif
+               }
+       }
+       if (coptype(p->n_op) != LTYPE)
+               p->n_left = rmfldops(p->n_left);
+       if (coptype(p->n_op) == BITYPE)
+               p->n_right = rmfldops(p->n_right);
+       return p;
+}
+#endif
+
+void
+ecomp(P1ND *p)
+{
+
+#ifdef PCC_DEBUG
+       if (edebug) {
+               printf("ecomp\n");
+               p1fwalk(p, eprint, 0);
+       }
+#endif
+       if (!reached) {
+               warner(Wunreachable_code);
+               reached = 1;
+       }
+       p = optim(p);
+#ifndef FIELDOPS
+       p = rmfldops(p);
+#endif
+       comops(p);
+       rmcops(p);
+       if (p->n_op == ICON && p->n_type == VOID)
+               p1tfree(p);
+       else
+               ecode(p);
+}
+
+
+#ifdef PASS1
+/* 
+ * Print out full tree.
+ * Nodes are already converted to pass2 style.
+ */
+static void    
+p2print(NODE *p)
+{
+       struct attr *ap;
+       int ty, i;
+
+       ty = optype(p->n_op);
+
+       printf("\" %d ", p->n_op);
+
+       printf("%d %d ", p->n_type, p->n_qual);
+       if (ty == LTYPE)
+               printf(CONFMT " ", p->n_lval);
+       if (ty != BITYPE) {
+               if (p->n_op != NAME && p->n_op != ICON)
+                       printf("%d ", p->n_rval);
+               }
+
+       /* handle special cases */
+       if (p->n_op == NAME || p->n_op == ICON ||
+           p->n_op == XASM || p->n_op == XARG)
+               printf("%s", p->n_name);
+
+       if (p->n_ap) {
+               printf(" + ");
+               for (ap = p->n_ap; ap; ap = ap->next) {
+                       printf("%d %d ", ap->atype, ap->sz);
+                       for (i = 0; i < ap->sz; i++)
+                               printf("%d ", ap->iarg(i));
+               }
+       }
+       printf("\n");
+
+       if (ty != LTYPE)
+               p2print(p->n_left);
+       if (ty == BITYPE)
+               p2print(p->n_right);
+}
+
+/*
+ * Print out the code trees for pass2.
+ * First on line is always a sync char, second is space:
+ *     ! - Prologue.
+ *     " - Node
+ *     ^ - Label
+ *     $ - Assembler statement
+ *     % - Epilog.
+ *     # - Line number
+ *     & - File name
+ *     * - Passthrough line.
+ */
+void
+pass2_compile(struct interpass *ip)
+{
+       struct interpass_prolog *ipp;
+       static int oldlineno;
+       int i;
+
+       if (oldlineno != ip->lineno)
+               printf("# %d\n", oldlineno = ip->lineno);
+
+       switch (ip->type) {
+       case IP_PROLOG:
+               ipp = (struct interpass_prolog *)ip;
+               printf("! %d %d %d %d %d %s\n",
+                   ipp->ipp_type, ipp->ipp_vis, ip->ip_lbl, ipp->ip_tmpnum,
+                   ipp->ip_lblnum, ipp->ipp_name);
+#ifdef TARGET_IPP_MEMBERS
+               printf("( ");
+               target_members_print_prolog(ipp);
+               printf("\n");
+#endif
+               break;
+       case IP_NODE:
+               p2print(ip->ip_node);
+               tfree(ip->ip_node);
+               break;
+       case IP_DEFLAB:
+               printf("^ %d\n", ip->ip_lbl);
+               break;
+       case IP_ASM:
+               printf("$ %s\n", ip->ip_asm);
+               break;
+       case IP_EPILOG:
+               ipp = (struct interpass_prolog *)ip;
+               printf("%% %d %d %d %d %s", 
+                   ipp->ipp_autos, ip->ip_lbl, ipp->ip_tmpnum,
+                   ipp->ip_lblnum, ipp->ipp_name);
+               if (ipp->ip_labels[0]) {
+                       for (i = 0; ipp->ip_labels[i]; i++)
+                               ;
+                       printf(" + %d", i);
+                       for (i = 0; ipp->ip_labels[i]; i++)
+                               printf(" %d", ipp->ip_labels[i]);
+               }
+               printf("\n");
+#ifdef TARGET_IPP_MEMBERS
+               printf(") ");
+               target_members_print_epilog(ipp);
+               printf("\n");
+#endif
+               break;
+       default:
+               cerror("Missing %d", ip->type);
+       }
+       free(ip);
+}
+#endif
+
+static char *
+sptostr(struct symtab *sp)
+{
+       char *cp = tmpalloc(32);
+       int n = sp->soffset;
+       if (n < 0)
+               n = -n;
+       snprintf(cp, 32, LABFMT, n);
+       return cp;
+}
+
+static NODE *
+p2tree(P1ND *p)
+{
+       struct attr *ap;
+       struct symtab *q;
+       NODE *np;
+       int ty;
+
+       myp2tree(p);  /* local action can be taken here */
+
+       /* Fix left imaginary types */
+       if (ISITY(BTYPE(p->n_type)))
+               MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT));
+
+       ty = coptype(p->n_op);
+       np = memset(talloc(), 0, sizeof(NODE));
+
+       /* Copy common data */
+       np->n_op = p->n_op;
+       np->n_type = p->n_type;
+       np->n_qual = p->n_qual;
+       if (ty != BITYPE)
+               np->n_rval = p->n_rval;
+       if (ty == LTYPE) {
+               slval(np, glval(p));
+       }
+
+       /* cleanup attributes.
+        * copy those that are supposed to go into pass2 */
+       for (ap = p->n_ap; ap; ap = ap->next)
+               if (ap->atype < ATTR_MI_MAX)
+                       np->n_ap = attr_add(np->n_ap, attr_dup(ap));
+
+       switch( p->n_op ){
+       case NAME:
+       case ICON:
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)
+#ifdef GCC_COMPAT
+                           || q->sflags == SLBLNAME
+#endif
+                           ) {
+                               np->n_name = sptostr(q);
+                               if ((q->sflags & SMASK) == SSTRING)
+                                       q->sflags |= SASG;
+                       } else
+                               np->n_name = getexname(q);
+               } else
+                       np->n_name = "";
+               break;
+
+       case STASG:
+       case STARG:
+       case STCALL:
+       case USTCALL:
+               ap = attr_new(ATTR_P2STRUCT, 2);
+               np->n_ap = attr_add(np->n_ap, ap);
+               /* STASG used for stack array init */
+               if (p->n_op == STASG && ISARY(p->n_type)) {
+                       int size1 = (int)tsize(p->n_type, p->n_left->n_df,
+                           p->n_left->n_ap)/SZCHAR;
+                       ap->iarg(0) = (int)tsize(p->n_type, p->n_right->n_df,
+                           p->n_right->n_ap)/SZCHAR;
+                       if (size1 < ap->iarg(0))
+                               ap->iarg(0) = size1;
+                       ap->iarg(1) = talign(p->n_type,
+                           p->n_left->n_ap)/SZCHAR;
+                       break;
+               }
+               /* set up size parameters */
+               ap->iarg(0) = (int)((tsize(STRTY, p->n_left->n_df,
+                   p->n_left->n_ap)+SZCHAR-1)/SZCHAR);
+               ap->iarg(1) = talign(STRTY,p->n_left->n_ap)/SZCHAR;
+               if (ap->iarg(1) == 0)
+                       ap->iarg(1) = 1; /* At least char for packed structs */
+               break;
+
+       case XARG:
+       case XASM:
+               np->n_name = tmpstrdup(p->n_name);
+               break;
+
+       default:
+               np->n_name = "";
+               }
+
+       if (ty != LTYPE)
+               np->n_left = p2tree(p->n_left);
+       if (ty == BITYPE)
+               np->n_right = p2tree(p->n_right);
+       return np;
+}
+
+
+/*
+ * Change void data types into char.
+ */
+static void
+delvoid(P1ND *p, void *arg)
+{
+       /* Convert "PTR undef" (void *) to "PTR uchar" */
+       if (BTYPE(p->n_type) == VOID)
+               p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+       if (BTYPE(p->n_type) == BOOL) {
+               if (p->n_op == SCONV && p->n_type == BOOL) {
+                       /* create a jump and a set */
+                       P1ND *r;
+                       int l, l2;
+
+                       r = tempnode(0, BOOL_TYPE, NULL, 0);
+                       cbranch(buildtree(EQ, p->n_left, bcon(0)),
+                           bcon(l = getlab()));
+                       *p = *r;
+                       ecode(buildtree(ASSIGN, p1tcopy(r), bcon(1)));
+                       branch(l2 = getlab());
+                       plabel(l);
+                       ecode(buildtree(ASSIGN, r, bcon(0)));
+                       plabel(l2);
+               } else
+                       p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE;
+       }
+               
+}
+
+/*
+ * Change calls inside calls to separate statement.
+ */
+static P1ND *
+deldcall(P1ND *p, int split)
+{
+       P1ND *q, *r;
+       int o = p->n_op;
+
+       if (cdope(o) & CALLFLG) {
+               if (split) {
+                       q = cstknode(p->n_type, p->n_df, p->n_ap);
+                       r = p1tcopy(q);
+                       q = block(ASSIGN, q, p, p->n_type, p->n_df, p->n_ap);
+                       ecode(q);
+                       return r;
+               }
+               split++;
+       }
+       if (coptype(o) == BITYPE)
+               p->n_right = deldcall(p->n_right, split);
+       if (coptype(o) != LTYPE)
+               p->n_left = deldcall(p->n_left, split);
+       return p;
+}
+
+#ifndef WORD_ADDRESSED
+
+static P1ND *
+pprop(P1ND *p, TWORD t, struct attr *ap)
+{
+       int o = p->n_op;
+       TWORD t2;
+
+#ifdef PCC_DEBUG
+       if (p->n_op == TEMP && p->n_type != t &&
+           !(ISPTR(p->n_type) && ISPTR(t))) {
+               cerror("TEMP type change: %x -> %x", p->n_type, t);
+       }
+#endif
+
+       p->n_type = t;
+       p->n_ap = ap;
+       switch (o) {
+       case UMUL:
+               t = INCREF(t);
+               break;
+       case ADDROF:
+               t2 = p->n_left->n_type;
+               if (p->n_left->n_op == TEMP) {
+                       /* Will be converted to memory in pass2 */
+                       /* Do not convert if:
+                        * - t2 not ptr and decref(t) != t2
+                        * - decref(t) not ptr and decref(t) != t2
+                        * XXX add PCONV again? Will be removed upwards.
+                        */
+                       if ((!ISPTR(t2) && DECREF(t) != t2) ||
+                           (ISPTR(t2) && !ISPTR(DECREF(t))))
+                               ; /* Cannot convert this */
+                       else
+                               p->n_left->n_type = DECREF(t);
+                       return p;
+               }
+               if (ISPTR(t2) && !ISPTR(DECREF(t)))
+                       break; /* not quite correct */
+               t = DECREF(t);
+               break;
+       case PCONV:
+               return p;
+
+       case PLUS:
+               if (!ISPTR(p->n_left->n_type)) {
+                       if (!ISPTR(p->n_right->n_type))
+                               cerror("%p: no * in PLUS", p);
+                       p->n_right = pprop(p->n_right, t, ap);
+               } else
+                       p->n_left = pprop(p->n_left, t, ap);
+               return p;
+
+       case MINUS:
+               if (ISPTR(p->n_left->n_type)) {
+                       if (ISPTR(p->n_right->n_type))
+                               break; /* change both */
+                       p->n_left = pprop(p->n_left, t, ap);
+               } else 
+                       p->n_right = pprop(p->n_right, t, ap);
+               return p;
+
+       case CALL:
+       case UCALL:
+       case STCALL: /* may end up here if struct passed in regs */
+       case USTCALL:
+               return p;
+
+       case STASG: /* if struct is cast to pointer */
+               return p;
+
+       case ASSIGN:
+               break;
+
+       case COMOP:
+               p->n_right = pprop(p->n_right, t, ap);
+               return p;
+
+       default:
+               if (coptype(o) == LTYPE)
+                       break;
+
+#ifdef PCC_DEBUG
+               p1fwalk(p, eprint, 0);
+#endif
+               cerror("pprop op error %d\n", o);
+       }
+       if (coptype(o) == BITYPE)
+               p->n_right = pprop(p->n_right, t, ap);
+       if (coptype(o) != LTYPE)
+               p->n_left = pprop(p->n_left, t, ap);
+       return p;
+}
+
+/*
+ * Search for PCONV's that can be removed while still keeping
+ * the type correctness.
+ */
+P1ND *
+rmpconv(P1ND *p)
+{
+       struct symtab *sp;
+       int o = p->n_op;
+       int ot = coptype(o);
+       P1ND *q, *l;
+
+       if (ot != LTYPE)
+               p->n_left = rmpconv(p->n_left);
+       if (ot == BITYPE)
+               p->n_right = rmpconv(p->n_right);
+       if (o != PCONV)
+               return p;
+       l = p->n_left;
+       if (nncon(l) || (cdope(l->n_op) & CALLFLG))
+               ; /* Let any nonamed constant be cast to pointer directly */
+       else if (l->n_type >= INTPTR && l->n_op == ICON) {
+               /* named constants only if >= pointer size */
+               /* create INTPTR type */
+               sp = l->n_sp;
+               l->n_sp = NULL;
+               concast(l, INTPTR);
+               l->n_sp = sp;
+       } else if (!ISPTR(l->n_type))
+               return p;
+       q = pprop(p->n_left, p->n_type, p->n_ap);
+       p1nfree(p);
+       return q;
+}
+#endif
+
+P1ND *
+optloop(P1ND *p)
+{
+       extern int usdnodes;
+       int n;
+
+       do {
+               n = usdnodes;
+               p = rmpconv(p);
+               p = optim(p);
+       } while (n != usdnodes);
+
+       return p;
+}
+
+void
+ecode(P1ND *p) 
+{
+       NODE *r;
+       /* walk the tree and write out the nodes.. */
+
+       if (nerrors)    
+               return;
+
+#ifdef GCC_COMPAT
+       {
+               P1ND *q = p;
+
+               if (q->n_op == UMUL)
+                       q = p->n_left;
+               if (cdope(q->n_op)&CALLFLG &&
+                   attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT))
+                       werror("return value ignored");
+       }
+#endif
+#ifndef WORD_ADDRESSED
+       p = rmpconv(p);
+#endif
+       p = optim(p);
+       p = deldcall(p, 0);
+       p1walkf(p, delvoid, 0);
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("Fulltree:\n"); 
+               p1fwalk(p, eprint, 0); 
+       }
+#endif
+       if (p->n_op == LABEL) {
+               plabel(glval(p->n_left));
+               p1tfree(p);
+               return;
+       }
+       r = p2tree(p);
+       p1tfree(p);
+       send_passt(IP_NODE, r);
+}
+
+/*
+ * Send something further on to the next pass.
+ */
+void
+send_passt(int type, ...)
+{
+       struct interpass *ip;
+       struct interpass_prolog *ipp;
+       extern int crslab;
+       va_list ap;
+       int sz;
+
+       va_start(ap, type);
+       if (cftnsp == NULL && type != IP_ASM) {
+#ifdef notyet
+               cerror("no function");
+#endif
+               if (type == IP_NODE)
+                       tfree(va_arg(ap, NODE *));
+               return;
+       }
+       if (type == IP_PROLOG || type == IP_EPILOG)
+               sz = sizeof(struct interpass_prolog);
+       else
+               sz = sizeof(struct interpass);
+
+       ip = xmalloc(sz);
+       ip->type = type;
+       ip->lineno = lineno;
+       switch (type) {
+       case IP_NODE:
+               ip->ip_node = va_arg(ap, NODE *);
+               break;
+       case IP_EPILOG:
+               if (!isinlining) {
+                       locctr(PROG, cftnsp);
+                       defloc(cftnsp);
+               }
+               /* FALLTHROUGH */
+       case IP_PROLOG:
+               inftn = type == IP_PROLOG ? 1 : 0;
+               ipp = (struct interpass_prolog *)ip;
+               memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0,
+                   sizeof(ipp->ipp_regs));
+               ipp->ipp_autos = va_arg(ap, int);
+               ipp->ipp_name = va_arg(ap, char *);
+               ipp->ipp_type = va_arg(ap, TWORD);
+               ipp->ipp_vis = va_arg(ap, int);
+               ip->ip_lbl = va_arg(ap, int);
+               ipp->ip_tmpnum = va_arg(ap, int);
+               ipp->ip_lblnum = crslab;
+               ipp->ip_labels = va_arg(ap, int *);;
+               if (type == IP_PROLOG)
+                       ipp->ip_lblnum-=2;
+               break;
+       case IP_DEFLAB:
+               ip->ip_lbl = va_arg(ap, int);
+               break;
+       case IP_ASM:
+               if (blevel == 0) { /* outside function */
+                       printf("%s", va_arg(ap, char *));
+                       va_end(ap);
+                       locctr(NOSEG, NULL);
+                       return;
+               }
+               ip->ip_asm = va_arg(ap, char *);
+               ip->ip_asm = tmpstrdup(ip->ip_asm);
+               break;
+       default:
+               cerror("bad send_passt type %d", type);
+       }
+       va_end(ap);
+       pass1_lastchance(ip); /* target-specific info */
+       if (isinlining)
+               inline_addarg(ip);
+       else
+               pass2_compile(ip);
+}
+
+char *
+copst(int op)
+{
+       if (op <= MAXOP)
+               return opst[op];
+#define        SNAM(x,y) case x: return #y;
+       switch (op) {
+       SNAM(QUALIFIER,QUALIFIER)
+       SNAM(CLASS,CLASS)
+       SNAM(RB,])
+       SNAM(DOT,.)
+       SNAM(ELLIPSIS,...)
+       SNAM(LB,[)
+       SNAM(TYPE,TYPE)
+       SNAM(COMOP,COMOP)
+       SNAM(QUEST,?)
+       SNAM(BIQUEST,?:)
+       SNAM(COLON,:)
+       SNAM(ANDAND,&&)
+       SNAM(OROR,||)
+       SNAM(NOT,!)
+       SNAM(CAST,CAST)
+       SNAM(PLUSEQ,+=)
+       SNAM(MINUSEQ,-=)
+       SNAM(MULEQ,*=)
+       SNAM(DIVEQ,/=)
+       SNAM(MODEQ,%=)
+       SNAM(ANDEQ,&=)
+       SNAM(OREQ,|=)
+       SNAM(EREQ,^=)
+       SNAM(LSEQ,<<=)
+       SNAM(RSEQ,>>=)
+       SNAM(INCR,++)
+       SNAM(DECR,--)
+       SNAM(STRING,STRING)
+       SNAM(SZOF,SIZEOF)
+       SNAM(ATTRIB,ATTRIBUTE)
+       SNAM(TYMERGE,TYMERGE)
+       SNAM(LABEL,LABEL)
+       SNAM(UPLUS,U+)
+       SNAM(ALIGN,ALIGNMENT)
+       SNAM(FUNSPEC,FUNSPEC)
+       SNAM(STREF,->)
+#ifdef GCC_COMPAT
+       SNAM(XREAL,__real__)
+       SNAM(XIMAG,__imag__)
+#endif
+       default:
+               cerror("bad copst %d", op);
+       }
+       return 0; /* XXX gcc */
+}
+
+int
+cdope(int op)
+{
+       if (op <= MAXOP)
+               return dope[op];
+       switch (op) {
+       case CLOP:
+       case STRING:
+       case QUALIFIER:
+       case CLASS:
+       case RB:
+       case ELLIPSIS:
+       case TYPE:
+       case ALIGN:
+       case FUNSPEC:
+               return LTYPE;
+       case DOT:
+       case SZOF:
+       case COMOP:
+       case QUEST:
+       case BIQUEST:
+       case COLON:
+       case LB:
+       case TYMERGE:
+       case STREF:
+               return BITYPE;
+       case XIMAG:
+       case XREAL:
+       case ATTRIB:
+       case LABEL:
+       case UPLUS:
+               return UTYPE;
+       case ANDAND:
+       case OROR:
+               return BITYPE|LOGFLG;
+       case NOT:
+               return UTYPE|LOGFLG;
+       case CAST:
+               return BITYPE|ASGFLG|ASGOPFLG;
+       case PLUSEQ:
+               return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG;
+       case MINUSEQ:
+               return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG;
+       case MULEQ:
+               return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG;
+       case OREQ:
+       case EREQ:
+       case ANDEQ:
+               return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG;
+       case DIVEQ:
+               return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG;
+       case MODEQ:
+               return BITYPE|DIVFLG|ASGFLG|ASGOPFLG;
+       case LSEQ:
+       case RSEQ:
+               return BITYPE|SHFFLG|ASGFLG|ASGOPFLG;
+       case INCR:
+       case DECR:
+               return BITYPE|ASGFLG;
+       }
+       cerror("cdope missing op %d", op);
+       return 0; /* XXX gcc */
+}
+
+/* 
+ * make a fresh copy of p
+ */
+P1ND *
+p1tcopy(P1ND *p) 
+{  
+       P1ND *q;
+
+       q = p1alloc();
+       *q = *p;
+
+       switch (coptype(q->n_op)) {
+       case BITYPE:
+               q->n_right = p1tcopy(p->n_right);
+               /* FALLTHROUGH */
+       case UTYPE: 
+               q->n_left = p1tcopy(p->n_left);
+       }
+
+       return(q);
+}
+
+P1ND *frelink;
+int usdnodes;
+/*
+ * Free a node, and return its left descendant.
+ * It is up to the caller to know whether the return value is usable.
+ */
+P1ND *
+p1nfree(P1ND *p)
+{
+       P1ND *l;
+#ifdef PCC_DEBUG_NODES
+       P1ND *q;
+#endif
+
+       if (p == NULL)
+               cerror("freeing blank node!");
+               
+       l = p->n_left;
+       if (p->n_op == FREE)
+               cerror("freeing FREE node", p);
+#ifdef PCC_DEBUG_NODES
+       q = frelink;
+       while (q != NULL) {
+               if (q == p)
+                       cerror("freeing free node %p", p);
+               q = q->n_left;
+       }
+#endif
+
+       if (ndebug)
+               printf("freeing p1node %p\n", p);
+       p->n_op = FREE;
+       p->n_left = frelink;
+       frelink = p;
+       usdnodes--;
+       return l;
+}
+
+P1ND *
+p1alloc(void)
+{
+       register P1ND *p;
+
+       usdnodes++;
+
+       if (frelink != NULL) {
+               p = frelink;
+               frelink = p->n_left;
+               if (p->n_op != FREE)
+                       cerror("node not FREE: %p", p);
+               if (ndebug)
+                       printf("alloc p1node %p from freelist\n", p);
+               return p;
+       }
+
+       p = stmtalloc(sizeof(P1ND));
+       p->n_op = FREE;
+       if (ndebug)
+               printf("alloc p1node %p from memory\n", p);
+       return p;
+}
+
+
+/*
+ * free the tree p
+ */
+void
+p1tfree(P1ND *p)
+{
+#ifdef PCC_DEBUG
+       if (p->n_op == FREE)
+               cerror("freeing FREE node");
+#endif
+       p1walkf(p, (void (*)(P1ND *, void *))p1nfree, 0);
+}
+
+void
+p1fwalk(P1ND *t, void (*f)(P1ND *, int, int *, int *), int down)
+{
+
+       int down1, down2;
+
+       more:
+       down1 = down2 = 0;
+
+       (*f)(t, down, &down1, &down2);
+
+       switch (coptype( t->n_op )) {
+
+       case BITYPE:
+               p1fwalk( t->n_left, f, down1 );
+               t = t->n_right;
+               down = down2;
+               goto more;
+
+       case UTYPE:
+               t = t->n_left;
+               down = down1;
+               goto more;
+
+       }
+}
+
+void
+p1walkf(P1ND *t, void (*f)(P1ND *, void *), void *arg)
+{
+       int opty;
+
+       opty = coptype(t->n_op);
+
+       if (opty != LTYPE)
+               p1walkf( t->n_left, f, arg );
+       if (opty == BITYPE)
+               p1walkf( t->n_right, f, arg );
+       (*f)(t, arg);
+}
+
+/*
+ * Do a preorder walk of the CM list p and apply function f on each element.
+ */
+void
+p1flist(P1ND *p, void (*f)(P1ND *, void *), void *arg)
+{
+       if (p->n_op == CM) {
+               (*f)(p->n_right, arg);
+               p1flist(p->n_left, f, arg);
+       } else
+               (*f)(p, arg);
+}
+
+/*
+ * The same as flist but postorder.
+ */
+void
+p1listf(P1ND *p, void (*f)(P1ND *))
+{
+       if (p->n_op == CM) {
+               p1listf(p->n_left, f);
+               (*f)(p->n_right);
+       } else
+               (*f)(p);
+}
+
+P1ND *
+nlabel(int label)
+{
+       return block(LABEL, bcon(label), NULL, 0, 0, 0);
+}
+
+/*
+ * set PROG-seg label.
+ */
+void
+plabel(int label)
+{
+       reached = 1; /* Will this always be correct? */
+       send_passt(IP_DEFLAB, label);
+}
+
+/*
+ * Perform integer promotion on node n.
+ */
+P1ND *
+intprom(P1ND *n)
+{
+       if (n->n_op == FLD && UPKFSZ(n->n_rval) < SZINT)
+               return makety(n, INT, 0, 0, 0);
+
+       if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) {
+               if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) ||
+                   (n->n_type == USHORT && MAX_USHORT > MAX_INT))
+                       return makety(n, UNSIGNED, 0, 0, 0);
+               return makety(n, INT, 0, 0, 0);
+       }
+       return n;
+}
+
+/*
+ * Return CON/VOL/0, whichever are active for the current type.
+ */
+int
+cqual(TWORD t, TWORD q)
+{
+       while (ISARY(t))
+               t = DECREF(t), q = DECQAL(q);
+       if (t <= BTMASK)
+               q <<= TSHIFT;
+       return q & (CON|VOL);
+}
+
+int crslab = 11;
+/*
+ * Return a number for internal labels.
+ */
+int
+getlab(void)
+{
+       int l2 = crslab++;
+       crslab++;
+       return l2;
+}
diff --git a/lang/pcc/pcc/cc/cpp/Makefile.in b/lang/pcc/pcc/cc/cpp/Makefile.in
new file mode 100644 (file)
index 0000000..7df86a5
--- /dev/null
@@ -0,0 +1,82 @@
+#      $Id: Makefile.in,v 1.54 2016/03/08 18:42:13 ragge Exp $
+#
+# Makefile.in for cpp
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+CC = @CC@
+EXEEXT = @EXEEXT@
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ \
+       -I$(srcdir) -I$(top_builddir) -I$(builddir) -I$(MIPDIR) -I$(MDIR) \
+       -I$(COMMONDIR)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+TARGMACH = @targmach@
+
+MIPDIR=$(top_srcdir)/mip
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+COMMONDIR=$(top_srcdir)/common
+
+DEST=@BINPREFIX@cpp$(EXEEXT)
+MANPAGE=@BINPREFIX@cpp
+
+all: $(DEST)
+
+OBJS=  compat.o cpp.o cpc.o token.o
+HDRS=  cpp.h
+
+$(OBJS): $(HDRS)
+
+compat.o: $(COMMONDIR)/compat.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c
+
+cpp.o: $(srcdir)/cpp.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cpp.c
+
+cpc.o: $(srcdir)/cpc.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cpc.c
+
+token.o: $(srcdir)/token.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/token.c
+
+$(DEST): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+test: $(DEST)
+       @for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do     \
+               echo -n "test$${n} " ;                                  \
+               ./$(DEST) < tests/test$${n} > tests/run$${n} &&         \
+               cmp tests/run$${n} tests/res$${n} && echo ;             \
+               if test -f tests/res$${n}C ; then                       \
+                       echo -n "test$${n}C " ;                         \
+                       ./$(DEST) -C < tests/test$${n} > tests/run$${n}C && \
+                       cmp tests/run$${n}C tests/res$${n}C && echo ;   \
+               fi ;                                                    \
+       done
+
+install:
+       test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)"
+       $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir)
+       test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1"
+       $(INSTALL_DATA) $(srcdir)/cpp.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1
+
+clean:
+       rm -f $(OBJS) $(DEST) tests/run*
+
+distclean: clean
+       rm -f Makefile
diff --git a/lang/pcc/pcc/cc/cpp/cpc.c b/lang/pcc/pcc/cc/cpp/cpc.c
new file mode 100644 (file)
index 0000000..a169482
--- /dev/null
@@ -0,0 +1,320 @@
+/*      $Id: cpc.c,v 1.7 2016/01/10 16:17:45 ragge Exp $      */
+
+/*
+ * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Small recursive parser for #if statements.
+ */
+
+#include "cpp.h"
+
+static int ctok;
+
+typedef struct nd ND;
+struct nd yynode;
+
+void qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3);
+void shft(void);
+int yyparse(void);
+void expr(ND *n1);
+void eqcol(ND *n1);
+void eoror(ND *n1);
+void eandand(ND *n1);
+void exor(ND *n1);
+void eand(ND *n1);
+void eqne(ND *n1);
+void eget(ND *n1);
+void elrs(ND *n1);
+void eplmin(ND *n1);
+void emdv(ND *n1);
+void eterm(ND *n1);
+void eval(int op, ND *n1, ND *n2);
+
+
+void
+shft(void)
+{
+       ctok = yylex();
+}
+
+int
+yyparse(void)
+{
+       ND n1;
+
+       shft();
+       expr(&n1);
+       if (n1.op == 0)
+               error("division by zero");
+       if (ctok != WARN)
+               error("junk after expression");
+       return (int)n1.nd_val;
+}
+
+/*
+ * evaluate a complete preprocessor #if expression.
+ */
+void
+expr(ND *n1)
+{
+       for (;;) {
+               eqcol(n1);
+               if (ctok != ',')
+                       return;
+               shft();
+       }
+}
+
+/*
+ * evaluate ?: conditionals.
+ */
+void
+eqcol(ND *n1)
+{
+       ND n2, n3;
+
+       eoror(n1);
+       if (ctok != '?')
+               return;
+
+       shft();
+       expr(&n2);
+       if (ctok != ':')
+               error("no : found");
+       shft();
+       eqcol(&n3);
+       if (n1->nd_val) 
+               n1->nd_val = n2.nd_val, n1->op = n2.op;
+       else
+               n1->nd_val = n3.nd_val, n1->op = n3.op;
+}
+
+void
+eoror(ND *n1)
+{
+       qloop(eandand, n1, OROR, 0, 0, 0);
+}
+
+void
+eandand(ND *n1)
+{
+       qloop(exor, n1, ANDAND, 0, 0, 0);
+}
+
+void
+exor(ND *n1)
+{
+       qloop(eand, n1, '|', '^', 0, 0);
+}
+
+void
+eand(ND *n1)
+{
+       qloop(eqne, n1, '&', 0, 0, 0);
+}
+
+void
+eqne(ND *n1)
+{
+       qloop(eget, n1, EQ, NE, 0, 0);
+}
+
+void
+eget(ND *n1)
+{
+       qloop(elrs, n1, '<', '>', LE, GE);
+}
+
+void
+elrs(ND *n1)
+{
+       qloop(eplmin, n1, LS, RS, 0, 0);
+}
+
+void
+eplmin(ND *n1)
+{
+       qloop(emdv, n1, '+', '-', 0, 0);
+}
+
+void
+emdv(ND *n1)
+{
+       qloop(eterm, n1, '*', '/', '%', 0);
+}
+
+/*
+ * Loop to evaluate all operators on the same precedence level.
+ */
+void
+qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3)
+{
+       ND n2;
+       int op;
+
+       fun(n1);
+       while (ctok == a0 || ctok == a1 || ctok == a2 || ctok == a3) {
+               op = ctok;
+               shft();
+               fun(&n2);
+               eval(op, n1, &n2);
+       }
+}
+
+static void
+gnum(int o, ND *n1)
+{
+       n1->op = yynode.op;
+       n1->nd_val = yynode.nd_val;
+       shft();
+}
+
+/*
+ * Highest precedence operators + numeric terminals.
+ */
+void
+eterm(ND *n1)
+{
+       int o = ctok;
+
+       switch (o) {
+       case '~':
+       case '!':
+       case '+':
+       case '-':
+               shft();
+               eterm(n1);
+               eval(o, n1, 0);
+               break;
+
+       case NUMBER:
+       case UNUMBER:
+               gnum(o, n1);
+               break;
+
+       case '(':
+               shft();
+               expr(n1);
+               if (ctok == ')') {
+                       shft();
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               error("bad terminal (%d)", o);
+               break;
+       }
+}
+
+/*
+ * keep all numeric evaluation here.
+ * evaluated value returned in n1.
+ */
+void
+eval(int op, ND *n1, ND *n2)
+{
+
+       if ((op == '/' || op == '%') && n2->nd_val == 0)
+               n1->op = 0;
+
+       if (n1->op == 0)
+               return; /* div by zero involved */
+
+       /* unary ops */
+       if (n2 == 0) {
+               switch (op) {
+               case '+': break;
+               case '-': n1->nd_val = -n1->nd_val; break;
+               case '~': n1->nd_val = ~n1->nd_val; break;
+               case '!': n1->nd_val = !n1->nd_val; n1->op = NUMBER; break;
+               }
+               return;
+       } 
+
+       if (op == OROR && n1->nd_val) {
+               n1->nd_val = 1, n1->op = NUMBER;
+               return;
+       }
+       if (op == ANDAND && n1->nd_val == 0) {
+               n1->op = NUMBER;
+               return;
+       }
+
+       if (n2->op == 0) {
+               n1->op = 0;
+               return;
+       }
+
+       if (n2->op == UNUMBER)
+               n1->op = UNUMBER;
+
+       switch (op) {
+       case OROR:
+               if (n2->nd_val)
+                       n1->nd_val = 1;
+               n1->op = NUMBER;
+               break;
+       case ANDAND:
+               n1->nd_val = n2->nd_val != 0;
+               n1->op = NUMBER;
+               break;
+       case '+': n1->nd_val += n2->nd_val; break;
+       case '-': n1->nd_val -= n2->nd_val; break;
+       case '|': n1->nd_val |= n2->nd_val; break;
+       case '^': n1->nd_val ^= n2->nd_val; break;
+       case '&': n1->nd_val &= n2->nd_val; break;
+       case LS: n1->nd_val <<= n2->nd_val; break;
+       case EQ: n1->nd_val = n1->nd_val == n2->nd_val; n1->op = NUMBER; break;
+       case NE: n1->nd_val = n1->nd_val != n2->nd_val; n1->op = NUMBER; break;
+       }
+
+       if (n1->op == NUMBER) {
+               switch (op) {
+               case '*': n1->nd_val *= n2->nd_val; break;
+               case '/': n1->nd_val /= n2->nd_val; break;
+               case '%': n1->nd_val %= n2->nd_val; break;
+               case '<': n1->nd_val = n1->nd_val < n2->nd_val; break;
+               case '>': n1->nd_val = n1->nd_val > n2->nd_val; break;
+               case LE: n1->nd_val = n1->nd_val <= n2->nd_val; break;
+               case GE: n1->nd_val = n1->nd_val >= n2->nd_val; break;
+               case RS: n1->nd_val >>= n2->nd_val; break;
+               }
+               return;
+       } else /* op == UNUMBER */ {
+               switch (op) {
+               case '*': n1->nd_uval *= n2->nd_uval; break;
+               case '/': n1->nd_uval /= n2->nd_uval; break;
+               case '%': n1->nd_uval %= n2->nd_uval; break;
+               case '<': n1->nd_uval = n1->nd_uval < n2->nd_uval; break;
+               case '>': n1->nd_uval = n1->nd_uval > n2->nd_uval; break;
+               case LE: n1->nd_uval = n1->nd_uval <= n2->nd_uval; break;
+               case GE: n1->nd_uval = n1->nd_uval >= n2->nd_uval; break;
+               case RS: n1->nd_uval >>= n2->nd_uval; break;
+               }
+               return;
+       }
+       error("unexpected arithmetic");
+}
diff --git a/lang/pcc/pcc/cc/cpp/cpp.1 b/lang/pcc/pcc/cc/cpp/cpp.1
new file mode 100644 (file)
index 0000000..ea8b63a
--- /dev/null
@@ -0,0 +1,267 @@
+.\"    $Id: cpp.1,v 1.17 2013/02/26 19:27:38 plunky Exp $
+.\"
+.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
+.\"
+.\" Permission to use, copy, modify, and/or distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
+.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
+.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+.\" THIS SOFTWARE.
+.\"
+.Dd February 26, 2013
+.Dt CPP 1
+.Os
+.Sh NAME
+.Nm cpp
+.Nd C preprocessor
+.Sh SYNOPSIS
+.Nm
+.Op Fl ACEMPtVv
+.Op Fl D Ar macro Ns Oo = Ns Ar value Oc
+.Op Fl d Ar flags
+.Op Fl I Ar path
+.Op Fl i Ar file
+.Op Fl S Ar path
+.Op Fl U Ar macro
+.Op Ar infile | -
+.Op Ar outfile
+.Sh DESCRIPTION
+The
+.Nm
+utility is a macro preprocessor used by the
+.Xr pcc 1
+compiler.
+It is mainly used to include header files,
+expand macro definitions,
+discard comments,
+and perform conditional compilation.
+.Nm
+is written to comply with the
+.St -isoC-99
+specification.
+.Pp
+The
+.Ar infile
+input file is optional.
+If not provided or the file name is
+.Qq -
+(dash),
+.Nm
+reads its initial file from standard input.
+The
+.Ar outfile
+output file is also optional, with output written to standard
+output if not provided.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl A
+For assembler-with-cpp input: treat non-directive lines starting
+with a # as comments.
+.It Fl C
+Do not discard comments.
+.It Fl D Ar macro Ns Oo = Ns Ar value Oc
+Create a macro definition before processing any input, as if a
+.Lp
+.Dl #define Ar macro Ar value
+.Lp
+directive had appeared in the source.
+If
+.Ar value
+is not set on the command-line, then a value of 1 is used.
+.It Fl d Ar flags
+Modify output according to
+.Ar flags ,
+which can be a list of character flags.
+The following flags are currently supported:
+.Bl -tag -width ".Sy M"
+.It Sy M
+Do not process any input, but output a list of
+.Dq #define
+statements for all defined macros other than builtin macros
+.Pq see below .
+.El
+.Lp
+any unknown flags are ignored.
+.It Fl E
+Modify the exit code, if there were any warnings.
+.It Fl I Ar path
+Add
+.Ar path
+to the list of directories searched by the
+.Dq #include
+directive.
+This may be used to override system include directories
+.Pq see Fl S No option .
+.Fl I
+may be specified multiple times and is cumulative.
+.It Fl i Ar file
+Include a file before processing any input, as if a
+.Lp
+.Dl #include Qo Ar file Qc
+.Lp
+directive had appeared in the source.
+.Fl i
+may be specified multiple times to include several files.
+.It Fl M
+Instead of producing a processed C code file, output a list
+of dependencies for
+.Xr make 1 ,
+detailing the files that need to be processed when compiling
+the input.
+.It Fl P
+Inhibit generation of line markers.  This is sometimes useful when
+running the preprocessor on something other than C code.
+.It Fl S Ar path
+Add
+.Ar path
+to the list of system directories searched by the
+.Dq #include
+directive.
+The
+.Fl S
+option may be specified multiple times and is cumulative.
+.It Fl t
+Traditional cpp syntax.
+Do not define the
+.Dv __TIME__ ,
+.Dv __DATE__ ,
+.Dv __STDC__ ,
+and
+.Dv __STDC_VERSION__
+macros.
+.It Fl U Ar macro
+Undefine a macro before processing any input, as if a
+.Lp
+.Dl #undef Ar macro
+.Lp
+directive had appeared in the source.
+.It Fl V
+Verbose debugging output.
+.Fl V
+can be repeated for greater detail.
+.Po
+This is only available if the
+.Nm
+program was built with
+.Dv PCC_DEBUG
+defined, which is the default
+.Pc .
+.It Fl v
+Display version.
+.El
+.Pp
+The
+.Fl D ,
+.Fl i
+and
+.Fl U
+options are processed in the order that they appear on the command
+line, before any input is read but after the command line options
+have been scanned.
+.Pp
+Files referenced by the
+.Dq #include
+directive as
+.Qq ... ,
+are first looked for in the current directory, then as per
+.Aq ...
+files, which are first looked for in the list of
+directories provided by any
+.Fl I
+options, then in the list of system directories provided by any
+.Fl S
+options.
+Note that
+.Nm
+does not define any include directories by default; if no
+.Fl I
+or
+.Fl S
+options are given, then only the current directory will be
+searched and no system files will be found.
+.Ss Builtin Macros
+A few macros are interpreted inside the
+.Nm cpp
+program:
+.Bl -diag
+.It __DATE__
+Expands to a quoted string literal containing the date in the form
+.Qq Mmm dd yyyy ,
+where the names of the months are the same as those generated by the
+.Xr asctime 3
+function, and the first character of dd is a space character if
+the value is less than 10.
+.It __FILE__
+Expands to a quoted string literal containing the presumed name of
+the current source file.
+When reading source from standard input, it expands to
+.Qq Aq stdin .
+.It __LINE__
+Expands to an integer constant representing the presumed line number
+of the source line containing the macro.
+.It __STDC__
+Expands to the integer constant
+.Dq 1 ,
+meaning that the compiler conforms to
+.St -isoC .
+.It __STDC_VERSION__
+Expands to the integer constant
+.Dq 199901L ,
+indicating that
+.Nm
+conforms to
+.St -isoC-99 .
+.It __TIME__
+Expands to a quoted string literal containing the time in the form
+.Qq hh:mm:ss
+as generated by the
+.Xr asctime 3
+function.
+.El
+.Pp
+Also see the
+.Fl t
+option.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Lp
+.Bl -tag -width Ds -offset indent -compact
+.It 0
+Successfully finished.
+.It 1
+An error occurred.
+.It 2
+The
+.Fl E
+option was given, and warnings were issued.
+.El
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr ccom 1 ,
+.Xr make 1 ,
+.Xr pcc 1 ,
+.Xr asctime 3
+.Sh HISTORY
+The
+.Nm
+command comes from the original Portable C Compiler by
+.An "S. C. Johnson" ,
+written in the late 70's.
+The code originates from the V6 preprocessor with some additions
+from V7 cpp and ansi/c99 support.
+.Pp
+A lot of the PCC code was rewritten by
+.An "Anders Magnusson" .
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
diff --git a/lang/pcc/pcc/cc/cpp/cpp.c b/lang/pcc/pcc/cc/cpp/cpp.c
new file mode 100644 (file)
index 0000000..05e4d37
--- /dev/null
@@ -0,0 +1,2598 @@
+/*     $Id: cpp.c,v 1.258 2016/03/14 20:27:56 ragge Exp $      */
+
+/*
+ * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The C preprocessor.
+ * This code originates from the V6 preprocessor with some additions
+ * from V7 cpp, and at last ansi/c99 support.
+ *
+ *     - kfind() expands the input buffer onto an output buffer.
+ *     - exparg() expand one buffer into another.
+ *             Recurses into submac() for fun-like macros.
+ *     - submac() replaces the given macro.
+ *             Recurses into subarg() for fun-like macros.
+ *     - subarg() expands fun-like macros.
+ *             Create strings, concats args, recurses into exparg.
+ */
+
+#include "config.h"
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "compat.h"
+#include "cpp.h"
+
+#ifndef S_ISDIR
+#define S_ISDIR(m)     (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/*
+ * Buffers used:
+ *     - expansion buffers (via getobuf etc...)
+ *     - string buffers (used to store macros)
+ *     - tree buffers (used by macro search algorithm)
+ *     - scratch buffer (identifier readin)
+ */
+
+
+
+
+#define        SBSIZE  1000000
+
+static usch    sbf[SBSIZE];
+static int     counter;
+/* C command */
+
+int tflag;     /* traditional cpp syntax */
+#ifdef PCC_DEBUG
+int dflag;     /* debug printouts */
+//static void imp(const char *);
+static void prline(const usch *s);
+static void prrep(const usch *s);
+#define        DPRINT(x) if (dflag) printf x
+#define        DDPRINT(x) if (dflag > 1) printf x
+#define        IMP(x) if (dflag > 1) imp(x)
+#else
+#define DPRINT(x)
+#define DDPRINT(x)
+#define IMP(x)
+#endif
+
+int Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag;
+char *Mfile, *MPfile;
+struct initar *initar;
+char *Mxfile;
+int warnings, Mxlen;
+FILE *of;
+
+/* include dirs */
+struct incs {
+       struct incs *next;
+       usch *dir;
+       dev_t dev;
+       ino_t ino;
+} *incdir[2];
+
+static struct symtab *filloc;
+static struct symtab *linloc;
+static struct symtab *pragloc;
+static struct symtab *defloc;
+static struct symtab *ctrloc;
+int    trulvl;
+int    flslvl;
+int    elflvl;
+int    elslvl;
+usch *stringbuf = sbf;
+
+/*
+ * Macro replacement list syntax:
+ * - For object-type macros, replacement strings are stored as-is.
+ * - For function-type macros, macro args are substituted for the
+ *   character WARN followed by the argument number.
+ * - The value element points to the beginning of the string.
+ *
+ * The first character in the replacement list is the number of arguments:
+ *   VARG  - ends with ellipsis, next char is argcount without ellips.
+ *   OBJCT - object-type macro
+ *   0    - empty parenthesis, foo()
+ *   1->   - number of args.
+ *
+ * WARN is used:
+ *     - in stored replacement lists to tell that an argument comes
+ *     - When expanding replacement lists to tell that the list ended.
+ *
+ * To ensure that an already expanded identifier won't get expanded
+ * again a EBLOCK char + its number is stored directly before any
+ * expanded identifier.
+ */
+
+/* args for lookup() */
+#define        FIND    0
+#define        ENTER   1
+
+/*
+ * No-replacement array.  If a macro is found and exists in this array
+ * then no replacement shall occur.
+ */
+struct blocker {
+       struct blocker *next;
+       struct symtab *sp;
+};
+struct blocker *blkidx[RECMAX];
+int blkidp;
+
+static struct iobuf *readargs2(usch **, struct symtab *sp, const usch **args);
+static int readargs1(struct symtab *sp, const usch **args);
+static struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *);
+static struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *);
+static void usage(void);
+static usch *xstrdup(const usch *str);
+static void addidir(char *idir, struct incs **ww);
+static void vsheap(struct iobuf *, const char *, va_list);
+static int skipws(struct iobuf *ib);
+static int getyp(usch *s);
+
+usch locs[] =
+       { FILLOC, LINLOC, PRAGLOC, DEFLOC,
+           'd','e','f','i','n','e','d',0, CTRLOC };
+
+int
+main(int argc, char **argv)
+{
+       struct initar *it;
+       register int ch;
+       const usch *fn1, *fn2;
+
+#ifdef TIMING
+       struct timeval t1, t2;
+
+       (void)gettimeofday(&t1, NULL);
+#endif
+
+       while ((ch = getopt(argc, argv, "ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
+               switch (ch) {
+               case 'A': /* assembler input */
+                       Aflag++;
+                       break;
+
+               case 'C': /* Do not discard comments */
+                       Cflag++;
+                       break;
+
+               case 'E': /* treat warnings as errors */
+                       Eflag++;
+                       break;
+
+               case 'D': /* define something */
+               case 'i': /* include */
+               case 'U': /* undef */
+                       /* XXX should not need malloc() here */
+                       if ((it = xmalloc(sizeof(struct initar))) == NULL)
+                               error("couldn't apply -%c %s", ch, optarg);
+                       it->type = ch;
+                       it->str = optarg;
+                       it->next = initar;
+                       initar = it;
+                       break;
+
+               case 'd':
+                       while (*optarg) {
+                               switch(*optarg) {
+                               case 'M': /* display macro definitions */
+                                       dMflag = 1;
+                                       Mflag = 1;
+                                       break;
+
+                               default: /* ignore others */
+                                       break;
+                               }
+                               optarg++;
+                       }
+                       break;
+
+               case 'I':
+               case 'S':
+                       addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
+                       break;
+
+               case 'M': /* Generate dependencies for make */
+                       Mflag++;
+                       break;
+
+               case 'P': /* Inhibit generation of line numbers */
+                       Pflag++;
+                       break;
+
+               case 't':
+                       tflag = 1;
+                       break;
+
+#ifdef PCC_DEBUG
+               case 'V':
+                       dflag++;
+                       break;
+#endif
+               case 'v':
+                       fprintf(stderr, "PCC preprocessor version "VERSSTR"\n");
+                       break;
+
+               case 'x':
+                       if (strcmp(optarg, "MMD") == 0) {
+                               MMDflag++;
+                       } else if (strcmp(optarg, "MP") == 0) {
+                               MPflag++;
+                       } else if (strncmp(optarg, "MT,", 3) == 0 ||
+                           strncmp(optarg, "MQ,", 3) == 0) {
+                               int l = strlen(optarg+3) + 2;
+                               char *cp, *up;
+
+                               if (optarg[1] == 'Q')
+                                       for (cp = optarg+3; *cp; cp++)
+                                               if (*cp == '$')
+                                                       l++;
+                               Mxlen += l;
+                               Mxfile = cp = realloc(Mxfile, Mxlen);
+                               for (up = Mxfile; *up; up++)
+                                       ;
+                               if (up != Mxfile)
+                                       *up++ = ' ';
+                               for (cp = optarg+3; *cp; cp++) {
+                                       *up++ = *cp;
+                                       if (optarg[1] == 'Q' && *cp == '$')
+                                               *up++ = *cp;
+                               }
+                               *up = 0;
+                       } else
+                               usage();
+                       break;
+
+               case '?':
+               default:
+                       usage();
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       filloc = lookup((const usch *)"__FILE__", ENTER);
+       linloc = lookup((const usch *)"__LINE__", ENTER);
+       pragloc = lookup((const usch *)"_Pragma", ENTER);
+       defloc = lookup((const usch *)"defined", ENTER);
+       ctrloc = lookup((const usch *)"__COUNTER__", ENTER);
+       filloc->value = locs;
+       linloc->value = locs+1;
+       pragloc->value = locs+2;
+       defloc->value = locs+3; /* also have macro name here */
+       ctrloc->value = locs+12;
+
+       if (Mflag && !dMflag) {
+               char *c;
+
+               if (argc < 1)
+                       error("-M and no infile");
+               if ((c = strrchr(argv[0], '/')) == NULL)
+                       c = argv[0];
+               else
+                       c++;
+               Mfile = (char *)xstrdup((usch *)c);
+               if (MPflag)
+                       MPfile = (char *)xstrdup((usch *)c);
+               if (Mxfile)
+                       Mfile = Mxfile;
+               if ((c = strrchr(Mfile, '.')) == NULL)
+                       error("-M and no extension: ");
+               c[1] = 'o';
+               c[2] = 0;
+       }
+
+       if (argc == 2) {
+               if ((of = freopen(argv[1], "w", stdout)) == NULL)
+                       error("Can't creat %s", argv[1]);
+       } else
+               of = stdout;
+
+       if (argc && strcmp(argv[0], "-")) {
+               fn1 = fn2 = (usch *)argv[0];
+       } else {
+               fn1 = NULL;
+               fn2 = (const usch *)"";
+       }
+       if (pushfile(fn1, fn2, 0, NULL))
+               error("cannot open %s", argv[0]);
+
+       fclose(of);
+#ifdef TIMING
+       (void)gettimeofday(&t2, NULL);
+       t2.tv_sec -= t1.tv_sec;
+       t2.tv_usec -= t1.tv_usec;
+       if (t2.tv_usec < 0) {
+               t2.tv_usec += 1000000;
+               t2.tv_sec -= 1;
+       }
+       fprintf(stderr, "cpp total time: %ld s %ld us\n",
+            (long)t2.tv_sec, (long)t2.tv_usec);
+#endif
+       if (Eflag && warnings > 0)
+               return 2;
+
+       return 0;
+}
+
+/*
+ * Write a character to an out buffer.
+ */
+void
+putob(struct iobuf *ob, int ch)
+{
+       if (ob->cptr == ob->bsz) {
+               int sz = ob->bsz - ob->buf;
+               ob->buf = xrealloc(ob->buf, sz + BUFSIZ);
+               ob->cptr = ob->buf + sz;
+               ob->bsz = ob->buf + sz + BUFSIZ;
+       }
+//     DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch));
+       *ob->cptr++ = ch;
+}
+
+static int nbufused;
+/*
+ * Write a character to an out buffer.
+ */
+struct iobuf *
+getobuf(void)
+{
+       struct iobuf *iob = xmalloc(sizeof(struct iobuf));
+
+       nbufused++;
+       iob->buf = iob->cptr = xmalloc(BUFSIZ);
+       iob->bsz = iob->buf + BUFSIZ;
+       iob->ro = 0;
+       return iob;
+}
+
+/*
+ * Create a read-only input buffer.
+ */
+static struct iobuf *
+mkrobuf(const usch *s)
+{
+       struct iobuf *iob = xmalloc(sizeof(struct iobuf));
+
+       nbufused++;
+       DPRINT(("mkrobuf %s\n", s));
+       iob->buf = iob->cptr = (usch *)s;
+       iob->bsz = iob->buf + strlen((char *)iob->buf);
+       iob->ro = 1;
+       return iob;
+}
+
+/*
+ * Copy a string to a buffer.
+ */
+static struct iobuf *
+strtobuf(usch *str, struct iobuf *iob)
+{
+       DPRINT(("strtobuf iob %p buf %p str %s\n", iob, iob->buf, str));
+       if (iob == NULL)
+               iob = getobuf();
+       do {
+               putob(iob, *str);
+       } while (*str++);
+       iob->cptr--;
+       return iob;
+}
+
+static usch *macbase;
+static int macpos, cmbase;
+
+static void
+macsav(int ch)
+{
+       if (macbase == NULL)
+               macbase = xmalloc(CPPBUF);
+       if (macpos == CPPBUF) {
+               usch *tb;
+               if (cmbase == 0)
+                       error("macro too large");
+               tb = xmalloc(CPPBUF);
+               memcpy(tb, macbase+cmbase, CPPBUF-cmbase);
+               xrealloc(macbase, cmbase);
+               macpos -= cmbase;
+               cmbase = 0;
+               macbase = tb;
+       }
+       macbase[macpos++] = ch;
+}
+
+static void                     
+macstr(const usch *s)
+{
+       do {
+               macsav(*s);
+       } while (*s++ != 0);
+       macpos--;
+}
+
+#define        setcmbase()     cmbase = macpos
+#define        clrcmbase()     macpos = cmbase
+
+void
+bufree(struct iobuf *iob)
+{
+       nbufused--;
+       if (iob->ro == 0)
+               free(iob->buf);
+       free(iob);
+}
+
+static void
+addidir(char *idir, struct incs **ww)
+{
+       struct incs *w;
+       struct stat st;
+
+       if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
+               return; /* ignore */
+       if (*ww != NULL) {
+               for (w = *ww; w->next; w = w->next) {
+#ifdef _WIN32
+                       if (strcmp(w->dir, idir) == 0)
+                               return;
+#else
+                       if (w->dev == st.st_dev && w->ino == st.st_ino)
+                               return;
+#endif
+               }
+#ifdef _WIN32
+               if (strcmp(w->dir, idir) == 0)
+                       return;
+#else
+               if (w->dev == st.st_dev && w->ino == st.st_ino)
+                       return;
+#endif
+               ww = &w->next;
+       }
+       if ((w = calloc(sizeof(struct incs), 1)) == NULL)
+               error("couldn't add path %s", idir);
+       w->dir = (usch *)idir;
+       w->dev = st.st_dev;
+       w->ino = st.st_ino;
+       *ww = w;
+}
+
+void
+line(void)
+{
+       struct iobuf *ob;
+       struct symtab *nl;
+       int c, n, ln;
+       usch *cp, *dp;
+
+       c = skipws(0);
+       if (ISID0(c)) { /* expand macro */
+               dp = readid(c);
+               if ((nl = lookup(dp, FIND)) == 0 || (ob = kfind(nl)) == 0)
+                       goto bad;
+       } else {
+               ob = getobuf();
+               do {
+                       putob(ob, c);
+               } while (ISDIGIT(c = cinput()));
+               cunput(c);
+               putob(ob, 0);
+       }
+       cp = ob->buf;
+
+       n = 0;
+       while (ISDIGIT(*cp))
+               n = n * 10 + *cp++ - '0';
+       if (*cp != 0)
+               goto bad;
+       bufree(ob);
+
+       /* Can only be decimal number here between 1-2147483647 */
+       if (n < 1 || n > 2147483647)
+               goto bad;
+
+       ln = n;
+       ifiles->escln = 0;
+       if ((c = skipws(NULL)) != '\n') {
+               if (c == 'L' || c == 'U' || c == 'u') {
+                       n = c, c = cinput();
+                       if (n == 'u' && c == '8')
+                               c = cinput();
+                       if (c == '\"')
+                               warning("#line only allows character literals");
+               }
+               if (c != '\"')
+                       goto bad;
+
+               setcmbase();
+               ifiles->fname = macbase+1;
+               faststr(c, macsav);
+               macbase[--macpos] = 0;
+               if (strcmp((char *)ifiles->fname, (char *)macbase+cmbase+1))
+                       ifiles->fname = xstrdup(macbase+cmbase+1);
+               clrcmbase();
+
+               c = skipws(0);
+       }
+       if (c != '\n')
+               goto bad;
+
+       ifiles->lineno = ln;
+       prtline(1);
+       ifiles->lineno--;
+       cunput('\n');
+       return;
+
+bad:   error("bad #line");
+}
+
+#ifdef MACHOABI
+
+/*
+ * Search for framework header file.
+ * Return 1 on success.
+ */
+
+static int
+fsrch_macos_framework(const usch *fn, const usch *dir)
+{
+       usch *saved_stringbuf = stringbuf;
+       usch *s = (usch *)strchr((const char*)fn, '/');
+       usch *nm;
+       usch *p;
+       int len  = s - fn;
+
+       if (s == NULL)
+               return 0;
+
+//     fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir);
+
+       nm = savstr(dir);
+       savch(0);
+       p = savstr(fn);
+       stringbuf = p + len;
+       savch(0);
+//     fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn);
+       p = (usch *)strstr((const char *)nm, (const char *)p);
+//     fprintf(stderr, "p = %s\n", (const char *)p);
+       if (p != NULL) {
+               stringbuf = p;
+               savch(0);
+               return fsrch_macos_framework(fn, nm);
+       }
+
+       p = nm + strlen((char *)nm) - 1;
+       while (*p == '/')
+               p--;
+       while (*p != '/')
+               p--;
+       stringbuf = ++p;
+       savstr((const usch *)"Frameworks/");
+       stringbuf = savstr(fn) + len;
+       savstr((const usch*)".framework/Headers");
+       savstr(s);
+       savch(0);
+
+//     fprintf(stderr, "nm: %s\n", nm);
+
+       if (pushfile(nm, fn, SYSINC, NULL) == 0)
+               return 1;
+//     fprintf(stderr, "not found %s, continuing...\n", nm);
+
+       stringbuf = saved_stringbuf;
+
+       return 0;
+}
+
+#endif
+
+/*
+ * Search for and include next file.
+ * Return 1 on success.
+ */
+static int
+fsrch(const usch *fn, int idx, struct incs *w)
+{
+       int i;
+
+       setcmbase();
+       for (i = idx; i < 2; i++) {
+               if (i > idx)
+                       w = incdir[i];
+               for (; w; w = w->next) {
+                       macstr(w->dir); macsav('/');
+                       macstr(fn); macsav(0);
+                       if (pushfile(macbase+cmbase, fn, i, w->next) == 0)
+                               return 1;
+                       clrcmbase();
+               }
+       }
+
+#ifdef MACHOABI
+       /*
+        * On MacOS, we may have to do some clever stuff
+        * to resolve framework headers.
+        */
+       {
+               usch *dir = stringbuf;
+               savstr(ifiles->orgfn);
+               stringbuf = (usch *)strrchr((char *)dir, '/');
+               if (stringbuf != NULL) {
+                       stringbuf++;
+                       savch(0);
+                       if (fsrch_macos_framework(fn, dir) == 1)
+                               return 1;
+               }
+               stringbuf = dir;
+
+               if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1)
+                       return 1;
+
+               if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1)
+                       return 1;
+       }
+#endif
+
+       return 0;
+}
+
+static void
+prem(void)
+{
+       error("premature EOF");
+}
+
+static struct iobuf *
+incfn(void)
+{
+       struct iobuf *ob;
+       struct symtab *nl;
+       usch *dp;
+       int c;
+
+       if (spechr[c = skipws(NULL)] & C_ID0) {
+               dp = readid(c);
+               if ((nl = lookup(dp, FIND)) == NULL)
+                       return NULL;
+
+               if ((ob = kfind(nl)) == 0)
+                       return NULL;
+       } else {
+               ob = getobuf();
+               putob(ob, c);
+               while ((c = cinput()) && c != '\n')
+                       putob(ob, c);
+               if (c != '\n')
+                       return NULL;
+               cunput(c);
+       }
+
+       /* now we have an (expanded?) filename in obuf */
+       while (ob->buf < ob->cptr && ISWS(ob->cptr[-1]))
+               ob->cptr--;
+
+       if (ob->buf[0] != '\"' && ob->buf[0] != '<')
+               return NULL;
+       if (ob->cptr[-1] != '\"' && ob->cptr[-1] != '>')
+               return NULL;
+       ob->cptr[-1] = 0;
+       return ob;
+}
+
+/*
+ * Include a file. Include order:
+ * - For <...> files, first search -I directories, then system directories.
+ * - For "..." files, first search "current" dir, then as <...> files.
+ */
+void
+include(void)
+{
+       struct iobuf *ob;
+       usch *fn, *nm = NULL;
+
+       if (flslvl)
+               return;
+
+       if ((ob = incfn()) == NULL) /* get include file name in obuf */
+               error("bad #include");
+
+       fn = xstrdup(ob->buf) + 1;      /* Save on string heap? */
+       bufree(ob);
+       /* test absolute path first */
+       if (fn[0] == '/' && pushfile(fn, fn, 0, NULL) == 0)
+               goto okret;
+       if (fn[-1] == '\"') {
+               /* nope, failed, try to create a path for it */
+               if ((nm = (usch *)strrchr((char *)ifiles->orgfn, '/'))) {
+                       ob = strtobuf((usch *)ifiles->orgfn, NULL);
+                       ob->cptr = ob->buf + (nm - ifiles->orgfn) + 1;
+                       strtobuf(fn, ob);
+                       putob(ob, 0);
+                       nm = xstrdup(ob->buf);
+                       bufree(ob);
+               } else {
+                       nm = xstrdup(fn);
+               }
+               if (pushfile(nm, nm, 0, NULL) == 0) {
+                       free(fn-1);
+                       goto okret;
+               }
+       }
+       if (fsrch(fn, 0, incdir[0]))
+               goto okret;
+
+       error("cannot find '%s'", fn);
+       /* error() do not return */
+
+okret:
+       if (nm)
+               free(nm);
+       prtline(1);
+}
+
+void
+include_next(void)
+{
+       struct iobuf *ob;
+       usch *nm;
+
+       if (flslvl)
+               return;
+
+       if ((ob = incfn()) == NULL) /* get include file name in obuf */
+               error("bad #include_next");
+
+       nm = xstrdup(ob->buf+1);
+       bufree(ob);
+
+       if (fsrch(nm, ifiles->idx, ifiles->incs) == 0)
+               error("cannot find '%s'", nm);
+       prtline(1);
+}
+
+/*
+ * Compare two replacement lists, taking in account comments etc.
+ */
+static int
+cmprepl(const usch *o, const usch *n)
+{
+       for (; *o; o++, n++) {
+               /* comment skip */
+               if (*o == '/' && o[1] == '*') {
+                       while (*o != '*' || o[1] != '/')
+                               o++;
+                       o += 2;
+               }
+               if (*n == '/' && n[1] == '*') {
+                       while (*n != '*' || n[1] != '/')
+                               n++;
+                       n += 2;
+               }
+               while (*o == ' ' || *o == '\t')
+                       o++;
+               while (*n == ' ' || *n == '\t')
+                       n++;
+               if (*o != *n)
+                       return 1;
+       }
+       return 0;
+}
+
+static int
+isell(void)
+{
+       if (cinput() != '.' || cinput() != '.')
+               return 0;
+       return 1;
+}
+
+static int
+skipwscmnt(struct iobuf *ib)
+{
+       /* XXX comment */
+       return skipws(ib);
+}
+
+static int
+findarg(usch *s, usch **args, int narg)
+{
+       int i;
+
+       for (i = 0; i < narg; i++)
+               if (strcmp((char *)s, (char *)args[i]) == 0)
+                       return i;
+       return -1;
+}
+
+/*
+ * gcc extensions:
+ * #define e(a...) f(s, a) ->  a works as __VA_ARGS__
+ * #define e(fmt, ...) f(s, fmt , ##__VA_ARGS__) -> remove , if no args
+ */
+void
+define(void)
+{
+       struct symtab *np;
+       usch *args[MAXARGS+1], cc[2], *vararg, *dp;
+       int c, i, redef, oCflag, t;
+       int narg = -1;
+       int wascon;
+
+       if (flslvl)
+               return;
+
+       oCflag = Cflag, Cflag = 0; /* Ignore comments here */
+       if (!ISID0(c = skipws(0)))
+               goto bad;
+
+       setcmbase();
+       dp = readid(c);
+       np = lookup(dp, ENTER);
+       if (np->value) {
+               redef = 1;
+       } else {
+               np->namep = xstrdup(dp);
+               redef = 0;
+       }
+
+       vararg = NULL;
+       macsav(0); /* set type slot */
+       if ((c = cinput()) == '(') {
+               narg = 0;
+               /* function-like macros, deal with identifiers */
+               c = skipws(0);
+               for (;;) {
+                       switch (c) {
+                       case ')':
+                               break;
+                       case '.':
+                               if (isell() == 0 || (c = skipws(0)) != ')')
+                                       goto bad;
+                               vararg = (usch *)"__VA_ARGS__";
+                               break;
+                       default:
+                               if (!ISID0(c))
+                                       goto bad;
+
+                               dp = readid(c);
+                               /* make sure there is no arg of same name */
+                               if (findarg(dp, args, narg) >= 0)
+                                       error("Duplicate parameter \"%s\"", dp);
+                               if (narg == MAXARGS)
+                                       error("Too many macro args");
+                               args[narg++] = xstrdup(dp);
+                               switch ((c = skipws(0))) {
+                               case ',': break;
+                               case ')': continue;
+                               case '.':
+                                       if (isell() == 0 || skipws(0) != ')')
+                                               goto bad;
+                                       vararg = args[--narg];
+                                       c = ')';
+                                       continue;
+                               default:
+                                       goto bad;
+                               }
+                               c = skipws(0);
+                       }
+                       if (c == ')')
+                               break;
+               }
+               c = skipws(0);
+       } else if (c == '\n') {
+               /* #define foo */
+               ;
+       } else if (c == 0) {
+               prem();
+       } else if (!ISWS(c))
+               goto bad;
+
+       Cflag = oCflag; /* Enable comments again */
+
+       if (vararg)
+               macsav(0); /* for macro type */
+
+       if (ISWS(c))
+               c = skipwscmnt(0);
+
+#define        DELEWS() while (macpos > cmbase+1+(vararg!=NULL) && \
+       ISWS(macbase[macpos-1])) macpos--
+
+       /* parse replacement-list, substituting arguments */
+       wascon = 0;
+       while (c != '\n') {
+               cc[0] = c, cc[1] = inc2();
+               t = getyp(cc);
+               cunput(cc[1]);
+
+               switch (t) {
+               case ' ':
+               case '\t':
+                       macsav(' '); /* save only one space */
+                       while ((c = cinput()) == ' ' || c == '\t')
+                               ;
+                       continue;
+
+               case '#':
+                       if (cc[1] == '#') {
+                               /* concat op */
+                               (void)cinput(); /* eat # */
+                               DELEWS();
+                               macsav(CONC);
+                               if (ISID0(c = skipws(0)) && narg >= 0)
+                                       wascon = 1;
+                               if (c == '\n')
+                                       goto bad; /* 6.10.3.3 p1 */
+                               continue;
+                       }
+
+                       if (narg < 0) {
+                               /* no meaning in object-type macro */
+                               macsav('#');
+                               break;
+                       }
+
+                       /* remove spaces between # and arg */
+                       macsav(SNUFF);
+                       c = skipws(0); /* whitespace, ignore */
+                       if (!ISID0(c))
+                               goto bad;
+                       dp = readid(c);
+                       if (vararg && strcmp((char *)dp, (char *)vararg) == 0) {
+                               macsav(WARN);
+                               macsav(VARG);
+                               macsav(SNUFF);
+                               break;
+                               
+                       }
+                       if ((i = findarg(dp, args, narg)) < 0)
+                               goto bad;
+                       macsav(WARN);
+                       macsav(i);
+                       macsav(SNUFF);
+                       break;
+
+               case NUMBER: 
+                       c = fastnum(c, macsav);
+                       continue;
+
+               case STRING:
+                       if (c == 'L' || c == 'u' || c == 'U') {
+                               macsav(c);
+                               if ((c = cinput()) == '8') {
+                                       macsav(c);
+                                       c = cinput();
+                               }
+                       }
+                       if (tflag)
+                               macsav(c);
+                       else
+                               faststr(c, macsav);
+                       break;
+
+               case IDENT:
+                       dp = readid(c);
+                       if (narg < 0) {
+                               macstr(dp);
+                               break; /* keep on heap */
+                       }
+                       if (vararg && strcmp((char *)dp, (char *)vararg) == 0) {
+                               macsav(WARN);
+                               macsav(wascon ? GCCARG : VARG);
+                               break;
+                       }
+
+                       /* check if its an argument */
+                       if ((i = findarg(dp, args, narg)) < 0) {
+                               macstr(dp);
+                               break;
+                       }
+                       macsav(WARN);
+                       macsav(i);
+                       break;
+
+               case 0:
+                       goto bad;
+                       
+               default:
+                       macsav(c);
+                       break;
+               }
+               wascon = 0;
+               c = cinput();
+       }
+       cunput(c);
+       /* remove trailing whitespace */
+       DELEWS();
+
+       if (macbase[cmbase+1+(vararg != 0)] == CONC)
+               goto bad; /* 6.10.3.3 p1 */
+
+       if (vararg) {
+               macbase[cmbase] = VARG;
+               macbase[cmbase+1] = narg;
+       } else
+               macbase[cmbase] = (narg < 0 ? OBJCT : narg);
+       macsav(0);
+
+       if (redef && ifiles->idx != SYSINC) {
+               if (cmprepl(np->value, macbase+cmbase)) { /* not equal */
+                       np->value = macbase+cmbase;
+                       warning("%s redefined (previously defined at \"%s\" line %d)",
+                           np->namep, np->file, np->line);
+               } else
+                       macpos = cmbase;  /* forget this space */
+       } else
+               np->value = macbase+cmbase;
+
+#ifdef PCC_DEBUG
+       if (dflag) {
+               const usch *w = np->value;
+
+               printf("!define %s: ", np->namep);
+               if (*w == OBJCT)
+                       printf("[object]");
+               else if (*w == VARG)
+                       printf("[VARG%d]", *++w);
+               else
+                       printf("[%d]", *w);
+               putchar('\'');
+               prrep(++w);
+               printf("\'\n");
+       }
+#endif
+       for (i = 0; i < narg; i++)
+               free(args[i]);
+       return;
+
+bad:   error("bad #define");
+}
+
+void
+warning(const char *fmt, ...)
+{
+       va_list ap;
+
+       if (ifiles != NULL)
+               fprintf(stderr, "%s:%d: warning: ",
+                   ifiles->fname, ifiles->lineno);
+
+       va_start(ap,fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fputc('\n', stderr);
+
+       warnings++;
+}
+
+void
+error(const char *fmt, ...)
+{
+       va_list ap;
+
+       if (ifiles != NULL)
+               fprintf(stderr, "%s:%d: error: ",
+                   ifiles->fname, ifiles->lineno);
+
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fputc('\n', stderr);
+       exit(1);
+}
+
+/*
+ * store a character into the "define" buffer.
+ */
+void
+savch(int c)
+{
+       if (stringbuf >= &sbf[SBSIZE])
+               error("out of macro space!");
+
+       *stringbuf++ = (usch)c;
+}
+
+static int
+pragwin(struct iobuf *ib)
+{
+       return ib ? *ib->cptr++ : cinput();
+}
+
+static int
+skipws(struct iobuf *ib)
+{
+       int t;
+
+       while ((t = pragwin(ib)) == ' ' || t == '\t')
+               ;
+       return t;
+}
+
+/*
+ * convert _Pragma() to #pragma for output.
+ * Syntax is already correct.
+ */
+static void
+pragoper(struct iobuf *ib)
+{
+       int t;
+       struct iobuf *ob = getobuf();
+
+       if (skipws(ib) != '(' || ((t = skipws(ib)) != '\"' && t != 'L'))
+               goto err;
+       if (t == 'L' && (t = pragwin(ib)) != '\"')
+               goto err;
+       strtobuf((usch *)"\n#pragma ", ob);
+       while ((t = pragwin(ib)) != '\"') {
+               if (t == BLKID) {
+                       pragwin(ib);
+                       continue;
+               }
+               if (t == '\"')
+                       continue;
+               if (t == '\\') {
+                       if ((t = pragwin(ib)) != '\"' && t != '\\')
+                               putob(ob, '\\');
+               }
+               putob(ob, t);
+       }
+       bsheap(ob, "\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
+       putstr(ob->buf);
+       bufree(ob);
+       if (skipws(ib) == ')')
+               return;
+
+err:   error("_Pragma() syntax error");
+}
+
+static int
+expok(struct symtab *sp, int l)
+{
+       struct blocker *w;
+
+       if (l == 0)
+               return 1;
+#ifdef PCC_DEBUG
+if (dflag) { printf("expok blocked: "); for (w = blkidx[l]; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
+#endif
+       w = blkidx[l];
+       while (w) {
+               if (w->sp == sp)
+                       return 0;
+               w = w->next;
+       }
+       return 1;
+}
+
+static int
+expokb(struct symtab *sp, struct blocker *bl)
+{
+       struct blocker *w;
+
+       if (bl == 0)
+               return 1;
+#ifdef PCC_DEBUG
+if (dflag) { printf("expokb blocked: "); for (w = bl; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
+#endif
+       w = bl;
+       while (w) {
+               if (w->sp == sp)
+                       return 0;
+               w = w->next;
+       }
+       return 1;
+}
+
+static struct blocker *
+blkget(struct symtab *sp, struct blocker *obl)
+{
+       struct blocker *bl = calloc(sizeof(*obl), 1);
+
+       bl->sp = sp;
+       bl->next = obl;
+       return bl;
+}
+
+static int
+blkix(struct blocker *obl)
+{
+       if (blkidp > 1 && blkidx[blkidp-1] == obl)
+               return blkidp-1;
+       if (blkidp == RECMAX)
+               error("blkix");
+       blkidx[blkidp] = obl;
+       return blkidp++;
+}
+
+static struct blocker *
+mergeadd(struct blocker *bl, int m)
+{
+       struct blocker *w, *ww;
+
+       DPRINT(("mergeadd: %p %d\n", bl, m));
+       if (bl == 0)
+               return blkidx[m];
+       if (m == 0)
+               return bl;
+
+       blkidx[blkidp] = bl;
+       for (w = blkidx[m]; w; w = w->next) {
+               ww = calloc(sizeof(*w), 1);
+               ww->sp = w->sp;
+               ww->next = blkidx[blkidp];
+               blkidx[blkidp] = ww;
+       }
+       DPRINT(("mergeadd return: %d ", blkidp));
+#ifdef PCC_DEBUG
+       if (dflag) {
+               for (w = blkidx[blkidp]; w; w = w->next)
+                       printf("%s ", w->sp->namep);
+               printf("\n");
+       }
+#endif
+       return blkidx[blkidp++];
+}
+
+static void
+storeblk(int l, struct iobuf *ob)
+{
+       DPRINT(("storeblk: %d\n", l));
+       putob(ob, BLKID);
+       putob(ob, l);
+}
+
+/*
+ * Save filename on heap (with escaped chars).
+ */
+static struct iobuf *
+unfname(void)
+{
+       struct iobuf *ob = getobuf();
+       const usch *bp = ifiles->fname;
+
+       putob(ob, '\"');
+       for (; *bp; bp++) {
+               if (*bp == '\"' || *bp == '\'' || *bp == '\\')
+                       putob(ob, '\\');
+               putob(ob, *bp);
+       }
+       putob(ob, '\"');
+       return ob;
+}
+
+/*
+ * Version of fastnum that reads from a string and saves in ob.
+ * We know that it is a number before calling this routine.
+ */
+static usch *
+fstrnum(usch *s, struct iobuf *ob)  
+{      
+       if (*s == '.') {
+               /* not digit, dot.  Next will be digit */
+               putob(ob, *s++);
+       }
+       for (;;) {
+               putob(ob, *s++);
+               if ((spechr[*s] & C_EP)) {
+                       if (s[1] != '-' && s[1] != '+')
+                               break;
+                       putob(ob, *s++);
+               } else if ((*s != '.') && ((spechr[*s] & C_ID) == 0))
+                       break;
+       }
+        return s;
+}
+
+/*
+ * get a string or character constant.
+ * similar to faststr.
+ */
+static usch *
+fstrstr(usch *s, struct iobuf *ob)
+{
+       int ch;
+
+       if (*s == 'L' || *s == 'U' || *s == 'u')
+               putob(ob, *s++);
+       if (*s == '8')
+               putob(ob, *s++);
+       ch = *s;
+       putob(ob, *s++);
+       while (*s != ch) {
+               if (*s == '\\')
+                       putob(ob, *s++);
+               putob(ob, *s++);
+       }
+       putob(ob, *s++);
+       return s;
+}
+
+/*
+ * Save standard comments if found.
+ */
+static usch *
+fcmnt(usch *s, struct iobuf *ob)
+{
+       putob(ob, *s++); /* / */
+       putob(ob, *s++); /* * */
+       for (;;s++) {
+               putob(ob, *s);
+               if (s[-1] == '*' && *s == '/')
+                       break;
+       }
+       return s+1;
+}
+
+static int
+getyp(usch *s)
+{
+
+       if (ISID0(*s)) return IDENT;
+       if ((*s == 'L' || *s == 'U' || *s == 'u') &&
+           (s[1] == '\'' || s[1] == '\"')) return STRING;
+       if (s[0] == 'u' && s[1] == 'U' && s[2] == '\"') return STRING;
+       if (s[0] == '\'' || s[0] == '\"') return STRING;
+       if (spechr[*s] & C_DIGIT) return NUMBER;
+       if (*s == '.' && (spechr[s[1]] & C_DIGIT)) return NUMBER;
+       if (*s == '/' && (s[1] == '/' || s[1] == '*')) return CMNT;
+       return *s;
+       
+}
+
+/*
+ * Check ib and print out the symbols there.
+ * If expandable symbols found recurse and expand them.
+ * If last identifier on the input list is expandable return it.
+ * Expect ib to be zero-terminated.
+ */
+static struct symtab *
+loopover(struct iobuf *ib, struct iobuf *ob)
+{
+       struct iobuf *xb, *xob;
+       struct symtab *sp;
+       usch *cp;
+       int l, c, t;
+
+       ib->cptr = ib->buf; /* start from beginning */
+#ifdef PCC_DEBUG
+       if (dflag) {
+               printf("loopover: '");
+               prline(ib->cptr);
+               printf("'\n");
+       }
+#endif
+
+       xb = getobuf();
+       while ((c = *ib->cptr)) {
+               switch (t = getyp(ib->cptr)) {
+               case CMNT:
+                       ib->cptr = fcmnt(ib->cptr, ob);
+                       continue;
+               case NUMBER:
+                       ib->cptr = fstrnum(ib->cptr, ob);
+                       continue;
+               case STRING:
+                       xb->cptr = xb->buf;
+                       ib->cptr = fstrstr(ib->cptr,xb);
+                       *xb->cptr = 0;
+                       for (cp = xb->buf; *cp; cp++) {
+                               if (*cp <= BLKID) {
+                                       if (*cp == BLKID)
+                                               cp++;
+                                       continue;
+                               }
+                               putob(ob, *cp);
+                       }
+                       continue;
+               case BLKID:
+                       l = ib->cptr[1];
+                       ib->cptr+=2;
+                       /* FALLTHROUGH */
+               case IDENT:
+                       if (t != BLKID)
+                               l = 0;
+                       /*
+                        * Tricky: if this is the last identifier
+                        * in the expanded list, and it is defined
+                        * as a function-like macro, then push it
+                        * back on the input stream and let fastscan
+                        * handle it as a new macro.
+                        * BUT: if this macro is blocked then this
+                        * should not be done.
+                        */
+                       for (cp = ib->cptr; ISID(*ib->cptr); ib->cptr++)
+                               ;
+                       if ((sp = lookup(cp, FIND)) == NULL) {
+sstr:                          for (; cp < ib->cptr; cp++)
+                                       putob(ob, *cp);
+                               continue;
+                       }
+                       if (expok(sp, l) == 0) {
+                               /* blocked */
+                               goto sstr;
+                       } else {
+                               if (*sp->value != OBJCT) {
+                                       cp = ib->cptr;
+                                       while (ISWS(*ib->cptr))
+                                               ib->cptr++;
+                                       if (*ib->cptr == 0) {
+                                               bufree(xb);
+                                               return sp;
+                                       }
+                                       ib->cptr = cp;
+                               }
+newmac:                                if ((xob = submac(sp, 1, ib, NULL)) == NULL) {
+                                       strtobuf((usch *)sp->namep, ob);
+                               } else {
+                                       sp = loopover(xob, ob);
+                                       bufree(xob);
+                                       if (sp != NULL)
+                                               goto newmac;
+                               }
+                       }
+                       continue;
+               default:
+                       putob(ob, c);
+               }
+
+               ib->cptr++;
+       }
+
+       bufree(xb);
+       DPRINT(("loopover return 0\n"));
+       return 0;
+}
+
+/*
+ * Handle defined macro keywords found on input stream.
+ * When finished print out the full expanded line.
+ * Input here is from the lex buffer.
+ * Return 1 if success, 0 otherwise.  fastscan restores stringbuf.
+ * Scanned data is stored on heap.  Last scan prints out the buffer.
+ */
+struct iobuf *
+kfind(struct symtab *sp)
+{
+       extern int inexpr;
+       struct blocker *bl;
+       struct iobuf *ib, *ob, *outb;
+       const usch *argary[MAXARGS+1], *sbp;
+       int c, n = 0;
+
+       blkidp = 1;
+       outb = NULL;
+       sbp = stringbuf;
+       DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
+       switch (*sp->value) {
+       case FILLOC:
+               ob = unfname();
+               return ob;
+
+       case LINLOC:
+               return bsheap(NULL, "%d", ifiles->lineno);
+
+       case PRAGLOC:
+               pragoper(NULL);
+               return getobuf();
+
+       case DEFLOC:
+       case OBJCT:
+               bl = blkget(sp, NULL);
+               ib = mkrobuf(sp->value+1);
+               ob = getobuf();
+               ob = exparg(1, ib, ob, bl);
+               bufree(ib);
+               break;
+
+       case CTRLOC:
+               return bsheap(NULL, "%d", counter++);
+
+       default:
+               /* Search for '(' */
+               while (ISWSNL(c = cinput()))
+                       if (c == '\n')
+                               n++;
+               if (c != '(') {
+                       if (inexpr == 0)
+                               putstr(sp->namep);
+                       if (n == 0)
+                               putch(' ');
+                       else for (ifiles->lineno += n; n; n--)
+                               putch('\n');
+                       cunput(c);
+                       return 0; /* Failed */
+               }
+
+               /* fetch arguments */
+again:         if (readargs1(sp, argary))
+                       error("readargs");
+
+               bl = blkget(sp, NULL);
+               ib = subarg(sp, argary, 1, bl);
+               ob = getobuf();
+               ob = exparg(1, ib, ob, bl);
+               bufree(ib);
+               break;
+       }
+
+       /*
+        * Loop over stringbuf, output the data and remove remaining  
+        * directives.  Start with extracting the last keyword (if any).
+        */
+       putob(ob, 0); /* XXX needed? */
+
+       if (outb == NULL)
+               outb = getobuf();
+
+       stringbuf = (usch *)sbp; /* XXX should check cleanup */
+       if ((sp = loopover(ob, outb))) {
+               /* Search for '(' */
+               while (ISWSNL(c = cinput()))
+                       if (c == '\n')
+                               n++;
+               if (c == '(') {
+                       bufree(ob);
+                       goto again;
+               }
+               cunput(c);
+               strtobuf((usch *)sp->namep, outb);
+       }
+       bufree(ob);
+
+       for (ifiles->lineno += n; n; n--)
+               putob(outb, '\n');
+       stringbuf = (usch *)sbp;
+       if (nbufused != 1)
+               error("lost buffer");
+       return outb;
+}
+
+/*
+ * Replace and push-back on input stream the eventual replaced macro.
+ * The check for whether it can expand or not should already have been done.
+ * Blocks for this identifier will be added via insblock() after expansion.
+ * The same as kfind but read a string.
+ */
+struct iobuf *
+submac(struct symtab *sp, int lvl, struct iobuf *ib, struct blocker *obl)
+{
+       struct blocker *bl;
+       struct iobuf *ob, *ab;
+       const usch *argary[MAXARGS+1];
+       usch *cp, *pr;
+
+       DPRINT(("%d:submac: trying '%s'\n", lvl, sp->namep));
+       switch (*sp->value) {
+       case FILLOC:
+               ob = unfname();
+               break;
+       case LINLOC:
+               ob = bsheap(NULL, "%d", ifiles->lineno);
+               break;
+       case PRAGLOC:
+               pragoper(ib);
+               ob = getobuf();
+               break;
+       case OBJCT:
+               bl = blkget(sp, obl);
+               ib = mkrobuf(sp->value+1);
+               ob = getobuf();
+               DPRINT(("%d:submac: calling exparg\n", lvl));
+               ob = exparg(lvl+1, ib, ob, bl);
+               bufree(ib);
+               DPRINT(("%d:submac: return exparg\n", lvl));
+               break;
+       case CTRLOC:
+               ob = bsheap(NULL, "%d", counter++);
+               break;
+       default:
+               cp = ib->cptr;
+               while (ISWSNL(*ib->cptr))
+                       ib->cptr++;
+               if (*ib->cptr != '(') {
+                       ib->cptr = cp;
+                       return 0;
+               }
+               cp = ib->cptr++;
+               pr = stringbuf;
+               if ((ab = readargs2(&ib->cptr, sp, argary)) == 0) {
+                       /* Bailed out in the middle of arg list */
+                       ib->cptr = cp; /* XXX */
+                       return 0;
+               }
+               bl = blkget(sp, obl);
+               ib = subarg(sp, argary, lvl+1, bl);
+               bufree(ab);
+               stringbuf = pr;
+
+               ob = getobuf();
+               DPRINT(("%d:submac(: calling exparg\n", lvl));
+               ob = exparg(lvl+1, ib, ob, bl);
+               bufree(ib);
+               DPRINT(("%d:submac(: return exparg\n", lvl));
+               break;
+       }
+       putob(ob, 0);
+       ob->cptr--;
+
+       return ob;
+}
+
+static int
+isdir(void)
+{
+       usch ch;
+
+       while ((ch = cinput()) == ' ' || ch == '\t')
+               ;
+       if (ch == '#')
+               return 1;
+       cunput(ch);
+       return 0;
+}
+
+/*
+ * Deal with directives inside a macro.
+ * Doing so is really ugly but gcc allows it, so...
+ */
+static void
+chkdir(void)
+{
+       usch ch;
+
+       for (;;) {
+               if (isdir()) {
+#ifndef GCC_COMPAT
+                       warning("conditionals inside macro arg list");
+#endif
+                       ppdir();
+               }
+               if (flslvl == 0)
+                       return;
+               while ((ch = cinput()) != '\n')
+                       ;
+               ifiles->lineno++;
+               putch('\n');
+       }
+}
+
+static int
+ra1_wsnl(int sp)
+{
+       int c;
+
+       while (ISWSNL(c = cinput())) {
+               if (c == '\n') {
+                       putch('\n');
+                       chkdir();
+                       ifiles->lineno++;
+                       if (sp) savch(' ');
+               }
+       }
+       return c;
+}
+
+/*
+ * Read arguments and put in argument array.
+ * If EOF is encountered return 1, otherwise 0.
+ */
+int
+readargs1(struct symtab *sp, const usch **args)
+{
+       struct iobuf *ob;
+       const usch *vp = sp->value;
+       int c, i, plev, narg, ellips = 0;
+
+       DPRINT(("readargs1\n"));
+       narg = *vp++;
+       if (narg == VARG) {
+               narg = *vp++;
+               ellips = 1;
+       }
+#ifdef PCC_DEBUG
+       if (dflag > 1) {
+               printf("narg %d varg %d: ", narg, ellips);
+               prrep(vp);
+               printf("\n");
+       }
+#endif
+
+       /*
+        * read arguments and store them on heap.
+        */
+       c = '(';
+       for (i = 0; i < narg && c != ')'; i++) {
+               args[i] = stringbuf;
+               plev = 0;
+
+               c = ra1_wsnl(0);
+               for (;;) {
+                       if (plev == 0 && (c == ')' || c == ','))
+                               break;
+                       if (c == '(') plev++;
+                       if (c == ')') plev--;
+                       if (c == 0)
+                               error("eof in macro");
+                       else if (c == '/') Ccmnt(savch);
+                       else if (c == '\"' || c == '\'') faststr(c, savch);
+                       else if (ISID0(c)) {
+                               usch *bp = stringbuf;
+                               do {
+                                       savch(c);
+                               } while ((spechr[c = cinput()] & C_ID));
+                               if ((sp = lookup(bp, FIND)) != NULL) {
+                                       if (sp == linloc) {
+                                               stringbuf = bp;
+                                               ob = bsheap(NULL, "%d", ifiles->lineno);
+                                               savstr(ob->buf);
+                                               bufree(ob);
+                                       } else if (sp == ctrloc) {
+                                               stringbuf = bp;
+                                               ob = bsheap(NULL, "%d", counter++);
+                                               savstr(ob->buf);
+                                               bufree(ob);
+                                       }
+                               }
+                               cunput(c);
+                       } else
+                               savch(c);
+                       if ((c = cinput()) == '\n') {
+                               chkdir();
+                               ifiles->lineno++, putch(c), c = ' ';
+                       }
+               }
+
+               while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
+                       stringbuf--;
+               savch('\0');
+#ifdef PCC_DEBUG
+               if (dflag) {
+                       printf("readargs: save arg %d '", i);
+                       prline(args[i]);
+                       printf("'\n");
+               }
+#endif
+       }
+
+       /* Handle varargs readin */
+       if (ellips)
+               args[i] = (const usch *)"";
+       if (ellips && c != ')') {
+               args[i] = stringbuf;
+               plev = 0;
+               c = ra1_wsnl(0);
+               for (;;) {
+                       if (plev == 0 && c == ')')
+                               break;
+                       if (c == '(') plev++;
+                       if (c == ')') plev--;
+                       if (c == '\"' || c == '\'') faststr(c, savch);
+                       else
+                               savch(c);
+                       if ((c = cinput()) == '\n')
+                               ifiles->lineno++, c = ' ';
+               }
+               while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
+                       stringbuf--;
+               savch('\0');
+#ifdef PCC_DEBUG
+               if (dflag) {
+                       printf("readargs: vararg arg %d '", i);
+                       prline(args[i]);
+                       printf("'\n");
+               }
+#endif
+
+       }
+       if (narg == 0 && ellips == 0)
+               c = ra1_wsnl(0);
+
+       if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
+               error("wrong arg count");
+       return 0;
+}
+
+static usch *raptr;
+static int
+raread(void)
+{
+       int rv;
+
+       if (raptr) {
+               if ((rv = *raptr))
+                       raptr++;
+       } else
+               rv = cinput();
+       return rv;
+}
+
+
+/*
+ * Read arguments and put in argument array.
+ * If EOF is encountered return 1, otherwise 0.
+ */
+struct iobuf *
+readargs2(usch **inp, struct symtab *sp, const usch **args)
+{
+       struct iobuf *ab;
+       const usch *vp = sp->value;
+       int argary[MAXARGS+1];
+       int c, i, j, plev, narg, ellips = 0;
+
+       DPRINT(("readargs2 %s '", sp->namep));
+#ifdef PCC_DEBUG
+       if (dflag && inp) {
+               prline(*inp);
+               printf("'\n");
+       }
+#endif
+       raptr = inp ? *inp : 0;
+       narg = *vp++;
+       if (narg == VARG) {
+               narg = *vp++;
+               ellips = 1;
+       }
+#ifdef PCC_DEBUG
+       if (dflag > 1) {
+               prrep(vp);
+               printf("\n");
+       }
+#endif
+
+       /*
+        * read arguments and store them on heap.
+        */
+       ab = getobuf();
+       c = '(';
+       for (i = 0; i < narg && c != ')'; i++) {
+               argary[i] = ab->cptr - ab->buf;
+               plev = 0;
+
+               while ((c = raread()) == ' ' || c == '\t')
+                       ;
+               for (;;) {
+                       if (plev == 0 && (c == ')' || c == ','))
+                               break;
+                       if (c == '(') plev++;
+                       if (c == ')') plev--;
+                       if (c == 0) {
+                               if (raptr) {
+                                       *inp = raptr;
+                                       raptr = 0;
+                               } else
+                                       error("eof in macro");
+                       } else if (c == BLKID) {
+                               putob(ab, c), putob(ab, raread());
+                       } else if (c == '/') {
+                               if ((c = raread()) == '*')
+                                       error("FIXME ccmnt");
+                               putob(ab, '/');
+                               continue;
+                       } else if (c == '\"' || c == '\'') {
+                               if (raptr) {
+                                       raptr = fstrstr(raptr-1, ab);
+                               } else {
+                                       int mp = macpos;
+                                       faststr(c, macsav);
+                                       strtobuf(macbase+mp, ab);
+                                       macpos = mp;
+                               }
+                       } else if (ISID0(c)) {
+                               int mp = macpos;
+                               do {
+                                       macsav(c);
+                               } while (ISID(c = raread()));
+                               macsav(0);
+                               macpos = mp;
+                               if ((sp = lookup(macbase+mp, FIND)) &&
+                                   (sp == linloc)) {
+                                       bsheap(ab, "%d", ifiles->lineno);
+                               } else
+                                       strtobuf(macbase+mp, ab);
+                               continue;
+                       } else
+                               putob(ab, c);
+                       c = raread();
+               }
+
+               while (argary[i] < ab->cptr-ab->buf && ISWSNL(ab->cptr[-1]))
+                       ab->cptr--;
+               putob(ab, '\0');
+#ifdef PCC_DEBUG
+               if (dflag) {
+                       printf("readargs2: save arg %d '", i);
+                       prline(ab->buf+argary[i]);
+                       printf("'\n");
+               }
+#endif
+       }
+
+       /* Handle varargs readin */
+       if (ellips)
+               args[i] = (const usch *)"";
+       if (ellips && c != ')') {
+               argary[i] = ab->cptr - ab->buf;
+               plev = 0;
+               while ((c = raread()) == ' ' || c == '\t')
+                       ;
+               for (;;) {
+                       if (plev == 0 && c == ')')
+                               break;
+                       if (c == '(') plev++;
+                       if (c == ')') plev--;
+                       if (c == '\"' || c == '\'') {
+                               if (raptr) {
+                                       raptr = fstrstr(raptr-1, ab);
+                               } else {
+                                       int mp = macpos;
+                                       faststr(c, macsav);
+                                       strtobuf(macbase+mp, ab);
+                                       macpos = mp;
+                               }
+                       } else
+                               putob(ab, c);
+                       c = raread();
+               }
+               while (argary[i] < ab->cptr-ab->buf && ISWSNL(ab->cptr[-1]))
+                       ab->cptr--;
+               putob(ab, '\0');
+               i++;
+       }
+       if (narg == 0 && ellips == 0) {
+               while ((c = raread()) == ' ' || c == '\t')
+                       ;
+       }
+
+       if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
+               error("wrong arg count");
+       if (raptr)
+               *inp = raptr;
+       for (j = 0; j < i; j++)
+               args[j] = ab->buf + argary[j];
+       return ab;
+}
+
+/*
+ * expand a function-like macro.
+ * vp points to end of replacement-list
+ * reads function arguments from input stream.
+ * result is pushed-back for more scanning.
+ */
+struct iobuf *
+subarg(struct symtab *nl, const usch **args, int lvl, struct blocker *bl)
+{
+       struct blocker *w;
+       struct iobuf *ob, *cb, *nb;
+       int narg, instr, snuff;
+       const usch *sp, *bp, *ap, *vp, *tp;
+
+       DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
+       ob = getobuf();
+       vp = nl->value;
+       narg = *vp++;
+       if (narg == VARG)
+               narg = *vp++;
+
+       sp = vp;
+       instr = snuff = 0;
+#ifdef PCC_DEBUG
+       if (dflag>1) {
+               printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
+               prrep(vp);
+               printf("' ");
+               for (w = bl; w; w = w->next)
+                       printf("%s ", w->sp->namep);
+               printf("\n");
+       }
+#endif
+
+       /*
+        * walk forward over replacement-list while replacing
+        * arguments.  Arguments are macro-expanded if required.
+        */
+       while (*sp) {
+               if (*sp == SNUFF)
+                       putob(ob, '\"'), snuff ^= 1;
+               else if (*sp == CONC)
+                       ;
+               else if (*sp == WARN) {
+
+                       if (sp[1] == VARG) {
+                               bp = ap = args[narg];
+                               sp++;
+#ifdef GCC_COMPAT
+                       } else if (sp[1] == GCCARG) {
+                               /* XXX remove last , not add 0 */
+                               ap = args[narg];
+                               if (ap[0] == 0)
+                                       ap = (const usch *)"0";
+                               bp = ap;
+                               sp++;
+#endif
+                       } else
+                               bp = ap = args[(int)*++sp];
+#ifdef PCC_DEBUG
+                       if (dflag>1){
+                               printf("%d:subarg GOTwarn; arglist '", lvl);
+                               prline(bp);
+                               printf("'\n");
+                       }
+#endif
+                       if (sp[-2] != CONC && !snuff && sp[1] != CONC) {
+                               /*
+                                * Expand an argument; 6.10.3.1:
+                                * "A parameter in the replacement list,
+                                *  is replaced by the corresponding argument
+                                *  after all macros contained therein have
+                                *  been expanded.".
+                                */
+                               w = bl ? bl->next : NULL;
+                               cb = mkrobuf(bp);
+                               nb = getobuf();
+                               DPRINT(("%d:subarg: calling exparg\n", lvl));
+                               nb = exparg(lvl+1, cb, nb, w);
+                               DPRINT(("%d:subarg: return exparg\n", lvl));
+                               bufree(cb);
+                               strtobuf(nb->buf, ob);
+                               bufree(nb);
+                       } else {
+                               while (*bp) {
+                                       if (snuff && !instr && ISWS(*bp)) {
+                                               while (ISWS(*bp))
+                                                       bp++;
+                                               putob(ob, ' ');
+                                       }
+
+                                       if (snuff &&
+                                           (*bp == '\'' || *bp == '"')) {
+                                               instr ^= 1;
+                                               for (tp = bp - 1; *tp == '\\'; tp--)
+                                                       instr ^= 1;
+                                               if (*bp == '"')
+                                                       putob(ob, '\\');
+                                       } 
+                                       if (snuff && instr && *bp == '\\')
+                                               putob(ob, '\\');
+                                       putob(ob, *bp);
+                                       bp++;
+                               }
+                       }
+               } else if (ISID0(*sp)) {
+                       if (lookup(sp, FIND))
+                               storeblk(blkix(bl), ob);
+                       while (ISID(*sp))
+                               putob(ob, *sp++);
+                       sp--;
+               } else
+                       putob(ob, *sp);
+               sp++;
+       }
+       putob(ob, 0);
+       ob->cptr = ob->buf;
+       DPRINT(("%d:subarg retline %s\n", lvl, ob->buf));
+       return ob;
+}
+
+/*
+ * Do a (correct) expansion of a WARN-terminated buffer of tokens.
+ * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
+ * Expansion blocking is not altered here unless when tokens are
+ * concatenated, in which case they are removed.
+ */
+struct iobuf *
+exparg(int lvl, struct iobuf *ib, struct iobuf *ob, struct blocker *bl)
+{
+       extern int inexpr;
+       struct iobuf *nob;
+       struct symtab *nl;
+       int c, m;
+       usch *cp, *bp, *sbp;
+
+       DPRINT(("%d:exparg: entry ib %s\n", lvl, ib->cptr));
+#ifdef PCC_DEBUG
+       if (dflag > 1) {
+               printf("exparg entry: full ");
+               prline(ib->cptr);
+               printf("\n");
+       }
+#endif
+
+       while ((c = getyp(ib->cptr)) != 0) {
+               ib->cptr++;
+
+               switch (c) {
+
+               case CMNT:
+                       ib->cptr = fcmnt(ib->cptr-1, ob);
+                       break;
+               case NUMBER:
+                       ib->cptr = fstrnum(ib->cptr-1, ob);
+                       break;
+               case STRING:
+                       ib->cptr = fstrstr(ib->cptr-1, ob);
+                       break;
+               case BLKID:
+                       m = *ib->cptr++;
+                       ib->cptr++;
+                       /* FALLTHROUGH */
+               case IDENT:
+                       if (c != BLKID)
+                               m = 0;
+                       for (cp = ib->cptr-1; ISID(*cp); cp++)
+                               ;
+#ifdef PCC_DEBUG
+if (dflag) { printf("!! ident "); prline(ib->cptr-1); printf("\n"); }
+#endif
+                       sbp = stringbuf;
+                       if (*cp == BLKID) {
+                               /* concatenation */
+                               bp = stringbuf;
+                               for (cp = ib->cptr-1; 
+                                   ISID(*cp) || *cp == BLKID; cp++) {
+                                       if (*cp == BLKID) {
+                                               /* XXX add to block list */
+                                               cp++;
+                                       } else
+                                               savch(*cp);
+                               }
+                               ib->cptr = cp;
+                               cp = stringbuf;
+                               savch(0);
+                       } else {
+                               bp = ib->cptr-1;
+                               ib->cptr = cp;
+                       }
+#ifdef PCC_DEBUG
+if (dflag) { printf("!! ident2 "); prline(bp); printf("\n"); }
+#endif
+                       if ((nl = lookup(bp, FIND)) == NULL) {
+sstr:                          for (; bp < cp; bp++)
+                                       putob(ob, *bp);
+                               stringbuf = sbp;
+                               break;
+                       } else if (inexpr && *nl->value == DEFLOC) {
+                               int gotlp = 0;
+                               while (ISWS(*ib->cptr)) ib->cptr++;
+                               if (*ib->cptr == '(')
+                                       gotlp++, ib->cptr++;
+                               while (ISWS(*ib->cptr)) ib->cptr++;
+                               if (!ISID0(*ib->cptr))
+                                       error("bad defined");
+                               putob(ob, lookup(ib->cptr, FIND) ? '1' : '0');
+                               while (ISID(*ib->cptr)) ib->cptr++;
+                               while (ISWS(*ib->cptr)) ib->cptr++;
+                               if (gotlp && *ib->cptr != ')')
+                                       error("bad defined");
+                               ib->cptr++;
+                               break;
+                       }
+                       stringbuf = sbp;
+                       if (expokb(nl, bl) && expok(nl, m)) {
+                               if ((nob = submac(nl, lvl+1, ib, bl))) {
+                                       if (nob->buf[0] == '-' ||
+                                           nob->buf[0] == '+')
+                                               putob(ob, ' ');
+                                       strtobuf(nob->buf, ob);
+                                       if (ob->cptr[-1] == '-' ||
+                                           ob->cptr[-1] == '+')
+                                               putob(ob, ' ');
+                                       bufree(nob);
+                               } else {
+                                       goto sblk;
+                               }
+                       } else {
+                               /* blocked */
+sblk:                          storeblk(blkix(mergeadd(bl, m)), ob);
+                               goto sstr;
+                       }
+                       break;
+
+               default:
+                       putob(ob, c);
+                       break;
+               }
+       }
+       putob(ob, 0);
+       ob->cptr--;
+       DPRINT(("%d:exparg return: ob %s\n", lvl, ob->buf));
+#ifdef PCC_DEBUG
+       if (dflag > 1) {
+               printf("%d:exparg: full ", lvl);
+               prline(ob->buf);
+               printf("\n");
+       }
+#endif
+       return ob;
+}
+
+#ifdef PCC_DEBUG
+
+static void
+prrep(const usch *s)
+{
+       while (*s) {
+               switch (*s) {
+               case WARN:
+                       if (s[1] == VARG) printf("<VARG>");
+                       else if (s[1] == GCCARG) printf("<GCCARG>");
+                       else printf("<ARG(%d)>", s[1]);
+                       s++;
+                       break;
+               case CONC: printf("<CONC>"); break;
+               case SNUFF: printf("<SNUFF>"); break;
+               case BLKID: printf("<BLKID(%d)>",s[1]); s++; break;
+               default: printf("%c", *s); break;
+               }
+               s++;
+       }
+}
+
+static void
+prline(const usch *s)
+{
+       while (*s) {
+               switch (*s) {
+               case BLKID: printf("<BLKID(%d)>", *++s); break;
+               case WARN: printf("<WARN>"); break;
+               case CONC: printf("<CONC>"); break;
+               case SNUFF: printf("<SNUFF>"); break;
+               case '\n': printf("<NL>"); break;
+               default: 
+                       if (*s > 0x7f)
+                               printf("<0x%x>", *s);
+                       else
+                               printf("%c", *s);
+                       break;
+               }
+               s++;
+       }
+}
+#endif
+
+usch *
+savstr(const usch *str)
+{
+       usch *rv = stringbuf;
+
+       do {
+               if (stringbuf >= &sbf[SBSIZE])
+                       error("out of macro space!");
+       } while ((*stringbuf++ = *str++));
+       stringbuf--;
+       return rv;
+}
+
+void
+putch(int ch)
+{
+       if (Mflag)
+               return;
+       fputc(ch, stdout);
+}
+
+void
+putstr(const usch *s)
+{
+       for (; *s; s++) {
+               if (Mflag == 0)
+                       fputc(*s, stdout);
+       }
+}
+
+/*
+ * convert a number to an ascii string. Store it on the heap.
+ */
+static void
+num2str(struct iobuf *ob, int num)
+{
+       static usch buf[12];
+       usch *b = buf;
+       int m = 0;
+
+       if (num < 0)
+               num = -num, m = 1;
+       do {
+               *b++ = (usch)(num % 10 + '0');
+               num /= 10;
+       } while (num);
+       if (m)
+               *b++ = '-';
+       while (b > buf)
+               putob(ob, *--b);
+}
+
+/*
+ * similar to sprintf, but only handles %c, %s and %d.
+ * saves result on heap.
+ */
+static void
+vsheap(struct iobuf *ob, const char *fmt, va_list ap)
+{
+       for (; *fmt; fmt++) {
+               if (*fmt == '%') {
+                       fmt++;
+                       switch (*fmt) {
+                       case 's':
+                               strtobuf(va_arg(ap, usch *), ob);
+                               break;
+                       case 'd':
+                               num2str(ob, va_arg(ap, int));
+                               break;
+                       case 'c':
+                               putob(ob, va_arg(ap, int));
+                               break;
+                       default:
+                               error("bad sheap");
+                       }
+               } else
+                       putob(ob, *fmt);
+       }
+       putob(ob, 0);
+       ob->cptr--;
+}
+
+struct iobuf *
+bsheap(struct iobuf *ob, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (ob == NULL)
+               ob = getobuf();
+
+       va_start(ap, fmt);
+       vsheap(ob, fmt, ap);
+       va_end(ap);
+
+       return ob;
+}
+
+static void
+usage(void)
+{
+       error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
+}
+
+#ifdef notyet
+/*
+ * Symbol table stuff.
+ * The data structure used is a patricia tree implementation using only
+ * bytes to store offsets.
+ * The information stored is (lower address to higher):
+ *
+ *     unsigned char bitno[2]; bit number in the string
+ *     unsigned char left[3];  offset from base to left element
+ *     unsigned char right[3]; offset from base to right element
+ */
+#endif
+
+/*
+ * This patricia implementation is more-or-less the same as
+ * used in ccom for string matching.
+ */
+struct tree {
+       int bitno;
+       struct tree *lr[2];
+};
+
+#define BITNO(x)               ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
+#define LEFT_IS_LEAF           0x80000000
+#define RIGHT_IS_LEAF          0x40000000
+#define IS_LEFT_LEAF(x)                (((x) & LEFT_IS_LEAF) != 0)
+#define IS_RIGHT_LEAF(x)       (((x) & RIGHT_IS_LEAF) != 0)
+#define P_BIT(key, bit)                (key[bit >> 3] >> (bit & 7)) & 1
+#define CHECKBITS              8
+
+static struct tree *sympole;
+static int numsyms;
+
+static struct tree *
+gtree(void)
+{
+       static int ntrees;
+       static struct tree *tp;
+
+       if (ntrees == 0) {
+               tp = xmalloc(BUFSIZ);
+               ntrees = BUFSIZ/sizeof(*tp);
+       }
+       return &tp[--ntrees];
+}
+
+/*
+ * Allocate a symtab struct and store the string.
+ */
+static struct symtab *
+getsymtab(const usch *str)
+{
+       static int nsyms;
+       static struct symtab *spp;
+       struct symtab *sp;
+
+       if (nsyms == 0) {
+               spp = xmalloc(BUFSIZ);
+               nsyms = BUFSIZ/sizeof(*sp);
+       }
+       sp = &spp[--nsyms];
+
+       sp->namep = str;
+       sp->value = NULL;
+       sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
+       sp->line = ifiles ? ifiles->lineno : 0;
+       return sp;
+}
+
+/*
+ * Do symbol lookup in a patricia tree.
+ * Only do full string matching, no pointer optimisations.
+ */
+struct symtab *
+lookup(const usch *key, int enterf)
+{
+       struct symtab *sp;
+       struct tree *w, *new, *last;
+       int len, cix, bit, fbit, svbit, ix, bitno;
+       const usch *k, *m;
+
+       /* Count full string length */
+       for (k = key, len = 0; ISID(*k) & C_ID; k++, len++)
+               ;
+
+       switch (numsyms) {
+       case 0: /* no symbols yet */
+               if (enterf != ENTER)
+                       return NULL;
+               sympole = (struct tree *)getsymtab(key);
+               numsyms++;
+               return (struct symtab *)sympole;
+
+       case 1:
+               w = sympole;
+               svbit = 0; /* XXX gcc */
+               break;
+
+       default:
+               w = sympole;
+               bitno = len * CHECKBITS;
+               for (;;) {
+                       bit = BITNO(w->bitno);
+                       fbit = bit >= bitno ? 0 : P_BIT(key, bit);
+                       svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+                           IS_LEFT_LEAF(w->bitno);
+                       w = w->lr[fbit];
+                       if (svbit)
+                               break;
+               }
+       }
+
+       sp = (struct symtab *)w;
+
+       m = sp->namep;
+       k = key;
+
+       /* Check for correct string and return */
+       for (cix = 0; *m && ISID(*k) && *m == *k; m++, k++, cix += CHECKBITS)
+               ;
+       if (*m == 0 && ISID(*k) == 0) {
+               if (enterf != ENTER && sp->value == NULL)
+                       return NULL;
+               return sp;
+       }
+
+       if (enterf != ENTER)
+               return NULL; /* no string found and do not enter */
+
+       ix = *m ^ *k;
+       while ((ix & 1) == 0)
+               ix >>= 1, cix++;
+
+       /* Create new node */
+       new = gtree();
+       bit = P_BIT(key, cix);
+       new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       new->lr[bit] = (struct tree *)getsymtab(key);
+
+       if (numsyms++ == 1) {
+               new->lr[!bit] = sympole;
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+               sympole = new;
+               return (struct symtab *)new->lr[bit];
+       }
+
+       w = sympole;
+       last = NULL;
+       for (;;) {
+               fbit = w->bitno;
+               bitno = BITNO(w->bitno);
+               if (bitno == cix)
+                       error("bitno == cix");
+               if (bitno > cix)
+                       break;
+               svbit = P_BIT(key, bitno);
+               last = w;
+               w = w->lr[svbit];
+               if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+                       break;
+       }
+
+       new->lr[!bit] = w;
+       if (last == NULL) {
+               sympole = new;
+       } else {
+               last->lr[svbit] = new;
+               last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       }
+       if (bitno < cix)
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+       return (struct symtab *)new->lr[bit];
+}
+
+void *
+xmalloc(int sz)
+{
+       usch *rv;
+
+       if ((rv = (void *)malloc(sz)) == NULL)
+               error("xmalloc: out of mem");
+       return rv;
+}
+
+void *
+xrealloc(void *p, int sz)
+{
+       usch *rv;
+
+       if ((rv = (void *)realloc(p, sz)) == NULL)
+               error("xrealloc: out of mem");
+       return rv;
+}
+
+static usch *
+xstrdup(const usch *str)
+{
+       usch *rv;
+
+       if ((rv = (usch *)strdup((const char *)str)) == NULL)
+               error("xstrdup: out of mem");
+       return rv;
+}
+
+
diff --git a/lang/pcc/pcc/cc/cpp/cpp.h b/lang/pcc/pcc/cc/cpp/cpp.h
new file mode 100644 (file)
index 0000000..9e21af1
--- /dev/null
@@ -0,0 +1,207 @@
+/*     $Id: cpp.h,v 1.93 2016/03/12 15:46:06 ragge Exp $       */
+
+/*
+ * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>     /* for debug/printf */
+
+typedef unsigned char usch;
+extern usch *stringbuf;
+
+extern int     trulvl;
+extern int     flslvl;
+extern int     elflvl;
+extern int     elslvl;
+extern int     dflag;
+extern int     tflag, Aflag, Cflag, Pflag;
+extern int     Mflag, dMflag, MPflag, MMDflag;
+extern char    *Mfile, *MPfile;
+extern int     defining;
+extern FILE    *of;
+
+/* args for lookup() */
+#define FIND    0
+#define ENTER   1
+
+/* buffer used internally */
+#ifndef CPPBUF
+#if defined(mach_pdp11)
+#define CPPBUF  BUFSIZ
+#define        BUF_STACK
+#else
+#define CPPBUF 16384
+#endif
+#endif
+
+#define        MAXARGS 128     /* Max # of args to a macro. Should be enough */
+#define        MAXIDSZ 63      /* Max length of C99 identifier; 5.2.4.1 */
+
+#define        PBMAX   10      /* min pushbackbuffer size */
+#define        BBUFSZ  (PBMAX+CPPBUF+1)
+
+#define        CTRLOC  0xf8    /* __COUNTER__ */
+#define        DEFLOC  0xf9    /* defined */
+#define        PRAGLOC 0xfa    /* _Pragma */
+#define        LINLOC  0xfb    /* __LINE__ */
+#define        FILLOC  0xfc    /* __FILE__ */
+#define GCCARG 0xfd    /* has gcc varargs that may be replaced with 0 */
+#define VARG   0xfe    /* has varargs */
+#define OBJCT  0xff
+#define WARN   1       /* SOH, not legal char */
+#define CONC   2       /* STX, not legal char */
+#define SNUFF  3       /* ETX, not legal char */
+#define        BLKID   4       /* EOT, not legal char */
+
+/* Used in macro expansion */
+#define RECMAX 10000                   /* max # of recursive macros */
+#define        MKB(l,h)        (l+((h)<<8))
+
+/* quick checks for some characters */
+#define C_SPEC 0001            /* for fastscan() parsing */
+#define C_2    0002            /* for yylex() tokenizing */
+#define C_WSNL 0004            /* ' ','\t','\r','\n' */
+#define C_ID   0010            /* [_a-zA-Z0-9] */
+#define C_ID0  0020            /* [_a-zA-Z] */
+#define C_EP   0040            /* [epEP] */
+#define C_DIGIT        0100            /* [0-9] */
+#define C_HEX  0200            /* [0-9a-fA-F] */
+
+extern usch spechr[];
+
+#define ISWSNL(x)      (spechr[x] & (C_WSNL))
+#define ISWS(x)                ((x) == '\t' || (x) == ' ')
+#define ISID(x)                (spechr[x] & C_ID)
+#define ISID0(x)       (spechr[x] & C_ID0)
+#define        ISDIGIT(x)      (spechr[x] & C_DIGIT)
+
+/*
+ * definition for include file info
+ */
+struct includ {
+       struct includ *next;
+       const usch *fname;      /* current fn, changed if #line found */
+       const usch *orgfn;      /* current fn, not changed */
+       int lineno;
+       int escln;              /* escaped newlines, to be added */
+       int infil;
+       usch *curptr;
+       usch *maxread;
+       usch *ostr;
+       usch *buffer;
+       int idx;
+       void *incs;
+       const usch *fn;
+#ifdef BUF_STACK
+       usch bbuf[BBUFSZ];
+#else
+       usch *bbuf;
+#endif
+};
+#define INCINC 0
+#define SYSINC 1
+
+extern struct includ *ifiles;
+
+/* Symbol table entry  */
+struct symtab {
+       const usch *namep;
+       const usch *value;
+       const usch *file;
+       int line;
+};
+
+struct initar {
+       struct initar *next;
+       int type;
+       char *str;
+};
+
+/* buffer definition */
+struct iobuf {
+       usch *buf;
+       usch *cptr;
+       usch *bsz;
+       int ro:1, inuse:1;
+};
+struct iobuf *getobuf(void);
+void putob(struct iobuf *ob, int ch);
+void bufree(struct iobuf *iob);
+
+/*
+ * Struct used in parse tree evaluation.
+ * op is one of:
+ *     - number type (NUMBER, UNUMBER)
+ *     - zero (0) if divided by zero.
+ */
+struct nd {
+       int op;
+       union {
+               long long val;
+               unsigned long long uval;
+       } n;
+};
+extern struct nd yynode;
+
+#define nd_val n.val
+#define nd_uval n.uval
+
+enum { NUMBER = 257, UNUMBER, LS, RS, EQ, NE, STRING, WSPACE, CMNT, IDENT,
+       OROR, ANDAND, DEFINED, LE, GE };
+
+#define        SLO_IGNOREWS    001
+
+struct symtab *lookup(const usch *namep, int enterf);
+struct blocker;
+struct iobuf *submac(struct symtab *nl, int, struct iobuf *, struct blocker *);
+struct iobuf *kfind(struct symtab *nl);
+void ppdir(void);
+
+void define(void);
+void include(void);
+void include_next(void);
+void line(void);
+
+int pushfile(const usch *fname, const usch *fn, int idx, void *incs);
+void prtline(int nl);
+int yylex(void);
+void cunput(int);
+int yyparse(void);
+usch *savstr(const usch *str);
+void savch(int c);
+void putch(int);
+void putstr(const usch *s);
+usch *sheap(const char *fmt, ...);
+struct iobuf *bsheap(struct iobuf *, const char *fmt, ...);
+void warning(const char *fmt, ...);
+void error(const char *fmt, ...);
+int cinput(void);
+int inc2(void);
+int Ccmnt(void (*d)(int));
+usch *heapid(int ch);
+usch *readid(int ch);
+void faststr(int bc, void (*d)(int));
+int fastnum(int ch, void (*d)(int));
+void *xrealloc(void *p, int sz);
+void *xmalloc(int sz);
diff --git a/lang/pcc/pcc/cc/cpp/cpy.y b/lang/pcc/pcc/cc/cpp/cpy.y
new file mode 100644 (file)
index 0000000..9af54c1
--- /dev/null
@@ -0,0 +1,221 @@
+/*     $Id: cpy.y,v 1.21 2014/05/28 08:52:42 plunky Exp $      */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include "config.h"
+
+#include "cpp.h"
+
+void yyerror(const char *);
+int setd(int l, int r);
+
+#define        EVALUNARY(tok, l, r) l.nd_val = tok r.nd_val; l.op = r.op
+#define        EVALBIN(tok, d, l, r)   \
+       d.op = setd(l.op, r.op); d.nd_val = l.nd_val tok r.nd_val
+#define        EVALUBIN(tok, d, l, r, t)                               \
+       d.op = setd(l.op, r.op);                                \
+       if (d.op == NUMBER) d.nd_val = l.nd_val tok r.nd_val;   \
+       else d.nd_uval = l.nd_uval tok r.nd_uval;               \
+       if (t && d.op) d.op = NUMBER
+#define        XEVALUBIN(tok, d, l, r)                                 \
+       if (r.nd_val) { EVALUBIN(tok, d, l, r, 0); } else d.op = 0
+%}
+
+%term stop
+%term EQ NE LE GE LS RS
+%term ANDAND OROR IDENT NUMBER UNUMBER DEFINED
+/*
+ * The following terminals are not used in the yacc code.
+ */
+%term STRING WSPACE CMNT
+
+%left ','
+%right '?' ':'
+%left OROR
+%left ANDAND
+%left '|' '^'
+%left '&'
+%binary EQ NE
+%binary '<' '>' LE GE
+%left LS RS
+%left '+' '-'
+%left '*' '/' '%'
+%right '!' '~' UMINUS
+%left '('
+
+%union {
+       struct nd node;
+}
+
+%type <node>   term e NUMBER UNUMBER
+
+%%
+S:     e '\n'  { 
+               if ($1.op == 0)
+                       error("division by zero");
+               return $1.nd_val;
+       }
+
+e:       e '*' e
+               { EVALUBIN(*, $$, $1, $3, 0); }
+       | e '/' e
+               { XEVALUBIN(/, $$, $1, $3); }
+       | e '%' e
+               { XEVALUBIN(%, $$, $1, $3); }
+       | e '+' e
+               { EVALBIN(+, $$, $1, $3); }
+       | e '-' e
+               { EVALBIN(-, $$, $1, $3); }
+       | e LS e
+               { EVALBIN(<<, $$, $1, $3); }
+       | e RS e
+               { EVALUBIN(>>, $$, $1, $3, 0); }
+       | e '<' e
+               { EVALUBIN(<, $$, $1, $3, 1); }
+       | e '>' e
+               { EVALUBIN(>, $$, $1, $3, 1); }
+       | e LE e
+               { EVALUBIN(<=, $$, $1, $3, 1); }
+       | e GE e
+               { EVALUBIN(>=, $$, $1, $3, 1); }
+       | e EQ e
+               { EVALUBIN(==, $$, $1, $3, 1); }
+       | e NE e
+               { EVALUBIN(!=, $$, $1, $3, 1); }
+       | e '&' e
+               { EVALBIN(&, $$, $1, $3); }
+       | e '^' e
+               { EVALBIN(^, $$, $1, $3); }
+       | e '|' e
+               { EVALBIN(|, $$, $1, $3); }
+       | e ANDAND e {
+               $$ = $1;
+               if ($1.nd_val) {
+                       $$.op = setd($1.op, $3.op);
+                       $$.nd_val = ($3.nd_val != 0);
+               }
+               if ($$.op == UNUMBER) $$.op = NUMBER;
+       }
+       | e OROR e {
+               if ($1.nd_val != 0) {
+                       $$.nd_val = ($1.nd_val != 0);
+                       $$.op = $1.op;
+               } else {
+                       $$.nd_val = ($3.nd_val != 0);
+                       $$.op = setd($1.op, $3.op);
+               }
+               if ($$.op == UNUMBER) $$.op = NUMBER;
+       }
+       | e '?' e ':' e {
+               if ($1.op == 0)
+                       $$ = $1;
+               else if ($1.nd_val)
+                       $$ = $3;
+               else
+                       $$ = $5;
+       }
+       | e ',' e {
+               $$.op = setd($1.op, $3.op);
+               $$.nd_val = $3.nd_val;
+               if ($$.op) $$.op =  $3.op;
+       }
+       | term
+               {$$ = $1;}
+term:
+         '-' term %prec UMINUS
+               { EVALUNARY(-, $$, $2); }
+       | '+' term %prec UMINUS
+               {$$ = $2;}
+       | '!' term
+               { $$.nd_val = ! $2.nd_val; $$.op = $2.op ? NUMBER : 0; }
+       | '~' term
+               { EVALUNARY(~, $$, $2); }
+       | '(' e ')'
+               {$$ = $2;}
+       | DEFINED '(' NUMBER ')'
+               {$$= $3;}
+       | DEFINED NUMBER
+               {$$ = $2;}
+       | NUMBER
+               {$$ = $1;}
+%%
+
+void
+yyerror(const char *err)
+{
+       error(err);
+}
+
+/*
+ * Set return type of an expression.
+ */
+int
+setd(int l, int r)
+{
+       if (!l || !r)
+               return 0; /* div by zero involved */
+       if (l == UNUMBER || r == UNUMBER)
+               return UNUMBER;
+       return NUMBER;
+}
+
diff --git a/lang/pcc/pcc/cc/cpp/scanner.l b/lang/pcc/pcc/cc/cpp/scanner.l
new file mode 100644 (file)
index 0000000..670e031
--- /dev/null
@@ -0,0 +1,939 @@
+%{
+/*     $Id: scanner.l,v 1.50 2011/06/03 15:42:45 plunky Exp $   */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+
+#include "compat.h"
+#include "cpp.h"
+#include "y.tab.h"
+%}
+
+%{
+static void cvtdig(int rad);
+static int charcon(usch *);
+static void elsestmt(void);
+static void ifdefstmt(void);
+static void ifndefstmt(void);
+static void endifstmt(void);
+static void ifstmt(void);
+static void cpperror(void);
+static void pragmastmt(void);
+static void undefstmt(void);
+static void cpperror(void);
+static void elifstmt(void);
+static void storepb(void);
+static void badop(const char *);
+void  include(void);
+void  define(void);
+
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+
+static int inch(void);
+
+static int scale, gotdef, contr;
+int inif;
+
+#ifdef FLEX_SCANNER /* should be set by autoconf instead */
+static int
+yyinput(char *b, int m)
+{
+       int c, i;
+
+       for (i = 0; i < m; i++) {
+               if ((c = inch()) < 0)
+                       break;
+               *b++ = c;
+               if (c == '\n') {
+                       i++;
+                       break;
+               }
+       }
+       return i;
+}
+#undef YY_INPUT
+#undef YY_BUF_SIZE
+#define        YY_BUF_SIZE (8*65536)
+#define YY_INPUT(b,r,m) (r = yyinput(b, m))
+#ifdef HAVE_CPP_VARARG_MACRO_GCC
+#define fprintf(x, ...) error(__VA_ARGS__)
+#endif
+#define        ECHO putstr((usch *)yytext)
+#undef fileno
+#define fileno(x) 0
+
+#if YY_FLEX_SUBMINOR_VERSION >= 31
+/* Hack to avoid unnecessary warnings */
+FILE *yyget_in (void);
+FILE *yyget_out  (void);
+int yyget_leng (void);
+char *yyget_text  (void);
+void yyset_in (FILE *  in_str );
+void yyset_out (FILE * out_str );
+int yyget_debug  (void);
+void yyset_debug (int  bdebug );
+int yylex_destroy  (void);
+#endif
+#else  /* Assume lex here */
+#undef input
+#undef unput
+#define input() inch()
+#define unput(ch) unch(ch)
+#endif
+#define PRTOUT(x) if (YYSTATE || slow) return x; if (!flslvl) putstr((usch *)yytext);
+/* protection against recursion in #include */
+#define MAX_INCLEVEL   100
+static int inclevel;
+%}
+
+D      [0-9]
+L      [a-zA-Z_]
+H      [a-fA-F0-9]
+E      [Ee][+-]?{D}+
+FS     (f|F|l|L)
+IS     (u|U|l|L)*
+WS     [\t ]
+
+%s IFR CONTR DEF COMMENT
+
+%%
+
+"\n"                   {       int os = YYSTATE;
+                               if (os != IFR)
+                                       BEGIN 0;
+                               ifiles->lineno++;
+                               if (flslvl == 0) {
+                                       if (ifiles->lineno == 1)
+                                               prtline();
+                                       else
+                                               putch('\n');
+                               }
+                               if ((os != 0 || slow) && !contr)
+                                       return '\n';
+                               contr = 0;
+                       }
+
+"\r"                   { ; /* Ignore CR's */ }
+
+<IFR>"++"              { badop("++"); }
+<IFR>"--"              { badop("--"); }
+<IFR>"=="              { return EQ; }
+<IFR>"!="              { return NE; }
+<IFR>"<="              { return LE; }
+<IFR>"<<"              { return LS; }
+<IFR>">>"              { return RS; }
+<IFR>">="              { return GE; }
+<IFR>"||"              { return OROR; }
+<IFR>"&&"              { return ANDAND; }
+<IFR>"defined"         {       int p, c;
+                               gotdef = 1;
+                               if ((p = c = yylex()) == '(')
+                                       c = yylex();
+                               if (c != IDENT || (p != IDENT && p != '('))
+                                       error("syntax error");
+                               if (p == '(' && yylex() != ')')
+                                       error("syntax error");
+                               return NUMBER;
+                       }
+
+<IFR>{WS}+             { ; }
+<IFR>{L}({L}|{D})*     {
+                               yylval.node.op = NUMBER;
+                               if (gotdef) {
+                                       yylval.node.nd_val
+                                           = lookup((usch *)yytext, FIND) != 0;
+                                       gotdef = 0;
+                                       return IDENT;
+                               }
+                               yylval.node.nd_val = 0;
+                               return NUMBER;
+                       }
+
+[0-9][0-9]*            {
+                               if (slow && !YYSTATE)
+                                       return IDENT;
+                               scale = yytext[0] == '0' ? 8 : 10;
+                               goto num;
+                       }
+
+0[xX]{H}+{IS}?         {       scale = 16;
+                       num:    if (YYSTATE == IFR) 
+                                       cvtdig(scale);
+                               PRTOUT(NUMBER);
+                       }
+0{D}+{IS}?             { scale = 8; goto num; }
+{D}+{IS}?              { scale = 10; goto num; }
+'(\\.|[^\\'])+'                {
+                               if (YYSTATE || slow) {
+                                       yylval.node.op = NUMBER;
+                                       yylval.node.nd_val = charcon((usch *)yytext);
+                                       return (NUMBER);
+                               }
+                               if (tflag)
+                                       yyless(1);
+                               if (!flslvl)
+                                       putstr((usch *)yytext);
+                       }
+
+<IFR>.                 { return yytext[0]; }
+
+{D}+{E}{FS}?           { PRTOUT(FPOINT); }
+{D}*"."{D}+({E})?{FS}? { PRTOUT(FPOINT); }
+{D}+"."{D}*({E})?{FS}? { PRTOUT(FPOINT); }
+
+^{WS}*#{WS}*           {       extern int inmac;
+
+                               if (inmac)
+                                       error("preprocessor directive found "
+                                           "while expanding macro");
+                               contr = 1;
+                               BEGIN CONTR;
+                       }
+{WS}+                  { PRTOUT(WSPACE); }
+
+<CONTR>"ifndef"                { contr = 0; ifndefstmt(); }
+<CONTR>"ifdef"         { contr = 0; ifdefstmt(); }
+<CONTR>"if"            { contr = 0; storepb(); BEGIN IFR; ifstmt(); BEGIN 0; }
+<CONTR>"include"       { contr = 0; BEGIN 0; include(); prtline(); }
+<CONTR>"else"          { contr = 0; elsestmt(); }
+<CONTR>"endif"         { contr = 0; endifstmt(); }
+<CONTR>"error"         { contr = 0; if (slow) return IDENT; cpperror(); BEGIN 0; }
+<CONTR>"define"                { contr = 0; BEGIN DEF; define(); BEGIN 0; }
+<CONTR>"undef"         { contr = 0; if (slow) return IDENT; undefstmt(); }
+<CONTR>"line"          { contr = 0; storepb(); BEGIN 0; line(); }
+<CONTR>"pragma"                { contr = 0; pragmastmt(); BEGIN 0; }
+<CONTR>"elif"          { contr = 0; storepb(); BEGIN IFR; elifstmt(); BEGIN 0; }
+
+
+
+"//".*$                        { /* if (tflag) yyless(..) */
+                               if (Cflag && !flslvl && !slow)
+                                       putstr((usch *)yytext);
+                               else if (!flslvl)
+                                       putch(' ');
+                       }
+"/*"                   {       int c, wrn;
+                               int prtcm = Cflag && !flslvl && !slow;
+                               extern int readmac;
+
+                               if (Cflag && !flslvl && readmac)
+                                       return CMNT;
+
+                               if (prtcm)
+                                       putstr((usch *)yytext);
+                               wrn = 0;
+                       more:   while ((c = input()) && c != '*') {
+                                       if (c == '\n')
+                                               putch(c), ifiles->lineno++;
+                                       else if (c == 1) /* WARN */
+                                               wrn = 1;
+                                       else if (prtcm)
+                                               putch(c);
+                               }
+                               if (c == 0)
+                                       return 0;
+                               if (prtcm)
+                                       putch(c);
+                               if ((c = input()) && c != '/') {
+                                       unput(c);
+                                       goto more;
+                               }
+                               if (prtcm)
+                                       putch(c);
+                               if (c == 0)
+                                       return 0;
+                               if (!tflag && !Cflag && !flslvl)
+                                       unput(' ');
+                               if (wrn)
+                                       unput(1);
+                       }
+
+<DEF>"##"              { return CONCAT; }
+<DEF>"#"               { return MKSTR; }
+<DEF>"..."             { return ELLIPS; }
+<DEF>"__VA_ARGS__"     { return VA_ARGS; }
+
+L?\"(\\.|[^\\"])*\"    { PRTOUT(STRING); }
+[a-zA-Z_0-9]+          { /* {L}({L}|{D})* */
+                               struct symtab *nl;
+                               if (slow)
+                                       return IDENT;
+                               if (YYSTATE == CONTR) {
+                                       if (flslvl == 0) {
+                                               /*error("undefined control");*/
+                                               while (input() != '\n')
+                                                       ;
+                                               unput('\n');
+                                               BEGIN 0;
+                                               goto xx;
+                                       } else {
+                                               BEGIN 0; /* do nothing */
+                                       }
+                               }
+                               if (flslvl) {
+                                       ; /* do nothing */
+                               } else if (isdigit((int)yytext[0]) == 0 &&
+                                   (nl = lookup((usch *)yytext, FIND)) != 0) {
+                                       usch *op = stringbuf;
+                                       putstr(gotident(nl));
+                                       stringbuf = op;
+                               } else
+                                       putstr((usch *)yytext);
+                               xx: ;
+                       }
+
+.                      {
+                               if (contr) {
+                                       while (input() != '\n')
+                                               ;
+                                       unput('\n');
+                                       BEGIN 0;
+                                       contr = 0;
+                                       goto yy;
+                               }
+                               if (YYSTATE || slow)
+                                       return yytext[0];
+                               if (yytext[0] == 6) { /* PRAGS */
+                                       usch *obp = stringbuf;
+                                       extern usch *prtprag(usch *);
+                                       *stringbuf++ = yytext[0];
+                                       do {
+                                               *stringbuf = input();
+                                       } while (*stringbuf++ != 14);
+                                       prtprag(obp);
+                                       stringbuf = obp;
+                               } else {
+                                       PRTOUT(yytext[0]);
+                               }
+                               yy:;
+                       }
+
+%%
+
+usch *yyp, yybuf[CPPBUF];
+
+int yylex(void);
+int yywrap(void);
+
+static int
+inpch(void)
+{
+       int len;
+
+       if (ifiles->curptr < ifiles->maxread)
+               return *ifiles->curptr++;
+
+       if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0)
+               error("read error on file %s", ifiles->orgfn);
+       if (len == 0)
+               return -1;
+       ifiles->curptr = ifiles->buffer;
+       ifiles->maxread = ifiles->buffer + len;
+       return inpch();
+}
+
+#define unch(c) *--ifiles->curptr = c
+
+static int
+inch(void)
+{
+       int c;
+
+again: switch (c = inpch()) {
+       case '\\': /* continued lines */
+msdos:         if ((c = inpch()) == '\n') {
+                       ifiles->lineno++;
+                       putch('\n');
+                       goto again;
+               } else if (c == '\r')
+                       goto msdos;
+               unch(c);
+               return '\\';
+       case '?': /* trigraphs */
+               if ((c = inpch()) != '?') {
+                       unch(c);
+                       return '?';
+               }
+               switch (c = inpch()) {
+               case '=': c = '#'; break;
+               case '(': c = '['; break;
+               case ')': c = ']'; break;
+               case '<': c = '{'; break;
+               case '>': c = '}'; break;
+               case '/': c = '\\'; break;
+               case '\'': c = '^'; break;
+               case '!': c = '|'; break;
+               case '-': c = '~'; break;
+               default:
+                       unch(c);
+                       unch('?');
+                       return '?';
+               }
+               unch(c);
+               goto again;
+       default:
+               return c;
+       }
+}
+
+/*
+ * Let the command-line args be faked defines at beginning of file.
+ */
+static void
+prinit(struct initar *it, struct includ *ic)
+{
+       char *a, *pre, *post;
+
+       if (it->next)
+               prinit(it->next, ic);
+       pre = post = NULL; /* XXX gcc */
+       switch (it->type) {
+       case 'D':
+               pre = "#define ";
+               if ((a = strchr(it->str, '=')) != NULL) {
+                       *a = ' ';
+                       post = "\n";
+               } else
+                       post = " 1\n";
+               break;
+       case 'U':
+               pre = "#undef ";
+               post = "\n";
+               break;
+       case 'i':
+               pre = "#include \"";
+               post = "\"\n";
+               break;
+       default:
+               error("prinit");
+       }
+       strlcat((char *)ic->buffer, pre, CPPBUF+1);
+       strlcat((char *)ic->buffer, it->str, CPPBUF+1);
+       if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
+               error("line exceeds buffer size");
+
+       ic->lineno--;
+       while (*ic->maxread)
+               ic->maxread++;
+}
+
+/*
+ * A new file included.
+ * If ifiles == NULL, this is the first file and already opened (stdin).
+ * Return 0 on success, -1 if file to be included is not found.
+ */
+int
+pushfile(usch *file)
+{
+       extern struct initar *initar;
+       struct includ ibuf;
+       struct includ *ic;
+       int c, otrulvl;
+
+       ic = &ibuf;
+       ic->next = ifiles;
+
+       slow = 0;
+       if (file != NULL) {
+               if ((ic->infil = open((char *)file, O_RDONLY)) < 0)
+                       return -1;
+               ic->orgfn = ic->fname = file;
+               if (++inclevel > MAX_INCLEVEL)
+                       error("Limit for nested includes exceeded");
+       } else {
+               ic->infil = 0;
+               ic->orgfn = ic->fname = (usch *)"<stdin>";
+       }
+       ic->buffer = ic->bbuf+NAMEMAX;
+       ic->curptr = ic->buffer;
+       ifiles = ic;
+       ic->lineno = 1;
+       ic->maxread = ic->curptr;
+       prtline();
+       if (initar) {
+               *ic->maxread = 0;
+               prinit(initar, ic);
+               if (dMflag)
+                       write(ofd, ic->buffer, strlen((char *)ic->buffer));
+               initar = NULL;
+       }
+
+       otrulvl = trulvl;
+
+       if ((c = yylex()) != 0)
+               error("yylex returned %d", c);
+
+       if (otrulvl != trulvl || flslvl)
+               error("unterminated conditional");
+
+       ifiles = ic->next;
+       close(ic->infil);
+       inclevel--;
+       return 0;
+}
+
+/*
+ * Print current position to output file.
+ */
+void
+prtline()
+{
+       usch *s, *os = stringbuf;
+
+       if (Mflag) {
+               if (dMflag)
+                       return; /* no output */
+               if (ifiles->lineno == 1) {
+                       s = sheap("%s: %s\n", Mfile, ifiles->fname);
+                       write(ofd, s, strlen((char *)s));
+               }
+       } else if (!Pflag)
+               putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
+       stringbuf = os;
+}
+
+void
+cunput(int c)
+{
+#ifdef PCC_DEBUG
+       extern int dflag;
+       if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c);
+#endif
+       unput(c);
+}
+
+int yywrap(void) { return 1; }
+
+static int
+dig2num(int c)
+{
+       if (c >= 'a')
+               c = c - 'a' + 10;
+       else if (c >= 'A')
+               c = c - 'A' + 10;
+       else
+               c = c - '0';
+       return c;
+}
+
+/*
+ * Convert string numbers to unsigned long long and check overflow.
+ */
+static void
+cvtdig(int rad)
+{
+       unsigned long long rv = 0;
+       unsigned long long rv2 = 0;
+       char *y = yytext;
+       int c;
+
+       c = *y++;
+       if (rad == 16)
+               y++;
+       while (isxdigit(c)) {
+               rv = rv * rad + dig2num(c);
+               /* check overflow */
+               if (rv / rad < rv2)
+                       error("Constant \"%s\" is out of range", yytext);
+               rv2 = rv;
+               c = *y++;
+       }
+       y--;
+       while (*y == 'l' || *y == 'L')
+               y++;
+       yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
+       yylval.node.nd_uval = rv;
+       if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
+               yylval.node.op = UNUMBER;
+       if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
+               /* too large for signed */
+               error("Constant \"%s\" is out of range", yytext);
+}
+
+static int
+charcon(usch *p)
+{
+       int val, c;
+
+       p++; /* skip first ' */
+       val = 0;
+       if (*p++ == '\\') {
+               switch (*p++) {
+               case 'a': val = '\a'; break;
+               case 'b': val = '\b'; break;
+               case 'f': val = '\f'; break;
+               case 'n': val = '\n'; break;
+               case 'r': val = '\r'; break;
+               case 't': val = '\t'; break;
+               case 'v': val = '\v'; break;
+               case '\"': val = '\"'; break;
+               case '\'': val = '\''; break;
+               case '\\': val = '\\'; break;
+               case 'x':
+                       while (isxdigit(c = *p)) {
+                               val = val * 16 + dig2num(c);
+                               p++;
+                       }
+                       break;
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7':
+                       p--;
+                       while (isdigit(c = *p)) {
+                               val = val * 8 + (c - '0');
+                               p++;
+                       }
+                       break;
+               default: val = p[-1];
+               }
+
+       } else
+               val = p[-1];
+       return val;
+}
+
+static void
+chknl(int ignore)
+{
+       int t;
+
+       slow = 1;
+       while ((t = yylex()) == WSPACE)
+               ;
+       if (t != '\n') {
+               if (ignore) {
+                       warning("newline expected, got \"%s\"", yytext);
+                       /* ignore rest of line */
+                       while ((t = yylex()) && t != '\n')
+                               ;
+               }
+               else
+                       error("newline expected, got \"%s\"", yytext);
+       }
+       slow = 0;
+}
+
+static void
+elsestmt(void)
+{
+       if (flslvl) {
+               if (elflvl > trulvl)
+                       ;
+               else if (--flslvl!=0) {
+                       flslvl++;
+               } else {
+                       trulvl++;
+                       prtline();
+               }
+       } else if (trulvl) {
+               flslvl++;
+               trulvl--;
+       } else
+               error("If-less else");
+       if (elslvl==trulvl+flslvl)
+               error("Too many else");
+       elslvl=trulvl+flslvl;
+       chknl(1);
+}
+
+static void
+ifdefstmt(void)                 
+{ 
+       int t;
+
+       if (flslvl) {
+               /* just ignore the rest of the line */
+               while (input() != '\n')
+                       ;
+               unput('\n');
+               yylex();
+               flslvl++;
+               return;
+       }
+       slow = 1;
+       do
+               t = yylex();
+       while (t == WSPACE);
+       if (t != IDENT)
+               error("bad ifdef");
+       slow = 0;
+       if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0)
+               trulvl++;
+       else
+               flslvl++;
+       chknl(0);
+}
+
+static void
+ifndefstmt(void)         
+{ 
+       int t;
+
+       slow = 1;
+       do
+               t = yylex();
+       while (t == WSPACE);
+       if (t != IDENT)
+               error("bad ifndef");
+       slow = 0;
+       if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0)
+               trulvl++;
+       else
+               flslvl++;
+       chknl(0);
+}
+
+static void
+endifstmt(void)                 
+{
+       if (flslvl) {
+               flslvl--;
+               if (flslvl == 0)
+                       prtline();
+       } else if (trulvl)
+               trulvl--;
+       else
+               error("If-less endif");
+       if (flslvl == 0)
+               elflvl = 0;
+       elslvl = 0;
+       chknl(1);
+}
+
+/*
+ * Note! Ugly!
+ * Walk over the string s and search for defined, and replace it with 
+ * spaces and a 1 or 0. 
+ */
+static void
+fixdefined(usch *s)
+{
+       usch *bc, oc;
+
+       for (; *s; s++) {
+               if (*s != 'd')
+                       continue;
+               if (memcmp(s, "defined", 7))
+                       continue;
+               /* Ok, got defined, can scratch it now */
+               memset(s, ' ', 7);
+               s += 7;
+#define        WSARG(x) (x == ' ' || x == '\t')
+               if (*s != '(' && !WSARG(*s))
+                       continue;
+               while (WSARG(*s))
+                       s++;
+               if (*s == '(')
+                       s++;
+               while (WSARG(*s))
+                       s++;
+#define IDARG(x) ((x>= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x == '_'))
+#define        NUMARG(x) (x >= '0' && x <= '9')
+               if (!IDARG(*s))
+                       error("bad defined arg");
+               bc = s;
+               while (IDARG(*s) || NUMARG(*s))
+                       s++;
+               oc = *s;
+               *s = 0;
+               *bc = (lookup(bc, FIND) != 0) + '0';
+               memset(bc+1, ' ', s-bc-1);
+               *s = oc;
+       }
+}
+
+/*
+ * get the full line of identifiers after an #if, pushback a WARN and
+ * the line and prepare for expmac() to expand.
+ * This is done before switching state.  When expmac is finished,
+ * pushback the expanded line, change state and call yyparse.
+ */
+static void
+storepb(void)
+{
+       usch *opb = stringbuf;
+       int c;
+
+       while ((c = input()) != '\n') {
+               if (c == '/') {
+                        if ((c = input()) == '*') {
+                               /* ignore comments here whatsoever */
+                               usch *g = stringbuf;
+                               getcmnt();
+                               stringbuf = g;
+                               continue;
+                       } else if (c == '/') {
+                               while ((c = input()) && c != '\n')
+                                       ;
+                               break;
+                       }
+                       unput(c);
+                       c = '/';
+               }
+               savch(c);
+       }
+       cunput('\n');
+       savch(0);
+       fixdefined(opb); /* XXX can fail if #line? */
+       cunput(1); /* WARN XXX */
+       unpstr(opb);
+       stringbuf = opb;
+       slow = 1;
+       expmac(NULL);
+       slow = 0;
+       /* line now expanded */
+       while (stringbuf > opb)
+               cunput(*--stringbuf);
+}
+
+static void
+ifstmt(void)
+{
+       if (flslvl == 0) {
+               slow = 1;
+               if (yyparse())
+                       ++trulvl;
+               else
+                       ++flslvl;
+               slow = 0;
+       } else
+               ++flslvl;
+}
+
+static void
+elifstmt(void)
+{
+       if (flslvl == 0)
+               elflvl = trulvl;
+       if (flslvl) {
+               if (elflvl > trulvl)
+                       ;
+               else if (--flslvl!=0)
+                       ++flslvl;
+               else {
+                       slow = 1;
+                       if (yyparse()) {
+                               ++trulvl;
+                               prtline();
+                       } else
+                               ++flslvl;
+                       slow = 0;
+               }
+       } else if (trulvl) {
+               ++flslvl;
+               --trulvl;
+       } else
+               error("If-less elif");
+}
+
+static usch *
+svinp(void)
+{
+       int c;
+       usch *cp = stringbuf;
+
+       while ((c = input()) && c != '\n')
+               savch(c);
+       savch('\n');
+       savch(0);
+       BEGIN 0;
+       return cp;
+}
+
+static void
+cpperror(void)
+{
+       usch *cp;
+       int c;
+
+       if (flslvl)
+               return;
+       c = yylex();
+       if (c != WSPACE && c != '\n')
+               error("bad error");
+       cp = svinp();
+       if (flslvl)
+               stringbuf = cp;
+       else
+               error("%s", cp);
+}
+
+static void
+undefstmt(void)
+{
+       struct symtab *np;
+
+       slow = 1;
+       if (yylex() != WSPACE || yylex() != IDENT)
+               error("bad undef");
+       if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
+               np->value = 0;
+       slow = 0;
+       chknl(0);
+}
+
+static void
+pragmastmt(void)
+{
+       int c;
+
+       slow = 1;
+       if (yylex() != WSPACE)
+               error("bad pragma");
+       if (!flslvl)
+               putstr((usch *)"#pragma ");
+       do {
+               c = input();
+               if (!flslvl)
+                       putch(c);       /* Do arg expansion instead? */
+       } while (c && c != '\n');
+       ifiles->lineno++;
+       prtline();
+       slow = 0;
+}
+
+static void
+badop(const char *op)
+{
+       error("invalid operator in preprocessor expression: %s", op);
+}
+
+int
+cinput()
+{
+       return input();
+}
diff --git a/lang/pcc/pcc/cc/cpp/tests/res1 b/lang/pcc/pcc/cc/cpp/tests/res1
new file mode 100644 (file)
index 0000000..bff9a25
--- /dev/null
@@ -0,0 +1,8 @@
+
+# 1 "<stdin>"
+
+
+
+
+char p[] = "x ## y";    
+                        
diff --git a/lang/pcc/pcc/cc/cpp/tests/res10 b/lang/pcc/pcc/cc/cpp/tests/res10
new file mode 100644 (file)
index 0000000..5f294c9
--- /dev/null
@@ -0,0 +1,16 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+int midiopen(int); 
+
+
+
+
+
+
+
+foo_optarg
diff --git a/lang/pcc/pcc/cc/cpp/tests/res11 b/lang/pcc/pcc/cc/cpp/tests/res11
new file mode 100644 (file)
index 0000000..4c49d18
--- /dev/null
@@ -0,0 +1,22 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+a
+a b
+a b c
+a b c d 
+
+
+
+
+
+
+__attribute__((__noreturn__))
+
+
+1  2
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/res12 b/lang/pcc/pcc/cc/cpp/tests/res12
new file mode 100644 (file)
index 0000000..05bab66
--- /dev/null
@@ -0,0 +1,21 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+2 2 2 2 2;
+
+
+
+
+
+
+
+
+
+
+
+
+(0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0,
diff --git a/lang/pcc/pcc/cc/cpp/tests/res13 b/lang/pcc/pcc/cc/cpp/tests/res13
new file mode 100644 (file)
index 0000000..5ec9b41
--- /dev/null
@@ -0,0 +1,13 @@
+
+# 1 "<stdin>"
+
+
+
+
+long
+
+
+
+
+
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/res14 b/lang/pcc/pcc/cc/cpp/tests/res14
new file mode 100644 (file)
index 0000000..dbd86d1
--- /dev/null
@@ -0,0 +1,11 @@
+
+# 1 "<stdin>"
+
+
+
+AB 
+
+
+
+i1(c) q p
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/res15 b/lang/pcc/pcc/cc/cpp/tests/res15
new file mode 100644 (file)
index 0000000..ea414de
--- /dev/null
@@ -0,0 +1,18 @@
+
+# 1 "<stdin>"
+
+do { _foo_X (); } while ( 0);
+
+
+do { _foo_Y (); } while ( 0);
+
+
+do { _foo_(); } while ( 0);
+
+
+
+
+(111 FIRST 111);
+(222 SECOND 222);
+(111 (222 THIRD 222) 111);
+(222 (111 FOURTH 111) 222);
diff --git a/lang/pcc/pcc/cc/cpp/tests/res15C b/lang/pcc/pcc/cc/cpp/tests/res15C
new file mode 100644 (file)
index 0000000..2b763e3
--- /dev/null
@@ -0,0 +1,18 @@
+
+# 1 "<stdin>"
+
+do { _foo_X (); } while (/* CONSTCOND */0);
+
+
+do { _foo_Y (); } while (/* CONSTCOND */0);
+
+
+do { _foo_(); } while (/* CONSTCOND */0);
+
+
+
+
+(111 /*LINTED*/ FIRST 111);
+(222 SECOND /*LINTED*/ 222);
+(111 /*LINTED*/ (222 THIRD /*LINTED*/ 222) 111);
+(222 (111 /*LINTED*/ FOURTH 111) /*LINTED*/ 222);
diff --git a/lang/pcc/pcc/cc/cpp/tests/res16 b/lang/pcc/pcc/cc/cpp/tests/res16
new file mode 100644 (file)
index 0000000..8a84a58
--- /dev/null
@@ -0,0 +1,108 @@
+
+# 1 "<stdin>"
+This file is testing line counting in various scenarios involving
+escaped newlines, including using the trigraph escape sequence
+
+--> 4 4
+"multi-line string"
+
+
+--> 8 8
+'multi-line character constant'
+
+
+--> 12 12
+multi-line 012345678 integer constant
+
+
+
+--> 17 17
+multi-line list of tokens
+
+
+
+
+
+--> 24 24
+
+
+--> 28 28
+
+
+
+
+
+
+--> 36 36
+
+
+--> 40 40
+   
+
+
+
+
+
+
+--> 48 48
+
+#pragma multi-line #pragma directive
+# 49 "<stdin>"
+
+
+
+--> 52 52
+
+
+
+
+--> 57 57
+multi-line macro embedded
+--> 59 59
+  
+
+
+
+--> 64 64
+macro with a leading comment
+--> 66 66
+       
+
+
+--> 70 70
+macro with leading whitespace and escaped newlines
+--> 72 72
+
+a token split by escaped newlines
+
+
+--> 77 77
+
+
+
+
+
+
+
+#pragma multi-line #pragma inside if-true block
+# 84 "<stdin>"
+
+
+
+--> 87 87
+
+--> 89 89
+  
+#pragma with a preceding comment
+# 90 "<stdin>"
+
+--> 91 91
+
+
+
+
+
+--> 97 97
diff --git a/lang/pcc/pcc/cc/cpp/tests/res16C b/lang/pcc/pcc/cc/cpp/tests/res16C
new file mode 100644 (file)
index 0000000..301fe95
--- /dev/null
@@ -0,0 +1,105 @@
+
+# 1 "<stdin>"
+This file is testing line counting in various scenarios involving
+escaped newlines, including using the trigraph escape sequence
+
+--> 4 4
+"multi-line string"
+
+
+--> 8 8
+'multi-line character constant'
+
+
+--> 12 12
+multi-line 012345678 integer constant
+
+
+
+--> 17 17
+multi-line list of tokens
+
+
+
+
+
+--> 24 24
+/* multi-line comment */
+
+
+--> 28 28
+ /*/ comment with escaped newlines /*
+         in the markers
+*/
+
+
+
+
+--> 36 36
+// multi-line C++ comment
+
+
+--> 40 40
+  //   C++ comment with leading whitespace and escaped newlines
+
+
+
+
+
+
+--> 48 48
+
+#pragma multi-line #pragma directive
+# 49 "<stdin>"
+
+
+
+--> 52 52
+
+
+
+
+--> 57 57
+multi-line macro /* with a comment */ embedded
+--> 59 59
+/*  comment    before    directive */ #define BAR macro with a leading comment
+
+
+
+--> 64 64
+BAR
+--> 66 66
+       
+
+
+--> 70 70
+macro with leading whitespace and escaped newlines
+--> 72 72
+
+a token split by escaped newlines
+
+
+--> 77 77
+
+
+
+
+
+
+
+#pragma multi-line #pragma inside if-true block
+# 84 "<stdin>"
+
+
+
+--> 87 87
+
+--> 89 89
+/* comment */ # pragma with a preceding comment
+--> 91 91
+
+
+
+
+
+--> 97 97
diff --git a/lang/pcc/pcc/cc/cpp/tests/res17 b/lang/pcc/pcc/cc/cpp/tests/res17
new file mode 100644 (file)
index 0000000..9cc042b
--- /dev/null
@@ -0,0 +1,33 @@
+
+# 1 "<stdin>"
+testing that pp-numbers are parsed correctly
+
+
+
+
+
+123.4e+foo
+123.4f+FOO
+123.4e+foo
+
+
+
+
+123.4e+foo
+
+
+
+
+FOO.123.foo.456+FOO+789.foo
+
+
+0xfaff
+
+
+
+0xfe00
+
+
+
+0xfeff
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/res18 b/lang/pcc/pcc/cc/cpp/tests/res18
new file mode 100644 (file)
index 0000000..f248e8b
--- /dev/null
@@ -0,0 +1,13 @@
+
+# 1 "<stdin>"
+
+
+"foo"
+"\"foo\""
+"\"foo\\n\""
+"\"\\\"foo\\\"\""
+"\"foo\\\\\""
+"\"\\\\\\\"foo\""
+"\"foo\\\\\\\\\""
+"foo\n"
+"foo\\n"
diff --git a/lang/pcc/pcc/cc/cpp/tests/res2 b/lang/pcc/pcc/cc/cpp/tests/res2
new file mode 100644 (file)
index 0000000..30da3c4
--- /dev/null
@@ -0,0 +1,27 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))
+^m(0,1);
+int i[] = { 1, 23, 4, 5,  };
+char c[2][6] = { "hello", "" };
+
+
+
+
+
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/res3 b/lang/pcc/pcc/cc/cpp/tests/res3
new file mode 100644 (file)
index 0000000..d42b7e0
--- /dev/null
@@ -0,0 +1,17 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+
+
+
+
+printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
+fputs(
+"strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
+\#include "vers2.h"
+"hello";
+"hello" ", world"
diff --git a/lang/pcc/pcc/cc/cpp/tests/res4 b/lang/pcc/pcc/cc/cpp/tests/res4
new file mode 100644 (file)
index 0000000..8e7649a
--- /dev/null
@@ -0,0 +1,6 @@
+
+# 1 "<stdin>"
+
+
+
+(1)
diff --git a/lang/pcc/pcc/cc/cpp/tests/res5 b/lang/pcc/pcc/cc/cpp/tests/res5
new file mode 100644 (file)
index 0000000..7d57f95
--- /dev/null
@@ -0,0 +1,5 @@
+
+# 1 "<stdin>"
+
+int j[] = { 123, 45, 67, 89,
+       10, 11, 12,  };
diff --git a/lang/pcc/pcc/cc/cpp/tests/res6 b/lang/pcc/pcc/cc/cpp/tests/res6
new file mode 100644 (file)
index 0000000..ee2ea69
--- /dev/null
@@ -0,0 +1,7 @@
+
+# 1 "<stdin>"
+
+
+
+
+foo
diff --git a/lang/pcc/pcc/cc/cpp/tests/res7 b/lang/pcc/pcc/cc/cpp/tests/res7
new file mode 100644 (file)
index 0000000..6d7c47c
--- /dev/null
@@ -0,0 +1,6 @@
+
+# 1 "<stdin>"
+
+
+a
+YES
diff --git a/lang/pcc/pcc/cc/cpp/tests/res8 b/lang/pcc/pcc/cc/cpp/tests/res8
new file mode 100644 (file)
index 0000000..118ead4
--- /dev/null
@@ -0,0 +1,9 @@
+
+# 1 "<stdin>"
+
+
+
+(hej.s_s.s_pos)
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/res9 b/lang/pcc/pcc/cc/cpp/tests/res9
new file mode 100644 (file)
index 0000000..631ecf1
--- /dev/null
@@ -0,0 +1,6 @@
+
+# 1 "<stdin>"
+
+
+
+ao
diff --git a/lang/pcc/pcc/cc/cpp/tests/test1 b/lang/pcc/pcc/cc/cpp/tests/test1
new file mode 100644 (file)
index 0000000..79a3c5d
--- /dev/null
@@ -0,0 +1,6 @@
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+char p[] = join(x, y); // equivalent to
+                       // char p[] = "x ## y";
diff --git a/lang/pcc/pcc/cc/cpp/tests/test10 b/lang/pcc/pcc/cc/cpp/tests/test10
new file mode 100644 (file)
index 0000000..dfba8b3
--- /dev/null
@@ -0,0 +1,14 @@
+#define __CONCAT(x,y) x ## y
+#define dev_type_open(n) int n(int)
+#define dev_decl(n,t) __CONCAT(dev_type_,t)(__CONCAT(n,t))
+#define cdev_decl(n) dev_decl(n,open)
+
+cdev_decl(midi); 
+
+# define __GETOPT_PREFIX foo_
+# define __GETOPT_CONCAT(x, y) x ## y
+# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y)
+# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y)
+# define optarg __GETOPT_ID (optarg)
+
+optarg
diff --git a/lang/pcc/pcc/cc/cpp/tests/test11 b/lang/pcc/pcc/cc/cpp/tests/test11
new file mode 100644 (file)
index 0000000..5bf4249
--- /dev/null
@@ -0,0 +1,20 @@
+#define D1(s, ...) s
+#define D2(s, ...) s D1(__VA_ARGS__)
+#define D3(s, ...) s D2(__VA_ARGS__)
+#define D4(s, ...) s D3(__VA_ARGS__)
+
+D1(a)
+D2(a, b)
+D3(a, b, c)
+D4(a, b, c, d) 
+
+
+#define __sun_attr___noreturn__ __attribute__((__noreturn__))
+#define ___sun_attr_inner(__a) __sun_attr_##__a
+#define __sun_attr__(__a) ___sun_attr_inner __a
+#define __NORETURN __sun_attr__((__noreturn__))
+__NORETURN
+#define X(...)
+#define Y(...)  1 __VA_ARGS__ 2
+Y(X X() ())
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/test12 b/lang/pcc/pcc/cc/cpp/tests/test12
new file mode 100644 (file)
index 0000000..a0a36f1
--- /dev/null
@@ -0,0 +1,19 @@
+#define y 2
+#define fe(p)       sfe(p) p
+#define sfe(p)    p
+#define Y fe(y) y  fe(y)
+
+Y;
+
+#    define S2B_QMIN 0
+#  define S2B_CMIN (S2B_QMIN + 8)
+#define S2B_1(i)        i,
+#define S2B_2(i)        S2B_1(i) S2B_1(i)
+#define S2B_4(i)        S2B_2(i) S2B_2(i)
+#define S2B_8(i)        S2B_4(i) S2B_4(i)
+#define S2B_16(i)       S2B_8(i) S2B_8(i)
+#define S2B_32(i)       S2B_16(i) S2B_16(i)
+#define S2B_64(i)       S2B_32(i) S2B_32(i)
+#define S2B_128(i)      S2B_64(i) S2B_64(i)
+#define S2B_256(i)      S2B_128(i) S2B_128(i)
+S2B_256(S2B_CMIN + 0)
diff --git a/lang/pcc/pcc/cc/cpp/tests/test13 b/lang/pcc/pcc/cc/cpp/tests/test13
new file mode 100644 (file)
index 0000000..51e2385
--- /dev/null
@@ -0,0 +1,11 @@
+
+#define UL long, foo
+#define D(I,F) I
+#define E(I) D(I)
+E(UL)
+
+#define FOO 1
+
+#if (FOO == 1)
+
+#endif /* FOO */ 
diff --git a/lang/pcc/pcc/cc/cpp/tests/test14 b/lang/pcc/pcc/cc/cpp/tests/test14
new file mode 100644 (file)
index 0000000..45c1892
--- /dev/null
@@ -0,0 +1,9 @@
+#define A(x) A ## x
+#define AB A(B)
+
+AB 
+
+#define i1(w) i2(w) p
+#define i2(x) i1(x) q
+i1(c)
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/test15 b/lang/pcc/pcc/cc/cpp/tests/test15
new file mode 100644 (file)
index 0000000..adca9ac
--- /dev/null
@@ -0,0 +1,16 @@
+#define        FOO(x)  do { _foo_ ## x (); } while (/* CONSTCOND */0)
+FOO(X);
+
+#define BAR    FOO(Y)
+BAR;
+
+#define BAZ    do { _foo_(); } while (/* CONSTCOND */0)
+BAZ;
+
+#define foo(a) (111 /*LINTED*/ a 111)
+#define bar(a) (222 a /*LINTED*/ 222)
+
+foo(FIRST);
+bar(SECOND);
+foo(bar(THIRD));
+bar(foo(FOURTH));
diff --git a/lang/pcc/pcc/cc/cpp/tests/test16 b/lang/pcc/pcc/cc/cpp/tests/test16
new file mode 100644 (file)
index 0000000..a7f3295
--- /dev/null
@@ -0,0 +1,97 @@
+This file is testing line counting in various scenarios involving
+escaped newlines, including using the trigraph escape sequence
+
+--> __LINE__ 4
+"multi-\
+line ??/
+string"
+--> __LINE__ 8
+'multi-\
+line ??/
+character constant'
+--> __LINE__ 12
+multi-\
+line 012\
+345??/
+678 integer constant
+--> __LINE__ 17
+multi-\
+line\
+ li??/
+st ??/
+of \
+tokens
+--> __LINE__ 24
+/* multi-\
+line ??/
+comment */
+--> __LINE__ 28
+ /\
+??/
+*/ comment with escaped newlines /*
+         in the markers
+??/
+*\
+/
+--> __LINE__ 36
+// multi-\
+line ??/
+C++ comment
+--> __LINE__ 40
+\
+ \
+ /\
+??/
+\
+/ ??/
+  C++ comment with leading whitespace and escaped newlines
+--> __LINE__ 48
+#pragma multi-\
+line ??/
+#pragma directive
+--> __LINE__ 52
+#define FOO multi-\
+line macro /* with\
+ a comment *??/
+/ embedded
+--> __LINE__ 57
+FOO
+--> __LINE__ 59
+/??/
+*  comment \
+   before ??/
+   directive */ #define BAR macro with a leading comment
+--> __LINE__ 64
+BAR
+--> __LINE__ 66
+\
+ ??/
+       #define BAZ macro with leading whitespace and escaped newlines
+--> __LINE__ 70
+BAZ
+--> __LINE__ 72
+#define POTATO a token split by escaped newlines
+PO\
+TA??/
+TO
+--> __LINE__ 77
+#if 0
+#pragma multi-??/
+line \
+#pragma inside if-false block
+--> __LINE__ 82
+#else
+#pragma multi-??/
+line \
+#pragma inside if-true block
+--> __LINE__ 87
+#endif
+--> __LINE__ 89
+/* comment */ # pragma with a preceding comment
+--> __LINE__ 91
+#if 0
+/* multi-\
+ * line comment at flslvl=1
+ */
+#endif
+--> __LINE__ 97
diff --git a/lang/pcc/pcc/cc/cpp/tests/test17 b/lang/pcc/pcc/cc/cpp/tests/test17
new file mode 100644 (file)
index 0000000..de26098
--- /dev/null
@@ -0,0 +1,31 @@
+testing that pp-numbers are parsed correctly
+
+#define e      E
+#define f      F
+#define foo    FOO
+
+123.4e+foo
+123.4f+foo
+12\
+3.4\
+e\
++\
+foo
+123??/
+.4??/
+e??/
++??/
+foo
+foo.123.foo.456+foo+789.foo
+
+#if 0xfaff
+0xfaff
+#endif
+
+#if 0xfe00
+0xfe00
+#endif
+
+#if 0xfeff
+0xfeff
+#endif
diff --git a/lang/pcc/pcc/cc/cpp/tests/test18 b/lang/pcc/pcc/cc/cpp/tests/test18
new file mode 100644 (file)
index 0000000..caad737
--- /dev/null
@@ -0,0 +1,11 @@
+#define str(a) #a
+
+str(foo)
+str("foo")
+str("foo\n")
+str("\"foo\"")
+str("foo\\")
+str("\\\"foo")
+str("foo\\\\")
+str(foo\n)
+str(foo\\n)
diff --git a/lang/pcc/pcc/cc/cpp/tests/test19 b/lang/pcc/pcc/cc/cpp/tests/test19
new file mode 100644 (file)
index 0000000..52ed28e
--- /dev/null
@@ -0,0 +1,33 @@
+#define        S(x)    S0(x)
+#define        S0(x)   #x
+#define        T(x,y)\
+S(x)\
+S(y)
+#define        T0(x,y)\
+S0(x)\
+S0(y)
+#define        U(x)\
+S(x)\
+S(x)
+#define        U0(x)\
+S0(x)\
+S0(x)
+#define        V(x)\
+V_(x)\
+V_(x)
+#define        V_(x)\
+S(x)
+#define        V0(x)\
+V0_(x)\
+V0_(x)
+#define        V0_(x)\
+S0(x)
+__COUNTER__
+S(__COUNTER__)
+S0(__COUNTER__)
+T(__COUNTER__,__COUNTER__)
+T0(__COUNTER__,__COUNTER__)
+U(__COUNTER__)
+U0(__COUNTER__)
+V(__COUNTER__)
+V0(__COUNTER__)
diff --git a/lang/pcc/pcc/cc/cpp/tests/test2 b/lang/pcc/pcc/cc/cpp/tests/test2
new file mode 100644 (file)
index 0000000..283d4fb
--- /dev/null
@@ -0,0 +1,25 @@
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+#define str(x) # x
+f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+g(x+(3,4)-w) | h 5) & m
+(f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
+char c[2][6] = { str(hello), str() };
+/*
+ * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+ * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
+ * int i[] = { 1, 23, 4, 5, };
+ * char c[2][6] = { "hello", "" };
+ */
diff --git a/lang/pcc/pcc/cc/cpp/tests/test3 b/lang/pcc/pcc/cc/cpp/tests/test3
new file mode 100644 (file)
index 0000000..a659245
--- /dev/null
@@ -0,0 +1,15 @@
+#define str(s) # s
+#define xstr(s) str(s)
+#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
+       x ## s, x ## t)
+#define INCFILE(n) vers ## n
+#define glue(a, b) a ## b
+#define xglue(a, b) glue(a, b)
+#define HIGHLOW "hello"
+#define LOW LOW ", world"
+debug(1, 2);
+fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
+       == 0) str(: @\n), s);
+\#include xstr(INCFILE(2).h)
+glue(HIGH, LOW);
+xglue(HIGH, LOW)
diff --git a/lang/pcc/pcc/cc/cpp/tests/test4 b/lang/pcc/pcc/cc/cpp/tests/test4
new file mode 100644 (file)
index 0000000..0068f37
--- /dev/null
@@ -0,0 +1,4 @@
+#define foobar 1
+#define C(x,y) x##y
+#define D(x) (C(x,bar))
+D(foo)
diff --git a/lang/pcc/pcc/cc/cpp/tests/test5 b/lang/pcc/pcc/cc/cpp/tests/test5
new file mode 100644 (file)
index 0000000..3ca0bb6
--- /dev/null
@@ -0,0 +1,3 @@
+#define t(x,y,z) x ## y ## z
+int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
+       t(10,,), t(,11,), t(,,12), t(,,) };
diff --git a/lang/pcc/pcc/cc/cpp/tests/test6 b/lang/pcc/pcc/cc/cpp/tests/test6
new file mode 100644 (file)
index 0000000..28cfdde
--- /dev/null
@@ -0,0 +1,5 @@
+#define X(a,b, \
+       c,d) \
+       foo
+
+X(1,2,3,4)
diff --git a/lang/pcc/pcc/cc/cpp/tests/test7 b/lang/pcc/pcc/cc/cpp/tests/test7
new file mode 100644 (file)
index 0000000..b22b22b
--- /dev/null
@@ -0,0 +1,4 @@
+#define a() YES
+#define b() a
+b()
+b()()
diff --git a/lang/pcc/pcc/cc/cpp/tests/test8 b/lang/pcc/pcc/cc/cpp/tests/test8
new file mode 100644 (file)
index 0000000..c5d2f9a
--- /dev/null
@@ -0,0 +1,7 @@
+// test macro expansion in arguments
+#define s_pos              s_s.s_pos
+#define foo(x) (x)
+
+//hej.s_pos
+foo(hej.s_pos)
+
diff --git a/lang/pcc/pcc/cc/cpp/tests/test9 b/lang/pcc/pcc/cc/cpp/tests/test9
new file mode 100644 (file)
index 0000000..4d4368d
--- /dev/null
@@ -0,0 +1,4 @@
+#define C(a,b,c) a##b##c
+#define N(x,y) C(x,_,y)
+#define A_O ao
+N(A,O)
diff --git a/lang/pcc/pcc/cc/cpp/token.c b/lang/pcc/pcc/cc/cpp/token.c
new file mode 100644 (file)
index 0000000..2b13b17
--- /dev/null
@@ -0,0 +1,1446 @@
+/*     $Id: token.c,v 1.162 2016/03/12 15:46:06 ragge Exp $    */
+
+/*
+ * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Tokenizer for the C preprocessor.
+ * There are three main routines:
+ *     - fastscan() loops over the input stream searching for magic
+ *             characters that may require actions.
+ *     - yylex() returns something from the input stream that
+ *             is suitable for yacc.
+ *
+ *     Other functions of common use:
+ *     - inpch() returns a raw character from the current input stream.
+ *     - inch() is like inpch but \\n and trigraphs are expanded.
+ *     - unch() pushes back a character to the input stream.
+ *
+ * Input data can be read from either stdio or a buffer.
+ * If a buffer is read, it will return EOF when ended and then jump back
+ * to the previous buffer.
+ *     - setibuf(usch *ptr). Buffer to read from, until NULL, return EOF.
+ *             When EOF returned, pop buffer.
+ *     - setobuf(usch *ptr).  Buffer to write to
+ *
+ * There are three places data is read:
+ *     - fastscan() which has a small loop that will scan over input data.
+ *     - flscan() where everything is skipped except directives (flslvl)
+ *     - inch() that everything else uses.
+ *
+ * 5.1.1.2 Translation phases:
+ *     1) Convert UCN to UTF-8 which is what pcc uses internally (chkucn).
+ *        Remove \r (unwanted)
+ *        Convert trigraphs (chktg)
+ *     2) Remove \\\n.  Need extra care for identifiers and #line.
+ *     3) Tokenize.
+ *        Remove comments (fastcmnt)
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include "compat.h"
+#include "cpp.h"
+
+static void cvtdig(usch **);
+static int dig2num(int);
+static int charcon(usch **);
+static void elsestmt(void);
+static void ifdefstmt(void);
+static void ifndefstmt(void);
+static void endifstmt(void);
+static void ifstmt(void);
+static void cpperror(void);
+static void cppwarning(void);
+static void undefstmt(void);
+static void pragmastmt(void);
+static void elifstmt(void);
+
+static int inpch(void);
+static int chktg(void);
+static int chkucn(void);
+static void unch(int c);
+
+#define        PUTCH(ch) if (!flslvl) putch(ch)
+/* protection against recursion in #include */
+#define MAX_INCLEVEL   100
+static int inclevel;
+
+struct includ *ifiles;
+
+/* some common special combos for init */
+#define C_NL   (C_SPEC|C_WSNL)
+#define C_DX   (C_SPEC|C_ID|C_DIGIT|C_HEX)
+#define C_I    (C_SPEC|C_ID|C_ID0)
+#define C_IP   (C_SPEC|C_ID|C_ID0|C_EP)
+#define C_IX   (C_SPEC|C_ID|C_ID0|C_HEX)
+#define C_IXE  (C_SPEC|C_ID|C_ID0|C_HEX|C_EP)
+
+usch spechr[256] = {
+       0,      0,      0,      0,      C_SPEC, C_SPEC, 0,      0,
+       0,      C_WSNL, C_NL,   0,      0,      C_WSNL, 0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+       0,      0,      0,      0,      0,      0,      0,      0,
+
+       C_WSNL, C_2,    C_SPEC, 0,      0,      0,      C_2,    C_SPEC,
+       0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC,
+       C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,
+       C_DX,   C_DX,   0,      0,      C_2,    C_2,    C_2,    C_SPEC,
+
+       0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    0,      C_SPEC, 0,      0,      C_I,
+
+       0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
+
+/* utf-8 */
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+       C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
+};
+
+/*
+ * fill up the input buffer
+ */
+static int
+inpbuf(void)
+{
+       int len;
+
+       if (ifiles->infil == -1)
+               return 0;
+       len = read(ifiles->infil, ifiles->buffer, CPPBUF);
+       if (len == -1)
+               error("read error on file %s", ifiles->orgfn);
+       if (len > 0) {
+               ifiles->buffer[len] = 0;
+               ifiles->curptr = ifiles->buffer;
+               ifiles->maxread = ifiles->buffer + len;
+       }
+       return len;
+}
+
+/*
+ * Fillup input buffer to contain at least minsz characters.
+ */
+static int
+refill(int minsz)
+{
+       usch *dp;
+       int i, sz;
+
+       if (ifiles->curptr+minsz < ifiles->maxread)
+               return 0; /* already enough in input buffer */
+
+       sz = ifiles->maxread - ifiles->curptr;
+       dp = ifiles->buffer - sz;
+       for (i = 0; i < sz; i++)
+               dp[i] = ifiles->curptr[i];
+       i = inpbuf();
+       ifiles->curptr = dp;
+       if (i == 0) {
+               ifiles->maxread = ifiles->buffer;
+               ifiles->buffer[0] = 0;
+       }
+       return 0;
+}
+#define        REFILL(x) if (ifiles->curptr+x >= ifiles->maxread) refill(x)
+
+/*
+ * return a raw character from the input stream
+ */
+static inline int
+inpch(void)
+{
+
+       do {
+               if (ifiles->curptr < ifiles->maxread)
+                       return *ifiles->curptr++;
+       } while (inpbuf() > 0);
+
+       return -1;
+}
+
+/*
+ * push a character back to the input stream
+ */
+static void
+unch(int c)
+{
+       if (c == -1)
+               return;
+
+       ifiles->curptr--;
+       if (ifiles->curptr < ifiles->bbuf)
+               error("pushback buffer full");
+       *ifiles->curptr = (usch)c;
+}
+
+/*
+ * Check for (and convert) trigraphs.
+ */
+static int
+chktg(void)
+{
+       int ch;
+
+       if ((ch = inpch()) != '?') {
+               unch(ch);
+               return 0;
+       }
+
+       switch (ch = inpch()) {
+       case '=':  return '#';
+       case '(':  return '[';
+       case ')':  return ']';
+       case '<':  return '{';
+       case '>':  return '}';
+       case '/':  return '\\';
+       case '\'': return '^';
+       case '!':  return '|';
+       case '-':  return '~';
+       }
+
+       unch(ch);
+       unch('?');
+       return 0;
+}
+
+/*
+ * 5.1.1.2 Translation phase 1.
+ */
+static int
+inc1(void)
+{
+       int ch, c2;
+
+       do {
+               ch = inpch();
+       } while (ch == '\r' || (ch == '\\' && chkucn()));
+       if (ch == '?' && (c2 = chktg()))
+               ch = c2;
+       return ch;
+}
+
+
+/*
+ * 5.1.1.2 Translation phase 2.
+ */
+int
+inc2(void)
+{
+       int ch, c2;
+
+       if ((ch = inc1()) != '\\')
+               return ch;
+       if ((c2 = inc1()) == '\n') {
+               ifiles->escln++;
+               ch = inc2();
+       } else
+               unch(c2);
+       return ch;
+}
+
+static int incmnt;
+/*
+ * deal with comments in the fast scanner.
+ * ps prints out the initial '/' if failing to batch comment.
+ */
+static int
+fastcmnt(int ps)
+{
+       int ch, rv = 1;
+
+       incmnt = 1;
+       if ((ch = inc2()) == '/') { /* C++ comment */
+               while ((ch = inc2()) != '\n')
+                       ;
+               unch(ch);
+       } else if (ch == '*') {
+               for (;;) {
+                       if ((ch = inc2()) < 0)
+                               break;
+                       if (ch == '*') {
+                               if ((ch = inc2()) == '/') {
+                                       break;
+                               } else
+                                       unch(ch);
+                       } else if (ch == '\n') {
+                               ifiles->lineno++;
+                               putch('\n');
+                       }
+               }
+       } else {
+               if (ps) PUTCH('/'); /* XXX ? */
+               unch(ch);
+               rv = 0;
+        }
+       if (ch < 0)
+               error("file ends in comment");
+       incmnt = 0;
+       return rv;
+}
+
+/*
+ * return next char, partly phase 3.
+ */
+static int
+inch(void)
+{
+       int ch, n;
+
+       ch = inc2();
+       n = ifiles->lineno;
+       if (ch == '/' && Cflag == 0 && fastcmnt(0)) {
+               /* Comments 5.1.1.2 p3 */
+               /* no space if traditional or multiline */
+               ch = (tflag || n != ifiles->lineno) ? inch() : ' ';
+       }
+       return ch;
+}
+
+/*
+ * check for universal-character-name on input, and
+ * unput to the pushback buffer encoded as UTF-8.
+ */
+static int
+chkucn(void)
+{
+       unsigned long cp, m;
+       int ch, n;
+
+       if (incmnt)
+               return 0;
+       if ((ch = inpch()) == -1)
+               return 0;
+       if (ch == 'u')
+               n = 4;
+       else if (ch == 'U')
+               n = 8;
+       else {
+               unch(ch);
+               return 0;
+       }
+
+       cp = 0;
+       while (n-- > 0) {
+               if ((ch = inpch()) == -1 || (spechr[ch] & C_HEX) == 0) {
+                       warning("invalid universal character name");
+                       // XXX should actually unput the chars and return 0
+                       unch(ch); // XXX eof
+                       break;
+               }
+               cp = cp * 16 + dig2num(ch);
+       }
+
+       if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60)
+           || (cp >= 0xd800 && cp <= 0xdfff))  /* 6.4.3.2 */
+               error("universal character name cannot be used");
+
+       if (cp > 0x7fffffff)
+               error("universal character name out of range");
+
+       n = 0;
+       m = 0x7f;
+       while (cp > m) {
+               unch(0x80 | (cp & 0x3f));
+               cp >>= 6;
+               m >>= (n++ ? 1 : 2);
+       }
+       unch(((m << 1) ^ 0xfe) | cp);
+       return 1;
+}
+
+/*
+ * deal with comments when -C is active.
+ * Save comments in expanded macros???
+ */
+int
+Ccmnt(void (*d)(int))
+{
+       int ch;
+
+       if ((ch = inch()) == '/') { /* C++ comment */
+               d(ch);
+               do {
+                       d(ch);
+               } while ((ch = inch()) != '\n');
+               unch(ch);
+               return 1;
+       } else if (ch == '*') {
+               d('/');
+               d('*');
+               for (;;) {
+                       ch = inch();
+                       d(ch);
+                       if (ch == '*') {
+                               if ((ch = inch()) == '/') {
+                                       d(ch);
+                                       return 1;
+                               } else
+                                       unch(ch);
+                       } else if (ch == '\n') {
+                               ifiles->lineno++;
+                       }
+               }
+       }
+       d('/');
+        unch(ch);
+        return 0;
+}
+
+/*
+ * Traverse over spaces and comments from the input stream,
+ * Returns first non-space character.
+ */
+static int
+fastspc(void)
+{
+       int ch;
+
+       while ((ch = inch()), ISWS(ch))
+               ;
+       return ch;
+}
+
+/*
+ * As above but only between \n and #.
+ */
+static int
+fastspcg(void)
+{
+       int ch, c2;
+
+       while ((ch = inch()) == '/' || ch == '%' || ISWS(ch)) {
+               if (ch == '%') {
+                       if ((c2 = inch()) == ':')
+                               ch = '#'; /* digraphs */
+                       else
+                               unch(c2);
+                       break;
+               }
+               if (ch == '/') {
+                       if (Cflag)
+                               return ch;
+                       if (fastcmnt(0) == 0)
+                               break;
+                       putch(' ');
+               } else
+                       putch(ch);
+       }
+       return ch;
+}
+
+usch idbuf[MAXIDSZ+1];
+/*
+ * readin chars and store in buf. Warn about too long names.
+ */
+usch *
+readid(int ch)
+{
+       int p = 0;
+
+       do {
+               if (p == MAXIDSZ)
+                       warning("identifier exceeds C99 5.2.4.1, truncating");
+               if (p < MAXIDSZ)
+                       idbuf[p] = ch;
+               p++;
+       } while (spechr[ch = inch()] & C_ID);
+       idbuf[p] = 0;
+       unch(ch);
+       return idbuf;
+}
+
+/*
+ * get a string or character constant and save it as given by d.
+ */
+void
+faststr(int bc, void (*d)(int))
+{
+       int ch;
+
+       incmnt = 1;
+       d(bc);
+       while ((ch = inc2()) != bc) {
+               if (ch == '\n') {
+                       warning("unterminated literal");
+                       incmnt = 0;
+                       unch(ch);
+                       return;
+               }
+               if (ch < 0)
+                       return;
+               if (ch == '\\') {
+                       incmnt = 0;
+                       if (chkucn())
+                               continue;
+                       incmnt = 1;
+                       d(ch);
+                       ch = inc2();
+               }
+               d(ch);
+       }
+       d(ch);
+       incmnt = 0;
+}
+
+/*
+ * get a preprocessing number and save it as given by d.
+ * Initial char ch is always stored.
+ * returns first non-pp-number char.
+ *
+ *     pp-number:      digit
+ *                     . digit
+ *                     pp-number digit
+ *                     pp-number identifier-nondigit
+ *                     pp-number e sign
+ *                     pp-number E sign
+ *                     pp-number p sign
+ *                     pp-number P sign
+ *                     pp-number .
+ */
+int
+fastnum(int ch, void (*d)(int))
+{
+       int c2;
+
+       if ((spechr[ch] & C_DIGIT) == 0) {
+               /* not digit, dot */
+               d(ch);
+               ch = inch();
+               if ((spechr[ch] & C_DIGIT) == 0)
+                       return ch;
+       }
+       for (;;) {
+               d(ch);
+               if ((ch = inch()) < 0)
+                       return -1;
+               if ((spechr[ch] & C_EP)) {
+                       if ((c2 = inch()) != '-' && c2 != '+') {
+                               if (c2 >= 0)
+                                       unch(c2);
+                               break;
+                       }
+                       d(ch);
+                       ch = c2;
+               } else if (ch == '.' || (spechr[ch] & C_ID)) {
+                       continue;
+               } else
+                       break;
+       }
+       return ch;
+}
+
+/*
+ * Scan quickly the input file searching for:
+ *     - '#' directives
+ *     - keywords (if not flslvl)
+ *     - comments
+ *
+ *     Handle strings, numbers and trigraphs with care.
+ *     Only data from pp files are scanned here, never any rescans.
+ *     This loop is always at trulvl.
+ */
+static void
+fastscan(void)
+{
+       struct iobuf *ob;
+       struct symtab *nl;
+       int ch, c2, i, nch;
+       usch *cp, *dp;
+
+       goto run;
+
+       for (;;) {
+               /* tight loop to find special chars */
+               /* should use getchar/putchar here */
+               for (;;) {
+                       if (ifiles->curptr < ifiles->maxread) {
+                               ch = *ifiles->curptr++;
+                       } else {
+                               if (inpbuf() > 0)
+                                       continue;
+                               return;
+                       }
+xloop:                 if (ch < 0)
+                               return; /* EOF */
+                       if ((spechr[ch] & C_SPEC) != 0)
+                               break;
+                       putch(ch);
+               }
+
+               REFILL(2);
+               nch = *ifiles->curptr;
+               switch (ch) {
+               case WARN:
+               case CONC:
+                       error("bad char passed");
+                       break;
+
+               case '/': /* Comments */
+                       if (nch != '/' && nch != '*') {
+                               putch(ch);
+                               continue;
+                       }
+                       if (Cflag == 0) {
+                               if (fastcmnt(1))
+                                       putch(' '); /* 5.1.1.2 p3 */
+                       } else
+                               Ccmnt(putch);
+                       break;
+
+               case '\n': /* newlines, for pp directives */
+                       /* take care of leftover \n */
+                       i = ifiles->escln + 1;
+                       ifiles->lineno += i;
+                       ifiles->escln = 0;
+                       while (i-- > 0)
+                               putch('\n');
+
+                       /* search for a # */
+run:                   while ((ch = inch()) == '\t' || ch == ' ')
+                               putch(ch);
+                       if (ch == '%') {
+                               if ((c2 = inch()) != ':')
+                                       unch(c2);
+                               else
+                                       ch = '#';
+                       }
+                       if (ch  == '#')
+                               ppdir();
+                       else
+                               goto xloop;
+                       break;
+
+               case '?':
+                       if (nch == '?' && (ch = chktg()))
+                               goto xloop;
+                       putch('?');
+                       break;
+
+               case '\'': /* character constant */
+                       if (tflag) {
+                               putch(ch);
+                               break;  /* character constants ignored */
+                       }
+                       /* FALLTHROUGH */
+               case '\"': /* strings */
+                       faststr(ch, putch);
+                       break;
+
+               case '.':  /* for pp-number */
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       ch = fastnum(ch, putch);
+                       goto xloop;
+
+               case 'u':
+                       if (nch == '8' && ifiles->curptr[1] == '\"') {
+                               putch(ch);
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case 'L':
+               case 'U':
+                       if (nch == '\"' || nch == '\'') {
+                               putch(ch);
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+#ifdef PCC_DEBUG
+                       if ((spechr[ch] & C_ID) == 0)
+                               error("fastscan");
+#endif
+               ident:
+                       if (flslvl)
+                               error("fastscan flslvl");
+                       dp = readid(ch);
+                       if ((nl = lookup(dp, FIND))) {
+                               if ((ob = kfind(nl))) {
+                                       if (*ob->buf == '-' || *ob->buf == '+')
+                                               putch(' ');
+                                       for (cp = ob->buf; cp < ob->cptr; cp++)
+                                               putch(*cp);
+                                       if (ob->cptr[-1] == '-' ||
+                                           ob->cptr[-1] == '+')
+                                               putch(' ');
+                                       bufree(ob);
+                               }
+                       } else
+                               putstr(dp);
+                       break;
+
+               case '\\':
+                       if (nch == '\n') {
+                               ifiles->escln++;
+                               ifiles->curptr++;
+                               break;
+                       }
+                       if (chkucn()) {
+                               ch = inch();
+                               goto ident;
+                       }
+                       putch('\\');
+                       break;
+               }
+       }
+
+/*eof:*/       warning("unexpected EOF");
+       putch('\n');
+}
+
+/*
+ * Store an if/elif line on heap for parsing, evaluate macros and 
+ * call yyparse().
+ */
+static usch *yyinp;
+int inexpr;
+static int
+exprline(void)
+{
+       struct iobuf *ob;
+       struct symtab *nl;
+       int oCflag = Cflag;
+       usch *bp = stringbuf, *dp;
+       int c, d, ifdef;
+
+       Cflag = ifdef = 0;
+
+       while ((c = inch()) != '\n') {
+               if (c == '\'' || c == '\"') {
+                       faststr(c, savch);
+                       continue;
+               }
+               if (ISDIGIT(c) || c == '.') {
+                       c = fastnum(c, savch);
+                       if (c == '\n')
+                               break;
+                       unch(c);
+                       continue;
+               }
+               if (c == 'L' || c == 'u' || c == 'U') {
+                       unch(d = inch());
+                       if (d == '\'')  /* discard wide designator */
+                               continue;
+               }
+               if (ISID0(c)) {
+                       dp = readid(c);
+                       nl = lookup(dp, FIND);
+                       if (nl && *nl->value == DEFLOC) {
+                               ifdef = 1;
+                       } else if (ifdef) {
+                               savch(nl ? '1' : '0');
+                               ifdef = 0;
+                       } else if (nl != NULL) {
+                               inexpr = 1;
+                               if ((ob = kfind(nl))) {
+                                       putob(ob, 0);
+                                       savstr(ob->buf);
+                                       bufree(ob);
+                               } else
+                                       savch('0');
+                               inexpr = 0;
+                       } else
+                               savch('0');
+               } else
+                       savch(c);
+       }
+       savch(0);
+       unch('\n');
+       yyinp = bp;
+       c = yyparse();
+       stringbuf = bp;
+       Cflag = oCflag;
+       return c;
+}
+
+int
+yylex(void)
+{
+       int ch, c2, t;
+
+       while ((ch = *yyinp++) == ' ' || ch == '\t')
+               ;
+       t = ISDIGIT(ch) ? NUMBER : ch;
+       if (ch < 128 && (spechr[ch] & C_2))
+               c2 = *yyinp++;
+       else
+               c2 = 0;
+
+       switch (t) {
+       case 0: return WARN;
+       case '=':
+               if (c2 == '=') return EQ;
+               break;
+       case '!':
+               if (c2 == '=') return NE;
+               break;
+       case '|':
+               if (c2 == '|') return OROR;
+               break;
+       case '&':
+               if (c2 == '&') return ANDAND;
+               break;
+       case '<':
+               if (c2 == '<') return LS;
+               if (c2 == '=') return LE;
+               break;
+       case '>':
+               if (c2 == '>') return RS;
+               if (c2 == '=') return GE;
+               break;
+       case '+':
+       case '-':
+               if (ch == c2)
+                       error("invalid preprocessor operator %c%c", ch, c2);
+               break;
+
+       case '\'':
+               yynode.op = NUMBER;
+               yynode.nd_val = charcon(&yyinp);
+               return NUMBER;
+
+       case NUMBER:
+               cvtdig(&yyinp);
+               return NUMBER;
+
+       default:
+               if (ISID0(t)) {
+                       yyinp--;
+                       while (ISID(*yyinp))
+                               yyinp++;
+                       yynode.nd_val = 0;
+                       return NUMBER;
+               }
+               return ch;
+       }
+       yyinp--;
+       return ch;
+}
+
+/*
+ * Let the command-line args be faked defines at beginning of file.
+ */
+static void
+prinit(struct initar *it, struct includ *ic)
+{
+       const char *pre, *post;
+       char *a;
+
+       if (it->next)
+               prinit(it->next, ic);
+       pre = post = NULL; /* XXX gcc */
+       switch (it->type) {
+       case 'D':
+               pre = "#define ";
+               if ((a = strchr(it->str, '=')) != NULL) {
+                       *a = ' ';
+                       post = "\n";
+               } else
+                       post = " 1\n";
+               break;
+       case 'U':
+               pre = "#undef ";
+               post = "\n";
+               break;
+       case 'i':
+               pre = "#include \"";
+               post = "\"\n";
+               break;
+       default:
+               error("prinit");
+       }
+       strlcat((char *)ic->buffer, pre, CPPBUF+1);
+       strlcat((char *)ic->buffer, it->str, CPPBUF+1);
+       if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
+               error("line exceeds buffer size");
+
+       ic->lineno--;
+       while (*ic->maxread)
+               ic->maxread++;
+}
+
+/*
+ * A new file included.
+ * If ifiles == NULL, this is the first file and already opened (stdin).
+ * Return 0 on success, -1 if file to be included is not found.
+ */
+int
+pushfile(const usch *file, const usch *fn, int idx, void *incs)
+{
+       extern struct initar *initar;
+       struct includ ibuf;
+       struct includ *ic;
+       int otrulvl;
+
+       ic = &ibuf;
+       ic->next = ifiles;
+
+       if (file != NULL) {
+               if ((ic->infil = open((const char *)file, O_RDONLY)) < 0)
+                       return -1;
+               ic->orgfn = ic->fname = file;
+               if (++inclevel > MAX_INCLEVEL)
+                       error("limit for nested includes exceeded");
+       } else {
+               ic->infil = 0;
+               ic->orgfn = ic->fname = (const usch *)"<stdin>";
+       }
+#ifndef BUF_STACK
+       ic->bbuf = malloc(BBUFSZ);
+#endif
+       ic->buffer = ic->bbuf+PBMAX;
+       ic->curptr = ic->buffer;
+       ifiles = ic;
+       ic->lineno = 1;
+       ic->escln = 0;
+       ic->maxread = ic->curptr;
+       ic->idx = idx;
+       ic->incs = incs;
+       ic->fn = fn;
+       prtline(1);
+       if (initar) {
+               int oin = ic->infil;
+               ic->infil = -1;
+               *ic->maxread = 0;
+               prinit(initar, ic);
+               initar = NULL;
+               if (dMflag)
+                       printf("%s", (char *)ic->buffer);
+               fastscan();
+               prtline(1);
+               ic->infil = oin;
+       }
+
+       otrulvl = trulvl;
+
+       fastscan();
+
+       if (otrulvl != trulvl || flslvl)
+               error("unterminated conditional");
+
+#ifndef BUF_STACK
+       free(ic->bbuf);
+#endif
+       ifiles = ic->next;
+       close(ic->infil);
+       inclevel--;
+       return 0;
+}
+
+/*
+ * Print current position to output file.
+ */
+void
+prtline(int nl)
+{
+       struct iobuf *ob;
+
+       if (Mflag) {
+               if (dMflag)
+                       return; /* no output */
+               if (ifiles->lineno == 1 &&
+                   (MMDflag == 0 || ifiles->idx != SYSINC)) {
+                       printf("%s: %s\n", Mfile, ifiles->fname);
+                       if (MPflag &&
+                           strcmp((const char *)ifiles->fname, (char *)MPfile))
+                               printf("%s:\n", ifiles->fname);
+               }
+       } else if (!Pflag) {
+               ob = bsheap(0, "\n# %d \"%s\"", ifiles->lineno, ifiles->fname);
+               if (ifiles->idx == SYSINC)
+                       bsheap(ob, " 3");
+               if (nl) bsheap(ob, "\n");
+               putstr(ob->buf);
+               bufree(ob);
+       }
+}
+
+void
+cunput(int c)
+{
+#ifdef PCC_DEBUG
+//     if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
+#endif
+       unch(c);
+}
+
+static int
+dig2num(int c)
+{
+       if (c >= 'a')
+               c = c - 'a' + 10;
+       else if (c >= 'A')
+               c = c - 'A' + 10;
+       else
+               c = c - '0';
+       return c;
+}
+
+/*
+ * Convert string numbers to unsigned long long and check overflow.
+ */
+static void
+cvtdig(usch **yyp)
+{
+       unsigned long long rv = 0;
+       unsigned long long rv2 = 0;
+       usch *y = *yyp;
+       int rad;
+
+       y--;
+       rad = *y != '0' ? 10 : y[1] == 'x' ||  y[1] == 'X' ? 16 : 8;
+       if (rad == 16)
+               y += 2;
+       while ((spechr[*y] & C_HEX)) {
+               rv = rv * rad + dig2num(*y);
+               /* check overflow */
+               if (rv / rad < rv2)
+                       error("constant is out of range");
+               rv2 = rv;
+               y++;
+       }
+       yynode.op = NUMBER;
+       while (*y == 'l' || *y == 'L' || *y == 'u' || *y == 'U') {
+               if (*y == 'u' || *y == 'U')
+                       yynode.op = UNUMBER;
+               y++;
+       }
+       yynode.nd_uval = rv;
+       if ((rad == 8 || rad == 16) && yynode.nd_val < 0)
+               yynode.op = UNUMBER;
+       if (yynode.op == NUMBER && yynode.nd_val < 0)
+               /* too large for signed, see 6.4.4.1 */
+               error("constant is out of range");
+       *yyp = y;
+}
+
+static int
+charcon(usch **yyp)
+{
+       int val, c;
+       usch *p = *yyp;
+
+       val = 0;
+       if (*p++ == '\\') {
+               switch (*p++) {
+               case 'a': val = '\a'; break;
+               case 'b': val = '\b'; break;
+               case 'f': val = '\f'; break;
+               case 'n': val = '\n'; break;
+               case 'r': val = '\r'; break;
+               case 't': val = '\t'; break;
+               case 'v': val = '\v'; break;
+               case '\"': val = '\"'; break;
+               case '\'': val = '\''; break;
+               case '\\': val = '\\'; break;
+               case 'x':
+                       while ((spechr[c = *p] & C_HEX)) {
+                               val = val * 16 + dig2num(c);
+                               p++;
+                       }
+                       break;
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7':
+                       p--;
+                       while ((spechr[c = *p] & C_DIGIT)) {
+                               val = val * 8 + (c - '0');
+                               p++;
+                       }
+                       break;
+               default: val = p[-1];
+               }
+
+       } else
+               val = p[-1];
+       if (*p != '\'')
+               error("bad charcon");
+       *yyp = ++p;
+       return val;
+}
+
+static void
+chknl(int ignore)
+{
+       void (*f)(const char *, ...);
+       int t;
+
+       f = ignore ? warning : error;
+       if ((t = fastspc()) != '\n') {
+               if (t) {
+                       f("newline expected");
+                       /* ignore rest of line */
+                       while ((t = inch()) >= 0 && t != '\n')
+                               ;
+               } else
+                       f("no newline at end of file");
+       }
+       unch(t);
+}
+
+static void
+elsestmt(void)
+{
+       if (flslvl) {
+               if (elflvl > trulvl)
+                       ;
+               else if (--flslvl!=0)
+                       flslvl++;
+               else
+                       trulvl++;
+       } else if (trulvl) {
+               flslvl++;
+               trulvl--;
+       } else
+               error("#else in non-conditional section");
+       if (elslvl==trulvl+flslvl)
+               error("too many #else");
+       elslvl=trulvl+flslvl;
+       chknl(1);
+}
+
+static void
+ifdefstmt(void)
+{
+       usch *bp;
+       int ch;
+
+       if (!ISID0(ch = fastspc()))
+               error("bad #ifdef");
+       bp = readid(ch);
+
+       if (lookup(bp, FIND) == NULL)
+               flslvl++;
+       else
+               trulvl++;
+       chknl(0);
+}
+
+static void
+ifndefstmt(void)
+{
+       usch *bp;
+       int ch;
+
+       if (!ISID0(ch = fastspc()))
+               error("bad #ifndef");
+       bp = readid(ch);
+       if (lookup(bp, FIND) != NULL)
+               flslvl++;
+       else
+               trulvl++;
+       chknl(0);
+}
+
+static void
+endifstmt(void)
+{
+       if (flslvl)
+               flslvl--;
+       else if (trulvl)
+               trulvl--;
+       else
+               error("#endif in non-conditional section");
+       if (flslvl == 0)
+               elflvl = 0;
+       elslvl = 0;
+       chknl(1);
+}
+
+static void
+ifstmt(void)
+{
+       exprline() ? trulvl++ : flslvl++;
+}
+
+static void
+elifstmt(void)
+{
+       if (flslvl == 0)
+               elflvl = trulvl;
+       if (flslvl) {
+               if (elflvl > trulvl)
+                       ;
+               else if (--flslvl!=0)
+                       flslvl++;
+               else if (exprline())
+                       trulvl++;
+               else
+                       flslvl++;
+       } else if (trulvl) {
+               flslvl++;
+               trulvl--;
+       } else
+               error("#elif in non-conditional section");
+}
+
+/* save line into stringbuf */
+static usch *
+savln(void)
+{
+       int c;
+       usch *cp = stringbuf;
+
+       while ((c = inch()) != -1) {
+               if (c == '\n') {
+                       unch(c);
+                       break;
+               }
+               savch(c);
+       }
+       savch(0);
+
+       return cp;
+}
+
+static void
+cpperror(void)
+{
+       usch *cp;
+
+       cp = savln();
+       error("#error %s", cp);
+       stringbuf = cp;
+}
+
+static void
+cppwarning(void)
+{
+       usch *cp;
+
+       cp = savln();
+       warning("#warning %s", cp);
+       stringbuf = cp;
+}
+
+static void
+undefstmt(void)
+{
+       struct symtab *np;
+       usch *bp;
+       int ch;
+
+       if (!ISID0(ch = fastspc()))
+               error("bad #undef");
+       bp = readid(ch);
+       if ((np = lookup(bp, FIND)) != NULL)
+               np->value = 0;
+       chknl(0);
+}
+
+static void
+identstmt(void)
+{
+       struct iobuf *ob = NULL;
+       struct symtab *sp;
+       usch *bp;
+       int ch;
+
+       if (ISID0(ch = fastspc())) {
+               bp = readid(ch);
+               if ((sp = lookup(bp, FIND)))
+                       ob = kfind(sp);
+               if (ob->buf[0] != '\"')
+                       goto bad;
+               if (ob)
+                       bufree(ob);
+       } else if (ch == '\"') {
+               faststr(ch, savch);
+       } else
+               goto bad;
+       chknl(1);
+       return;
+bad:
+       error("bad #ident directive");
+}
+
+static void
+pragmastmt(void)
+{
+       int ch;
+
+       putstr((const usch *)"\n#pragma");
+       while ((ch = inch()) != '\n' && ch > 0)
+               putch(ch);
+       unch(ch);
+       prtline(1);
+}
+
+int
+cinput(void)
+{
+
+       return inch();
+}
+
+#define        DIR_FLSLVL      001
+#define        DIR_FLSINC      002
+static struct {
+       const char *name;
+       void (*fun)(void);
+       int flags;
+} ppd[] = {
+       { "ifndef", ifndefstmt, DIR_FLSINC },
+       { "ifdef", ifdefstmt, DIR_FLSINC },
+       { "if", ifstmt, DIR_FLSINC },
+       { "include", include, 0 },
+       { "else", elsestmt, DIR_FLSLVL },
+       { "endif", endifstmt, DIR_FLSLVL },
+       { "error", cpperror, 0 },
+       { "warning", cppwarning, 0 },
+       { "define", define, 0 },
+       { "undef", undefstmt, 0 },
+       { "line", line, 0 },
+       { "pragma", pragmastmt, 0 },
+       { "elif", elifstmt, DIR_FLSLVL },
+       { "ident", identstmt, 0 },
+#ifdef GCC_COMPAT
+       { "include_next", include_next, 0 },
+#endif
+};
+#define        NPPD    (int)(sizeof(ppd) / sizeof(ppd[0]))
+
+static void
+skpln(void)
+{
+       int ch;
+
+       /* just ignore the rest of the line */
+       while ((ch = inch()) != -1) {
+               if (ch == '\n') {
+                       unch('\n');
+                       break;
+               }
+       }
+}
+
+/*
+ * do an even faster scan than fastscan while at flslvl.
+ * just search for a new directive.
+ */
+static void
+flscan(void)
+{
+       int ch;
+
+       for (;;) {
+               switch (ch = inch()) {
+               case -1:
+                       return;
+               case '\n':
+                       ifiles->lineno++;
+                       putch('\n');
+                       if ((ch = fastspcg()) == '#')
+                               return;
+                       unch(ch);
+                       break;
+               case '/':
+                       fastcmnt(0);    /* may be around directives */
+                       break;
+               }
+        }
+}
+
+
+/*
+ * Handle a preprocessor directive.
+ * # is already found.
+ */
+void
+ppdir(void)
+{
+       int ch, i, oldC;
+       usch *bp;
+
+       oldC = Cflag;
+redo:  Cflag = 0;
+       if ((ch = fastspc()) == '\n') { /* empty directive */
+               unch(ch);
+               Cflag = oldC;
+               return;
+       }
+       Cflag = oldC;
+       if ((spechr[ch] & C_ID0) == 0)
+               goto out;
+       bp = readid(ch);
+
+       /* got some keyword */
+       for (i = 0; i < NPPD; i++) {
+               if (bp[0] == ppd[i].name[0] &&
+                   strcmp((char *)bp, ppd[i].name) == 0) {
+                       if (flslvl == 0) {
+                               (*ppd[i].fun)();
+                               if (flslvl == 0)
+                                       return;
+                       } else {
+                               if (ppd[i].flags & DIR_FLSLVL) {
+                                       (*ppd[i].fun)();
+                                       if (flslvl == 0)
+                                               return;
+                               }else if (ppd[i].flags & DIR_FLSINC)
+                                       flslvl++;
+                       }
+                       flscan();
+                       goto redo;
+               }
+       }
+       flscan();
+       goto redo;
+
+out:
+       if (flslvl == 0 && Aflag == 0)
+               error("invalid preprocessor directive");
+
+       unch(ch);
+       skpln();
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/Makefile.in b/lang/pcc/pcc/cc/cxxcom/Makefile.in
new file mode 100644 (file)
index 0000000..b2b2ec0
--- /dev/null
@@ -0,0 +1,186 @@
+#      $Id: Makefile.in,v 1.7 2016/03/08 18:42:13 ragge Exp $
+#
+# Makefile.in for cxxcom
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+CC = @CC@
+EXEEXT = @EXEEXT@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -D_ISOC99_SOURCE -DLANG_CXX \
+       -Dos_$(TARGOS) -Dmach_$(TARGMACH) \
+       -I$(srcdir) -I$(builddir) -I$(top_builddir) -I$(MIPDIR) -I$(MDIR) \
+       -I$(top_srcdir)/os/$(TARGOS) -I$(COMMONDIR)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LFLAGS =
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+TARGOS = @targos@
+TARGOSVER = @targosver@
+TARGMACH = @targmach@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+MIPDIR=$(top_srcdir)/mip
+COMMONDIR=$(top_srcdir)/common
+
+DEST=@BINPREFIX@cxxcom$(EXEEXT)
+MANPAGE=@BINPREFIX@cxxcom
+MKEXT=mkext$(EXEEXT)
+
+all: $(DEST)
+
+OBJS=  builtins.o cgram.o code.o common.o compat.o external.o          \
+       gcc_compat.o init.o inline.o local.o local2.o main.o cxxcode.o  \
+       match.o optim.o optim2.o order.o pftn.o reader.o                \
+       regs.o scan.o stabs.o symtabs.o table.o trees.o
+
+LOBJS= mkext.lo common.lo table.lo
+
+HDRS=  $(srcdir)/pass1.h $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h        \
+       $(MDIR)/macdefs.h $(MIPDIR)/node.h $(COMMONDIR)/compat.h
+
+#
+# round 1: generate external.[ch], cgram.[ch] & scan.c
+#
+
+$(LOBJS): $(HDRS)
+
+mkext.lo: $(MIPDIR)/mkext.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c
+
+common.lo: $(MIPDIR)/common.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c
+
+table.lo: $(MDIR)/table.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c
+
+$(MKEXT): $(LOBJS)
+       $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS)
+
+external.c: $(MKEXT)
+       $(builddir)/$(MKEXT)
+
+cgram.c: $(srcdir)/cgram.y
+       $(YACC) $(YFLAGS) -d $(srcdir)/cgram.y
+       mv -f y.tab.c cgram.c
+       mv -f y.tab.h cgram.h
+
+scan.c: $(srcdir)/scan.l
+       $(LEX) $(LFLAGS) $(srcdir)/scan.l
+       mv -f $(LEX_OUTPUT_ROOT).c scan.c
+
+#
+# round 2: compile $(OBJS)
+#
+
+$(OBJS): $(HDRS) external.c cgram.c
+
+builtins.o: $(srcdir)/builtins.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/builtins.c
+
+cgram.o: cgram.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ cgram.c
+
+code.o: $(MDIR)/code.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/code.c
+
+common.o: $(MIPDIR)/common.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c
+
+compat.o: $(COMMONDIR)/compat.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c
+
+cxxcode.o: $(srcdir)/cxxcode.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cxxcode.c
+
+external.o: external.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c
+
+gcc_compat.o: $(srcdir)/gcc_compat.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/gcc_compat.c
+
+init.o: $(srcdir)/init.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c
+
+inline.o: $(srcdir)/inline.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/inline.c
+
+local.o: $(MDIR)/local.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local.c
+
+local2.o: $(MDIR)/local2.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c
+
+main.o: $(srcdir)/main.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c
+
+match.o: $(MIPDIR)/match.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c
+
+optim.o: $(srcdir)/optim.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/optim.c
+
+optim2.o: $(MIPDIR)/optim2.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c
+
+order.o: $(MDIR)/order.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c
+
+pftn.o: $(srcdir)/pftn.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/pftn.c
+
+reader.o: $(MIPDIR)/reader.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c
+
+regs.o: $(MIPDIR)/regs.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c
+
+scan.o: scan.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ scan.c
+
+stabs.o: $(srcdir)/stabs.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/stabs.c
+
+symtabs.o: $(srcdir)/symtabs.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/symtabs.c
+
+table.o: $(MDIR)/table.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c
+
+trees.o: $(srcdir)/trees.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/trees.c
+
+#
+# round 3: build $(DEST)
+#
+
+$(DEST): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+install: $(DEST)
+       test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)"
+       $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir)
+       test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1"
+#      $(INSTALL_DATA) $(srcdir)/ccom.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1
+
+clean:
+       rm -f $(DEST) $(OBJS) $(MKEXT) $(LOBJS) $(LEX_OUTPUT_ROOT).c    \
+           scan.c y.tab.[ch] cgram.[ch] external.[ch]
+
+distclean: clean
+       rm -f Makefile
diff --git a/lang/pcc/pcc/cc/cxxcom/builtins.c b/lang/pcc/pcc/cc/cxxcom/builtins.c
new file mode 100644 (file)
index 0000000..f863be3
--- /dev/null
@@ -0,0 +1,808 @@
+/*     $Id: builtins.c,v 1.7 2016/03/05 15:31:25 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef NO_C_BUILTINS
+
+/*
+ * replace an alloca function with direct allocation on stack.
+ * return a destination temp node.
+ */
+static NODE *
+builtin_alloca(const struct bitable *bt, NODE *a)
+{
+       NODE *t, *u;
+
+#ifdef notyet
+       if (xnobuiltins)
+               return NULL;
+#endif
+
+       t = tempnode(0, VOID|PTR, 0, 0);
+       u = tempnode(regno(t), VOID|PTR, 0, 0);
+       spalloc(t, a, SZCHAR);
+       return u;
+}
+
+/*
+ * Determine if a value is known to be constant at compile-time and
+ * hence that PCC can perform constant-folding on expressions involving
+ * that value.
+ */
+static NODE *
+builtin_constant_p(const struct bitable *bt, NODE *a)
+{
+       void putjops(NODE *p, void *arg);
+       NODE *f;
+       int isconst;
+
+       walkf(a, putjops, 0);
+       for (f = a; f->n_op == COMOP; f = f->n_right)
+               ;
+       isconst = nncon(f);
+       tfree(a);
+       return bcon(isconst);
+}
+
+/*
+ * Hint to the compiler whether this expression will evaluate true or false.
+ * Just ignored for now.
+ */
+static NODE *
+builtin_expect(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+
+       if (a && a->n_op == CM) {
+               tfree(a->n_right);
+               f = a->n_left;
+               nfree(a);
+               a = f;
+       }
+
+       return a;
+}
+
+/*
+ * Take integer absolute value.
+ * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1)))
+ */
+static NODE *
+builtin_abs(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q, *r, *t, *t2, *t3;
+       int tmp1, tmp2, shift;
+
+       if (a->n_type != INT)
+               a = cast(a, INT, 0);
+
+       if (a->n_op == ICON) {
+               if (getlval(a) < 0)
+                       setlval(a, -getlval(a));
+               p = a;
+       } else {
+               t = tempnode(0, a->n_type, a->n_df, a->n_ap);
+               tmp1 = regno(t);
+               p = buildtree(ASSIGN, t, a);
+
+               t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
+               shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1;
+               q = buildtree(RS, t, bcon(shift));
+
+               t2 = tempnode(0, a->n_type, a->n_df, a->n_ap);
+               tmp2 = regno(t2);
+               q = buildtree(ASSIGN, t2, q);
+
+               t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
+               t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
+               t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
+               r = buildtree(MINUS, buildtree(ER, t, t2), t3);
+
+               p = buildtree(COMOP, p, buildtree(COMOP, q, r));
+       }
+
+       return p;
+}
+
+#define        cmop(x,y) buildtree(COMOP, x, y)
+#define        lblnod(l) nlabel(l)
+
+#ifndef TARGET_CXZ
+/*
+ * Find number of beginning 0's in a word of type t.
+ * t should be deunsigned.
+ */
+static NODE *
+builtin_cxz(NODE *a, TWORD t, int isclz)
+{
+       NODE *t101, *t102;
+       NODE *rn, *p;
+       int l15, l16, l17;
+       int sz;
+
+       t = ctype(t);
+       sz = (int)tsize(t, 0, 0);
+
+       t101 = tempnode(0, INT, 0, 0);
+       t102 = tempnode(0, t, 0, 0);
+       l15 = getlab();
+       l16 = getlab();
+       l17 = getlab();
+       rn = buildtree(ASSIGN, ccopy(t102), a);
+       rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0)));
+       rn = cmop(rn, lblnod(l16));
+
+       p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15));
+       rn = cmop(rn, p);
+       if (isclz) {
+               p = buildtree(CBRANCH,
+                   buildtree(GE, ccopy(t102), bcon(0)), bcon(l17));
+       } else {
+               p = buildtree(CBRANCH,
+                   buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)),
+                   bcon(0)), bcon(l17));
+       }
+       rn = cmop(rn, p);
+
+       rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0));
+
+       rn = cmop(rn, lblnod(l17));
+       rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1)));
+
+       rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1)));
+
+       rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0));
+       rn = cmop(rn, lblnod(l15));
+       return cmop(rn, t101);
+}
+
+static NODE *
+builtin_clz(const struct bitable *bt, NODE *a)
+{
+       return builtin_cxz(a, INT, 1);
+}
+
+static NODE *
+builtin_clzl(const struct bitable *bt, NODE *a)
+{
+       return builtin_cxz(a, LONG, 1);
+}
+
+static NODE *
+builtin_clzll(const struct bitable *bt, NODE *a)
+{
+       return builtin_cxz(a, LONGLONG, 1);
+}
+
+static NODE *
+builtin_ctz(const struct bitable *bt, NODE *a)
+{
+       return builtin_cxz(a, INT, 0);
+}
+
+static NODE *
+builtin_ctzl(const struct bitable *bt, NODE *a)
+{
+       return builtin_cxz(a, LONG, 0);
+}
+
+static NODE *
+builtin_ctzll(const struct bitable *bt, NODE *a)
+{
+       return builtin_cxz(a, LONGLONG, 0);
+}
+#endif
+
+#ifndef TARGET_FFS
+/*
+ * Find number of beginning 0's in a word of type t.
+ * t should be deunsigned.
+ */
+static NODE *
+builtin_ff(NODE *a, TWORD t)
+{
+       NODE *t101, *t102;
+       NODE *rn, *p;
+       int l15, l16, l17;
+       int sz;
+
+       t = ctype(t);
+       sz = (int)tsize(t, 0, 0)+1;
+
+       t101 = tempnode(0, INT, 0, 0);
+       t102 = tempnode(0, t, 0, 0);
+       l15 = getlab();
+       l16 = getlab();
+       l17 = getlab();
+       rn = buildtree(ASSIGN, ccopy(t101), bcon(0));
+       rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a));
+
+       p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15));
+       rn = cmop(rn, p);
+
+       rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1)));
+
+       rn = cmop(rn, lblnod(l16));
+
+       p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15));
+       rn = cmop(rn, p);
+
+       p = buildtree(CBRANCH,
+           buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)),
+           bcon(0)), bcon(l17));
+       rn = cmop(rn, p);
+
+       rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0));
+
+       rn = cmop(rn, lblnod(l17));
+       rn = cmop(rn, buildtree(RSEQ, t102, bcon(1)));
+
+       rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1)));
+
+       rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0));
+       rn = cmop(rn, lblnod(l15));
+       return cmop(rn, t101);
+}
+
+static NODE *
+builtin_ffs(const struct bitable *bt, NODE *a)
+{
+       return builtin_ff(a, INT);
+}
+
+static NODE *
+builtin_ffsl(const struct bitable *bt, NODE *a)
+{
+       return builtin_ff(a, LONG);
+}
+
+static NODE *
+builtin_ffsll(const struct bitable *bt, NODE *a)
+{
+       return builtin_ff(a, LONGLONG);
+}
+#endif
+
+/*
+ * Get size of object, if possible.
+ * Currently does nothing,
+ */
+static NODE *
+builtin_object_size(const struct bitable *bt, NODE *a)
+{
+       CONSZ v = icons(a->n_right);
+       NODE *f;
+
+       if (v < 0 || v > 3)
+               uerror("arg2 must be between 0 and 3");
+
+       f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, bt->rt));
+       nfree(a);
+       return f;
+}
+
+#ifndef TARGET_STDARGS
+static NODE *
+builtin_stdarg_start(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q;
+       int sz;
+
+       /* must first deal with argument size; use int size */
+       p = a->n_right;
+       if (p->n_type < INT) {
+               sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap));
+       } else
+               sz = 1;
+
+       /* do the real job */
+       p = buildtree(ADDROF, p, NIL); /* address of last arg */
+#ifdef BACKAUTO
+       p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */
+#else
+       p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */
+#endif
+       q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */
+       q = buildtree(CAST, q, p); /* cast to void * (for assignment) */
+       p = q->n_right;
+       nfree(q->n_left);
+       nfree(q);
+       p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */
+       nfree(a);
+       return p;
+}
+
+static NODE *
+builtin_va_arg(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q, *r, *rv;
+       int sz, nodnum;
+
+       /* create a copy to a temp node of current ap */
+       p = ccopy(a->n_left);
+       q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+       nodnum = regno(q);
+       rv = buildtree(ASSIGN, q, p);
+
+       r = a->n_right;
+       sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR;
+       /* add one to ap */
+#ifdef BACKAUTO
+       rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz)));
+#else
+#error fix wrong eval order in builtin_va_arg
+       ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz)));
+#endif
+
+       nfree(a->n_right);
+       nfree(a);
+       r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap);
+       return buildtree(COMOP, rv, buildtree(UMUL, r, NIL));
+
+}
+
+static NODE *
+builtin_va_end(const struct bitable *bt, NODE *a)
+{
+       tfree(a);
+       return bcon(0); /* nothing */
+}
+
+static NODE *
+builtin_va_copy(const struct bitable *bt, NODE *a)
+{
+       NODE *f;
+
+       f = buildtree(ASSIGN, a->n_left, a->n_right);
+       nfree(a);
+       return f;
+}
+#endif /* TARGET_STDARGS */
+
+/*
+ * For unimplemented "builtin" functions, try to invoke the
+ * non-builtin name
+ */
+static NODE *
+binhelp(NODE *a, TWORD rt, char *n)
+{
+       NODE *f = block(NAME, NIL, NIL, INT, 0, 0);
+
+       f->n_sp = lookup(addname(n), SNORMAL);
+       if (f->n_sp->sclass == SNULL) {
+               f->n_sp->sclass = EXTERN;
+               f->n_sp->stype = INCREF(rt)+(FTN-PTR);
+       }
+       f->n_type = f->n_sp->stype;
+       f = clocal(f);
+       return buildtree(CALL, f, a);
+}
+
+static NODE *
+builtin_unimp(const struct bitable *bt, NODE *a)
+{
+       return binhelp(a, bt->rt, &bt->name[10]);
+}
+
+#if 0
+static NODE *
+builtin_unimp_f(NODE *f, NODE *a, TWORD rt)
+{
+       return binhelp(f, a, rt, f->n_sp->sname);
+}
+#endif
+
+#ifndef TARGET_PREFETCH
+static NODE *
+builtin_prefetch(const struct bitable *bt, NODE *a)
+{
+       tfree(a);
+       return bcon(0);
+}
+#endif
+
+#ifndef TARGET_ISMATH
+/*
+ * Handle the builtin macros for the math functions is*
+ * To get something that is be somewhat generic assume that 
+ * isnan() is a real function and that cast of a NaN type 
+ * to double will still be a NaN.
+ */
+static NODE *
+mtisnan(NODE *p)
+{
+
+       return binhelp(cast(ccopy(p), DOUBLE, 0), INT, "isnan");
+}
+
+static TWORD
+mtcheck(NODE *p)
+{
+       TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type;
+
+       if ((t1 >= FLOAT && t1 <= LDOUBLE) ||
+           (t2 >= FLOAT && t2 <= LDOUBLE))
+               return MAX(t1, t2);
+       return 0;
+}
+
+static NODE *
+builtin_isunordered(const struct bitable *bt, NODE *a)
+{
+       NODE *p;
+
+       if (mtcheck(a) == 0)
+               return bcon(0);
+
+       p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+       tfree(a);
+       return p;
+}
+static NODE *
+builtin_isany(NODE *a, TWORD rt, int cmpt)
+{
+       NODE *p, *q;
+       TWORD t;
+
+       if ((t = mtcheck(a)) == 0)
+               return bcon(0);
+       p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+       p = buildtree(NOT, p, NIL);
+       q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0),
+           cast(ccopy(a->n_right), t, 0));
+       p = buildtree(ANDAND, p, q);
+       tfree(a);
+       return p;
+}
+static NODE *
+builtin_isgreater(const struct bitable *bt, NODE *a)
+{
+       return builtin_isany(a, bt->rt, GT);
+}
+static NODE *
+builtin_isgreaterequal(const struct bitable *bt, NODE *a)
+{
+       return builtin_isany(a, bt->rt, GE);
+}
+static NODE *
+builtin_isless(const struct bitable *bt, NODE *a)
+{
+       return builtin_isany(a, bt->rt, LT);
+}
+static NODE *
+builtin_islessequal(const struct bitable *bt, NODE *a)
+{
+       return builtin_isany(a, bt->rt, LE);
+}
+static NODE *
+builtin_islessgreater(const struct bitable *bt, NODE *a)
+{
+       NODE *p, *q, *r;
+       TWORD t;
+
+       if ((t = mtcheck(a)) == 0)
+               return bcon(0);
+       p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+       p = buildtree(NOT, p, NIL);
+       q = buildtree(GT, cast(ccopy(a->n_left), t, 0),
+           cast(ccopy(a->n_right), t, 0));
+       r = buildtree(LT, cast(ccopy(a->n_left), t, 0),
+           cast(ccopy(a->n_right), t, 0));
+       q = buildtree(OROR, q, r);
+       p = buildtree(ANDAND, p, q);
+       tfree(a);
+       return p;
+}
+#endif
+
+/*
+ * Math-specific builtins that expands to constants.
+ * Versins here is for IEEE FP, vax needs its own versions.
+ */
+#if TARGET_ENDIAN == TARGET_LE
+static const unsigned char vFLOAT[] = { 0, 0, 0x80, 0x7f };
+static const unsigned char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
+#ifdef LDBL_128
+static const unsigned char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
+#else /* LDBL_80 */
+static const unsigned char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
+#endif
+static const unsigned char nFLOAT[] = { 0, 0, 0xc0, 0x7f };
+static const unsigned char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
+#ifdef LDBL_128
+static const unsigned char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f };
+#else /* LDBL_80 */
+static const unsigned char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 };
+#endif
+#else
+static const unsigned char vFLOAT[] = { 0x7f, 0x80, 0, 0 };
+static const unsigned char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
+#ifdef LDBL_128
+static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#else /* LDBL_80 */
+static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+static const unsigned char nFLOAT[] = { 0x7f, 0xc0, 0, 0 };
+static const unsigned char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
+#ifdef LDBL_128
+static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#else /* LDBL_80 */
+static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+#endif
+
+#define VALX(typ,TYP) {                                                \
+       typ d;                                                  \
+       int x;                                                  \
+       NODE *f;                                                \
+       x = MIN(sizeof(n ## TYP), sizeof(d));                   \
+       memcpy(&d, v ## TYP, x);                                \
+       f = block(FCON, NIL, NIL, TYP, NULL, 0);                \
+       f->n_dcon = fltallo();                                  \
+       ((FLT *)f->n_dcon)->fp = d;                             \
+       return f;                                               \
+}
+
+static NODE *
+builtin_huge_valf(const struct bitable *bt, NODE *a) VALX(float,FLOAT)
+static NODE *
+builtin_huge_val(const struct bitable *bt, NODE *a) VALX(double,DOUBLE)
+static NODE *
+builtin_huge_vall(const struct bitable *bt, NODE *a) VALX(long double,LDOUBLE)
+
+#define        builtin_inff    builtin_huge_valf
+#define        builtin_inf     builtin_huge_val
+#define        builtin_infl    builtin_huge_vall
+
+/*
+ * Return NANs, if reasonable.
+ */
+static NODE *
+builtin_nanx(const struct bitable *bt, NODE *a)
+{
+       if (a == NULL || a->n_op == CM) {
+               uerror("%s bad argument", bt->name);
+               a = bcon(0);
+       } else if (a->n_op == STRING && *a->n_name == '\0') {
+               a->n_op = FCON;
+               a->n_type = bt->rt;
+               a->n_dcon = fltallo();
+               memcpy(&FCAST(a->n_dcon)->fp, nLDOUBLE, sizeof(long double));
+       } else
+               a = binhelp(eve(a), bt->rt, &bt->name[10]);
+       return a;
+}
+
+/*
+ * Target defines, to implement target versions of the generic builtins
+ */
+#ifndef TARGET_MEMCMP
+#define        builtin_memcmp builtin_unimp
+#endif
+#ifndef TARGET_MEMCPY
+#define        builtin_memcpy builtin_unimp
+#endif
+#ifndef TARGET_MEMPCPY
+#define        builtin_mempcpy builtin_unimp
+#endif
+#ifndef TARGET_MEMSET
+#define        builtin_memset builtin_unimp
+#endif
+
+/* Reasonable type of size_t */
+#ifndef SIZET
+#if SZINT == SZSHORT
+#define        SIZET UNSIGNED
+#elif SZLONG > SZINT
+#define SIZET ULONG
+#else
+#define SIZET UNSIGNED
+#endif
+#endif
+
+static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT };
+static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT };
+static TWORD allocat[] = { SIZET };
+static TWORD expectt[] = { LONG, LONG };
+static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT };
+static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT };
+static TWORD strchrt[] = { CHAR|PTR, INT };
+static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD nant[] = { CHAR|PTR };
+static TWORD bitt[] = { UNSIGNED };
+static TWORD bitlt[] = { ULONG };
+static TWORD bitllt[] = { ULONGLONG };
+static TWORD abst[] = { INT };
+
+static const struct bitable bitable[] = {
+       { "__builtin___memcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR },
+       { "__builtin___mempcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR },
+       { "__builtin___memmove_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR },
+       { "__builtin___memset_chk", builtin_unimp, 0, 4, memsett, VOID|PTR },
+
+       { "__builtin___strcat_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR },
+       { "__builtin___strcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR },
+       { "__builtin___strncat_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR },
+       { "__builtin___strncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR },
+
+       { "__builtin___printf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___fprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___sprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___snprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vfprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vsprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+       { "__builtin___vsnprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT },
+
+       { "__builtin_alloca", builtin_alloca, 0, 1, allocat, VOID|PTR },
+       { "__builtin_abs", builtin_abs, 0, 1, abst, INT },
+       { "__builtin_clz", builtin_clz, 0, 1, bitt, INT },
+       { "__builtin_clzl", builtin_clzl, 0, 1, bitlt, INT },
+       { "__builtin_clzll", builtin_clzll, 0, 1, bitllt, INT },
+       { "__builtin_ctz", builtin_ctz, 0, 1, bitt, INT },
+       { "__builtin_ctzl", builtin_ctzl, 0, 1, bitlt, INT },
+       { "__builtin_ctzll", builtin_ctzll, 0, 1, bitllt, INT },
+       { "__builtin_ffs", builtin_ffs, 0, 1, bitt, INT },
+       { "__builtin_ffsl", builtin_ffsl, 0, 1, bitlt, INT },
+       { "__builtin_ffsll", builtin_ffsll, 0, 1, bitllt, INT },
+       { "__builtin_popcount", builtin_unimp, 0, 1, bitt, UNSIGNED },
+       { "__builtin_popcountl", builtin_unimp, 0, 1, bitlt, ULONG },
+       { "__builtin_popcountll", builtin_unimp, 0, 1, bitllt, ULONGLONG },
+
+       { "__builtin_constant_p", builtin_constant_p, 0, 1, 0, INT },
+       { "__builtin_expect", builtin_expect, 0, 2, expectt, LONG },
+       { "__builtin_memcmp", builtin_memcmp, 0, 3, memcpyt, INT },
+       { "__builtin_memcpy", builtin_memcpy, 0, 3, memcpyt, VOID|PTR },
+       { "__builtin_mempcpy", builtin_mempcpy, 0, 3, memcpyt, VOID|PTR },
+       { "__builtin_memset", builtin_memset, 0, 3, memsett, VOID|PTR },
+       { "__builtin_huge_valf", builtin_huge_valf, 0, 0, 0, FLOAT },
+       { "__builtin_huge_val", builtin_huge_val, 0, 0, 0, DOUBLE },
+       { "__builtin_huge_vall", builtin_huge_vall, 0, 0, 0, LDOUBLE },
+       { "__builtin_inff", builtin_inff, 0, 0, 0, FLOAT },
+       { "__builtin_inf", builtin_inf, 0, 0, 0, DOUBLE },
+       { "__builtin_infl", builtin_infl, 0, 0, 0, LDOUBLE },
+       { "__builtin_isgreater", builtin_isgreater, 0, 2, NULL, INT },
+       { "__builtin_isgreaterequal", builtin_isgreaterequal, 0, 2, NULL, INT },
+       { "__builtin_isless", builtin_isless, 0, 2, NULL, INT },
+       { "__builtin_islessequal", builtin_islessequal, 0, 2, NULL, INT },
+       { "__builtin_islessgreater", builtin_islessgreater, 0, 2, NULL, INT },
+       { "__builtin_isunordered", builtin_isunordered, 0, 2, NULL, INT },
+       { "__builtin_nanf", builtin_nanx, BTNOEVE, 1, nant, FLOAT },
+       { "__builtin_nan", builtin_nanx, BTNOEVE, 1, nant, DOUBLE },
+       { "__builtin_nanl", builtin_nanx, BTNOEVE, 1, nant, LDOUBLE },
+       { "__builtin_object_size", builtin_object_size, 0, 2, memsett, SIZET },
+       { "__builtin_prefetch", builtin_prefetch, 0, 1, memsett, VOID },
+       { "__builtin_strcmp", builtin_unimp, 0, 2, strcmpt, INT },
+       { "__builtin_strcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR },
+       { "__builtin_stpcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR },
+       { "__builtin_strchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR },
+       { "__builtin_strlen", builtin_unimp, 0, 1, strcmpt, SIZET },
+       { "__builtin_strrchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR },
+       { "__builtin_strncpy", builtin_unimp, 0, 3, strncpyt, CHAR|PTR },
+       { "__builtin_strncat", builtin_unimp, 0, 3, strncpyt, CHAR|PTR },
+       { "__builtin_strcspn", builtin_unimp, 0, 2, strcspnt, SIZET },
+       { "__builtin_strspn", builtin_unimp, 0, 2, strspnt, SIZET },
+       { "__builtin_strstr", builtin_unimp, 0, 2, strcmpt, CHAR|PTR },
+       { "__builtin_strpbrk", builtin_unimp, 0, 2, strpbrkt, CHAR|PTR },
+#ifndef TARGET_STDARGS
+       { "__builtin_stdarg_start", builtin_stdarg_start, 0, 2, 0, VOID },
+       { "__builtin_va_start", builtin_stdarg_start, 0, 2, 0, VOID },
+       { "__builtin_va_arg", builtin_va_arg, BTNORVAL|BTNOPROTO, 2, 0, 0 },
+       { "__builtin_va_end", builtin_va_end, 0, 1, 0, VOID },
+       { "__builtin_va_copy", builtin_va_copy, 0, 2, 0, VOID },
+#endif
+#ifdef TARGET_BUILTINS
+       TARGET_BUILTINS
+#endif
+};
+
+/*
+ * Check and cast arguments for builtins.
+ */
+static int
+acnt(NODE *a, int narg, TWORD *tp)
+{
+       NODE *q;
+       TWORD t;
+
+       if (a == NIL)
+               return narg;
+       for (; a->n_op == CM; a = a->n_left, narg--) {
+               if (tp == NULL)
+                       continue;
+               q = a->n_right;
+               t = ctype(tp[narg-1]);
+               if (q->n_type == t)
+                       continue;
+               a->n_right = ccast(q, t, 0, NULL, 0);
+       }
+
+       /* Last arg is ugly to deal with */
+       if (narg == 1 && tp != NULL && a->n_type != tp[0]) {
+               q = talloc();
+               *q = *a;
+               q = ccast(q, ctype(tp[0]), 0, NULL, 0);
+               *a = *q;
+               nfree(q);
+       }
+       return narg != 1;
+}
+
+NODE *
+builtin_check(struct symtab *sp, NODE *a)
+{
+       const struct bitable *bt;
+
+       if (sp->soffset < 0 ||
+           sp->soffset >= (int)(sizeof(bitable)/sizeof(bitable[0])))
+               cerror("builtin_check");
+
+       bt = &bitable[sp->soffset];
+       if ((bt->flags & BTNOEVE) == 0)
+               a = eve(a);
+       if (((bt->flags & BTNOPROTO) == 0) && acnt(a, bt->narg, bt->tp)) {
+               uerror("wrong argument count to %s", bt->name);
+               return bcon(0);
+       }
+       return (*bt->fun)(bt, a);
+}
+
+/*
+ * Put all builtin functions into the global symbol table.
+ */
+void
+builtin_init()
+{
+       const struct bitable *bt;
+       NODE *p = block(TYPE, 0, 0, 0, 0, 0);
+       struct symtab *sp;
+       int i;
+
+       for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) {
+               bt = &bitable[i];
+               sp = lookup(addname(bt->name), 0);
+               if (bt->rt == 0 && (bt->flags & BTNORVAL) == 0)
+                       cerror("function '%s' has no return type", bt->name);
+               p->n_type = INCREF(bt->rt) + (FTN-PTR);
+               p->n_sp = sp;
+               defid(p, EXTDEF);
+               sp->soffset = i;
+               sp->sflags |= SBUILTIN;
+       }
+       nfree(p);
+}
+#endif
diff --git a/lang/pcc/pcc/cc/cxxcom/cgram.y b/lang/pcc/pcc/cc/cxxcom/cgram.y
new file mode 100644 (file)
index 0000000..9419a61
--- /dev/null
@@ -0,0 +1,2548 @@
+/*     $Id: cgram.y,v 1.9 2015/11/24 17:30:20 ragge Exp $      */
+
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Comments for this grammar file. Ragge 021123
+ *
+ * ANSI support required rewrite of the function header and declaration
+ * rules almost totally.
+ *
+ * The lex/yacc shared keywords are now split from the keywords used
+ * in the rest of the compiler, to simplify use of other frontends.
+ */
+
+/*
+ * At last count, there were 5 shift/reduce and no reduce/reduce conflicts
+ * Four are accounted for;
+ * One is "dangling else"
+ * Two is in attribute parsing
+ * One is in ({ }) parsing
+ */
+
+/*
+ * Token used in C lex/yacc communications.
+ */
+%token C_STRING        /* a string constant */
+%token C_ICON          /* an integer constant */
+%token C_FCON          /* a floating point constant */
+%token C_NAME          /* an identifier */
+%token C_TYPENAME      /* a typedef'd name */
+%token C_ANDAND        /* && */
+%token C_OROR          /* || */
+%token C_GOTO          /* unconditional goto */
+%token C_RETURN        /* return from function */
+%token C_TYPE          /* a type */
+%token C_CLASS         /* a storage class */
+%token C_ASOP          /* assignment ops */
+%token C_RELOP         /* <=, <, >=, > */
+%token C_EQUOP         /* ==, != */
+%token C_DIVOP         /* /, % */
+%token C_SHIFTOP       /* <<, >> */
+%token C_INCOP         /* ++, -- */
+%token C_UNOP          /* !, ~ */
+%token C_STROP         /* ., -> */
+%token C_STRUCT
+%token C_IF
+%token C_ELSE
+%token C_SWITCH
+%token C_BREAK
+%token C_CONTINUE
+%token C_WHILE 
+%token C_DO
+%token C_FOR
+%token C_DEFAULT
+%token C_CASE
+%token C_SIZEOF
+%token C_ALIGNOF
+%token C_ENUM
+%token C_ELLIPSIS
+%token C_QUALIFIER
+%token C_FUNSPEC
+%token C_ASM
+%token NOMATCH
+%token C_TYPEOF        /* COMPAT_GCC */
+%token C_ATTRIBUTE     /* COMPAT_GCC */
+%token PCC_OFFSETOF
+%token GCC_DESIG
+%token CXX_NAMESPACE
+%token CXX_DUALCC
+%token CXX_TEMPLATE
+%token CXX_USING
+%token CXX_TYPENAME
+%token CXX_CASTS
+%token CXX_THROW
+%token CXX_MORENM
+%token CXX_NEW
+%token CXX_DELETE
+%token CXX_CLASS
+
+/*
+ * Precedence
+ */
+%left ','
+%right '=' C_ASOP
+%right '?' ':'
+%left C_OROR
+%left C_ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left C_EQUOP
+%left C_RELOP
+%left C_SHIFTOP
+%left '+' '-'
+%left '*' C_DIVOP
+%right C_UNOP
+%right C_INCOP C_SIZEOF
+%left '[' '(' C_STROP
+%{
+# include "pass1.h"
+# include <stdarg.h>
+# include <string.h>
+# include <stdlib.h>
+
+int fun_inline;        /* Reading an inline function */
+int oldstyle;  /* Current function being defined */
+static struct symtab *xnf;
+extern int enummer, tvaloff, inattr;
+extern struct rstack *rpole;
+static int widestr, alwinl;
+NODE *cftnod;
+static int attrwarn = 1;
+
+#define        NORETYP SNOCREAT /* no return type, save in unused field in symtab */
+
+       NODE *bdty(int op, ...);
+static void fend(struct symtab *);
+static struct symtab *fundef(NODE *tp, NODE *p);
+static void olddecl(NODE *p, NODE *a);
+static struct symtab *init_declarator(NODE *tn, NODE *p, int assign, NODE *a);
+static void resetbc(int mask);
+static void swend(void);
+static void addcase(NODE *p);
+#ifdef GCC_COMPAT
+static void gcccase(NODE *p, NODE *);
+#endif
+static struct attr *gcc_attr_wrapper(NODE *p);
+static void adddef(void);
+static void savebc(void);
+static void swstart(int, TWORD);
+static void genswitch(int, TWORD, struct swents **, int);
+static char *mkpstr(char *str);
+static struct symtab *clbrace(NODE *);
+static NODE *cmop(NODE *l, NODE *r);
+static NODE *xcmop(NODE *out, NODE *in, NODE *str);
+static void mkxasm(char *str, NODE *p);
+static NODE *xasmop(char *str, NODE *p);
+static int maxstlen(char *str);
+static char *stradd(char *old, char *new);
+static NODE *biop(int op, NODE *l, NODE *r);
+static void flend(void);
+static char * simname(char *s);
+static NODE *tyof(NODE *);     /* COMPAT_GCC */
+static NODE *voidcon(void);    /* COMPAT_GCC */
+static NODE *funargs(NODE *p);
+static void oldargs(NODE *p);
+static void uawarn(NODE *p, char *s);
+static int con_e(NODE *p);
+static void dainit(NODE *d, NODE *a);
+static NODE *tymfix(NODE *p);
+static NODE *namekill(NODE *p, int clr);
+static NODE *aryfix(NODE *p);
+
+#define        TYMFIX(inp) { \
+       NODE *pp = inp; \
+       inp = tymerge(pp->n_left, pp->n_right); \
+       nfree(pp->n_left); nfree(pp); }
+/*
+ * State for saving current switch state (when nested switches).
+ */
+struct savbc {
+       struct savbc *next;
+       int brklab;
+       int contlab;
+       int flostat;
+       int swx;
+} *savbc, *savctx;
+
+%}
+
+%union {
+       int intval;
+       NODE *nodep;
+       struct symtab *symp;
+       struct rstack *rp;
+       char *strp;
+}
+
+       /* define types */
+%start edf
+
+%type <intval> ifelprefix ifprefix whprefix forprefix doprefix switchpart
+               xbegin
+%type <nodep> e .e term enum_dcl struct_dcl cast_type declarator
+               elist type_sq cf_spec merge_attribs
+               parameter_declaration abstract_declarator initializer
+               parameter_type_list parameter_list addrlbl
+               declaration_specifiers designation
+               specifier_qualifier_list merge_specifiers
+               identifier_list arg_param_list type_qualifier_list
+               designator_list designator xasm oplist oper cnstr 
+               typeof attribute attribute_specifier /* COMPAT_GCC */
+               attribute_list attr_spec_list attr_var /* COMPAT_GCC */
+               new_ma new_type_sq new_ds nmrec
+%type <strp>   string C_STRING GCC_DESIG nsname CXX_MORENM
+%type <rp>     str_head
+%type <symp>   xnfdeclarator clbrace enum_head funtype
+
+%type <intval>  C_STRUCT C_RELOP C_DIVOP C_SHIFTOP
+               C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP
+
+%type <nodep>   C_TYPE C_QUALIFIER C_ICON C_FCON C_CLASS
+%type <strp>   C_NAME C_TYPENAME
+%%
+
+edf:             ext_def_list
+               | { ftnend(); }
+               ;
+
+ext_def_list:    ext_def_list external_def
+               | external_def
+               ;
+
+external_def:     funtype kr_args compoundstmt { fend($1); }
+               |  declaration  { blevel = 0; symclear(0); }
+               | namespace
+               | extlink
+               | blockdcl
+               |  ';'
+               |  error { blevel = 0; }
+               ;
+
+funtype:         /* no type given */ declarator {
+                   $$ = fundef(mkty(INT, 0, 0), $1);
+                   cftnsp->sflags |= NORETYP;
+               }
+               | declaration_specifiers declarator { $$ = fundef($1,$2); }
+               ;
+
+kr_args:         /* empty */
+               | arg_dcl_list
+               ;
+
+blockdcl:        simple_decl
+               | asmstatement
+               | ns_alias
+               | using_x
+               ;
+
+using_x:         CXX_USING tnopt ccopt nested_name_sp ';' { werror("using"); }
+               | CXX_USING CXX_NAMESPACE ccopt nested_name_sp ';' { werror("using2"); }
+               ;
+
+tnopt:           CXX_TYPENAME { }
+               | { }
+               ;
+
+ns_alias:        CXX_NAMESPACE C_NAME '=' qual_ns_sp ';' { werror("ns_alias");}
+               ;
+
+qual_ns_sp:      ccopt nested_name_sp
+               ;
+
+nested_name_sp:   nmtnm
+               | nmtnm CXX_DUALCC nested_name_sp
+               | nmtnm CXX_DUALCC CXX_TEMPLATE nested_name_sp
+               ;
+
+nmtnm:           C_NAME
+               | C_TYPENAME
+               ;
+
+ccopt:           CXX_DUALCC
+               | { }
+               ;
+
+simple_decl:     ')' NOMATCH { uerror("simple-declaration"); }
+               ;
+
+namespace:       CXX_NAMESPACE nsname attr_var nsbeg ns_body '}' { POPSYM(); }
+               ;
+
+nsname:                  C_NAME
+               | { $$ = NULL; }
+               ;
+ns_body:         ext_def_list
+               | { }
+               ;
+
+nsbeg:           '{' { dclns($<nodep>0, $<strp>-1); }
+               ;
+
+extlink:         C_CLASS C_STRING eb '{' ext_def_list '}' { elnk = LINK_DEF; }
+               | C_CLASS C_STRING eb '{' '}' { elnk = LINK_DEF; }
+               | C_CLASS C_STRING eb declaration { elnk = LINK_DEF; }
+               ;
+
+eb:              {
+                       NODE *p = $<nodep>-1;
+                       char *s = $<strp>0;
+                       if (p->n_type != EXTERN)
+                               uerror("'extern' expected");
+                       if (strcmp(s, "\"C\"") != 0 && strcmp(s, "\"c\""))
+                               uerror("unknown linkage %s", s);
+                       nfree(p);
+                       elnk = LINK_C;
+               }
+               ;
+/*
+ * Returns a node pointer or NULL, if no types at all given.
+ * Type trees are checked for correctness and merged into one
+ * type node in typenode().
+ */
+declaration_specifiers:
+                  merge_attribs { $$ = typenode($1); }
+               ;
+
+merge_attribs:    type_sq { $$ = $1; }
+               |  type_sq merge_attribs { $$ = cmop($2, $1); }
+               |  cf_spec { $$ = $1; }
+               |  cf_spec merge_attribs { $$ = cmop($2, $1); }
+               ;
+
+type_sq:          C_TYPE { $$ = $1; }
+               |  C_TYPENAME { 
+                       struct symtab *sp = lookup($1, 0);
+                       if (sp->stype == ENUMTY) {
+                               sp->stype = strmemb(sp->sap)->stype;
+                       }
+                       $$ = mkty(sp->stype, sp->sdf, sp->sap);
+                       $$->n_sp = sp;
+               }
+               |  struct_dcl { $$ = $1; }
+               |  enum_dcl { $$ = $1; }
+               |  C_QUALIFIER { $$ = $1; }
+               |  attribute_specifier { $$ = biop(ATTRIB, $1, 0); }
+               |  typeof { $$ = $1; }
+               ;
+
+cf_spec:          C_CLASS { $$ = $1; }
+               |  C_FUNSPEC { fun_inline = 1;  /* XXX - hack */
+                       $$ = block(QUALIFIER, NIL, NIL, 0, 0, 0); }
+               ;
+
+typeof:                   C_TYPEOF '(' e ')' { $$ = tyof(eve($3)); }
+               |  C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); }
+               ;
+
+new_ma:                   new_type_sq
+               |  new_type_sq new_ma { $$ = cmop($2, $1); }
+               |  cf_spec { $$ = $1; }
+               |  cf_spec new_ma { $$ = cmop($2, $1); }
+               ;
+
+new_ds:                   new_ma { $$ = typenode($1); }
+               ;
+
+new_type_sq:      C_TYPE { $$ = $1; }
+               |  C_TYPENAME { 
+                       struct symtab *sp = lookup($1, 0);
+                       if (sp->stype == ENUMTY) {
+                               sp->stype = strmemb(sp->sap)->stype;
+                       }
+                       $$ = mkty(sp->stype, sp->sdf, sp->sap);
+                       $$->n_sp = sp;
+               }
+               |  struct_dcl { $$ = $1; }
+               |  enum_dcl { $$ = $1; }
+               |  C_QUALIFIER { $$ = $1; }
+               ;
+
+attribute_specifier :
+                  C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; }
+ /*COMPAT_GCC*/        ;
+
+attribute_list:           attribute
+               |  attribute ',' attribute_list { $$ = cmop($3, $1); }
+               ;
+
+attribute:        {
+#ifdef GCC_COMPAT
+                        $$ = voidcon();
+#endif
+               }
+               |  C_NAME { $$ = bdty(NAME, $1); }
+               |  C_NAME '(' elist ')' {
+                       $$ = bdty($3 == NIL ? UCALL : CALL, bdty(NAME, $1), $3);
+               }
+               ;
+
+/*
+ * Adds a pointer list to front of the declarators.
+ */
+declarator:       '*' declarator { $$ = bdty(UMUL, $2); }
+               |  '*' type_qualifier_list declarator {
+                       $$ = $2;
+                       $$->n_left = $3;
+               }
+               |  nmrec C_NAME { $$ = biop(NMLIST, $1, bdty(NAME, $2)); }
+               |  C_NAME { $$ = bdty(NAME, $1); }
+               |  '(' attr_spec_list declarator ')' {
+                       $$ = $3;
+                       $$->n_ap = attr_add($$->n_ap, gcc_attr_wrapper($2));
+               }
+               |  '(' declarator ')' { $$ = $2; }
+               |  declarator '[' e ']' { $$ = biop(LB, $1, $3); }
+               |  declarator '[' C_CLASS e ']' {
+                       if ($3->n_type != STATIC)
+                               uerror("bad class keyword");
+                       tfree($3); /* XXX - handle */
+                       $$ = biop(LB, $1, $4);
+               }
+               |  declarator '[' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); }
+               |  declarator '[' '*' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); }
+               |  declarator '(' parameter_type_list ')' {
+                       $$ = bdty(CALL, $1, $3);
+               }
+               |  declarator '(' identifier_list ')' {
+                       $$ = bdty(CALL, $1, $3);
+                       oldstyle = 1;
+               }
+               |  declarator '(' ')' { $$ = bdty(UCALL, $1); }
+               ;
+
+type_qualifier_list:
+                  C_QUALIFIER { $$ = $1; $$->n_op = UMUL; }
+               |  type_qualifier_list C_QUALIFIER {
+                       $$ = $1;
+                       $$->n_qual |= $2->n_qual;
+                       nfree($2);
+               }
+               |  attribute_specifier {
+                       $$ = block(UMUL, NIL, NIL, 0, 0, gcc_attr_wrapper($1));
+               }
+               |  type_qualifier_list attribute_specifier {
+                       $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($2));
+               }
+               ;
+
+identifier_list:   C_NAME { $$ = bdty(NAME, $1); oldargs($$); }
+               |  identifier_list ',' C_NAME {
+                       $$ = cmop($1, bdty(NAME, $3));
+                       oldargs($$->n_right);
+               }
+               ;
+
+/*
+ * Returns as parameter_list, but can add an additional ELLIPSIS node.
+ */
+parameter_type_list:
+                  parameter_list { $$ = $1; }
+               |  parameter_list ',' C_ELLIPSIS {
+                       $$ = cmop($1, biop(ELLIPSIS, NIL, NIL));
+               }
+               ;
+
+/*
+ * Returns a linked lists of nodes of op CM with parameters on
+ * its right and additional CM nodes of its left pointer.
+ * No CM nodes if only one parameter.
+ */
+parameter_list:           parameter_declaration { $$ = $1; }
+               |  parameter_declaration '&' { $$ = $1; }
+               |  parameter_list ',' parameter_declaration {
+                       $$ = cmop($1, $3);
+               }
+               ;
+
+/*
+ * Returns a node pointer to the declaration.
+ */
+parameter_declaration:
+                  declaration_specifiers declarator attr_var {
+                       if (glval($1) != SNULL && glval($1) != REGISTER)
+                               uerror("illegal parameter class");
+                       $$ = block(TYMERGE, $1, $2, INT, 0, gcc_attr_wrapper($3));
+               }
+               |  declaration_specifiers abstract_declarator { 
+                       $$ = block(TYMERGE, $1, $2, INT, 0, 0);
+               }
+               |  declaration_specifiers {
+                       $$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0);
+               }
+               ;
+
+abstract_declarator:
+                  '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); }
+               |  '*' type_qualifier_list {
+                       $$ = $2;
+                       $$->n_left = bdty(NAME, NULL);
+               }
+               |  '*' abstract_declarator { $$ = bdty(UMUL, $2); }
+               |  '*' type_qualifier_list abstract_declarator {
+                       $$ = $2;
+                       $$->n_left = $3;
+               }
+               |  '(' abstract_declarator ')' { $$ = $2; }
+               |  '[' ']' attr_var {
+                       $$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET),
+                           INT, 0, gcc_attr_wrapper($3));
+               }
+               |  '[' e ']' attr_var {
+                       $$ = block(LB, bdty(NAME, NULL), $2,
+                           INT, 0, gcc_attr_wrapper($4));
+               }
+               |  abstract_declarator '[' ']' attr_var {
+                       $$ = block(LB, $1, bcon(NOOFFSET),
+                           INT, 0, gcc_attr_wrapper($4));
+               }
+               |  abstract_declarator '[' e ']' attr_var {
+                       $$ = block(LB, $1, $3, INT, 0, gcc_attr_wrapper($5));
+               }
+               |  '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); }
+               |  '(' ib2 parameter_type_list ')' {
+                       $$ = bdty(CALL, bdty(NAME, NULL), $3);
+               }
+               |  abstract_declarator '(' ')' {
+                       $$ = bdty(UCALL, $1);
+               }
+               |  abstract_declarator '(' ib2 parameter_type_list ')' {
+                       $$ = bdty(CALL, $1, $4);
+               }
+               ;
+
+ib2:             { }
+               ;
+/*
+ * K&R arg declaration, between ) and {
+ */
+arg_dcl_list:     arg_declaration
+               |  arg_dcl_list arg_declaration
+               ;
+
+
+arg_declaration:   declaration_specifiers arg_param_list ';' {
+                       nfree($1);
+               }
+               ;
+
+arg_param_list:           declarator attr_var {
+                       olddecl(block(TYMERGE, ccopy($<nodep>0), $1,
+                           INT, 0, 0), $2);
+               }
+               |  arg_param_list ',' declarator attr_var {
+                       olddecl(block(TYMERGE, ccopy($<nodep>0), $3,
+                           INT, 0, 0), $4);
+               }
+               ;
+
+/*
+ * Declarations in beginning of blocks.
+ */
+block_item_list:   block_item
+               |  block_item_list block_item
+               ;
+
+block_item:       declaration
+               |  statement
+               ;
+
+/*
+ * Here starts the old YACC code.
+ */
+
+/*
+ * Variables are declared in init_declarator.
+ */
+declaration:      declaration_specifiers ';' { tfree($1); fun_inline = 0; }
+               |  declaration_specifiers init_declarator_list ';' {
+                       tfree($1);
+                       fun_inline = 0;
+               }
+               ;
+
+/*
+ * Normal declaration of variables. curtype contains the current type node.
+ * Returns nothing, variables are declared in init_declarator.
+ */
+init_declarator_list:
+                  init_declarator { symclear(blevel); }
+               |  init_declarator_list ',' attr_var { $<nodep>$ = $<nodep>0; } init_declarator {
+                       uawarn($3, "init_declarator");
+                       symclear(blevel);
+               }
+               ;
+
+enum_dcl:         enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); }
+               |  C_ENUM C_NAME {  $$ = enumref($2); }
+               ;
+
+enum_head:        C_ENUM { $$ = enumhd(NULL); }
+               |  C_ENUM C_NAME {  $$ = enumhd($2); }
+               ;
+
+moe_list:         moe
+               |  moe_list ',' moe
+               ;
+
+moe:              C_NAME {  moedef($1); }
+               |  C_TYPENAME {  moedef($1); }
+               |  C_NAME '=' e { enummer = con_e($3); moedef($1); }
+               |  C_TYPENAME '=' e { enummer = con_e($3); moedef($1); }
+               ;
+
+struct_dcl:       str_head '{' struct_dcl_list '}' {
+                       NODE *p;
+
+                       $$ = dclstruct($1);
+                       if (pragma_allpacked) {
+                               p = bdty(CALL, bdty(NAME, "packed"),
+                                   bcon(pragma_allpacked));
+                               $$->n_ap = attr_add($$->n_ap,gcc_attr_wrapper(p)); }
+               }
+               |  C_STRUCT attr_var C_NAME { 
+                       $$ = rstruct($3,$1);
+                       uawarn($2, "struct_dcl");
+               }
+               |  C_STRUCT attr_var nmrec C_NAME { 
+                       $$ = cxxrstruct($1,$2,$3,$4);
+                       uawarn($2, "struct_dcl");
+               }
+ /*COMPAT_GCC*/        |  str_head '{' '}' { $$ = dclstruct($1); }
+               ;
+
+attr_var:         {    
+                       NODE *q, *p;
+
+                       p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"),
+                           bcon(pragma_aligned)) : NIL;
+                       if (pragma_packed) {
+                               q = bdty(NAME, "packed");
+                               p = (p == NIL ? q : cmop(p, q));
+                       }
+                       pragma_aligned = pragma_packed = 0;
+                       $$ = p;
+               }
+ /*COMPAT_GCC*/        |  attr_spec_list
+               ;
+
+attr_spec_list:           attribute_specifier 
+               |  attr_spec_list attribute_specifier { $$ = cmop($1, $2); }
+               ;
+
+str_head:         C_STRUCT attr_var {  $$ = bstruct(NULL, $1, $2);  }
+               |  C_STRUCT attr_var C_NAME {  $$ = bstruct($3, $1, $2);  }
+               ;
+
+struct_dcl_list:   struct_declaration
+               |  struct_dcl_list struct_declaration
+               ;
+
+struct_declaration:
+                  declaration_specifiers struct_declarator_list optsemi {
+                       tfree($1);
+               }
+               |  C_NAME ':' { /* cxxaccess($1); */ }
+               ;
+
+optsemi:          ';' { }
+               |  optsemi ';' { werror("extra ; in struct"); }
+               ;
+
+specifier_qualifier_list:
+                  merge_specifiers { $$ = typenode($1); }
+               ;
+
+merge_specifiers:  type_sq merge_specifiers { $$ = cmop($2, $1); }
+               |  type_sq { $$ = $1; }
+               ;
+
+struct_declarator_list:
+                  struct_declarator { symclear(blevel); }
+               |  struct_declarator_list ',' { $<nodep>$=$<nodep>0; } 
+                       struct_declarator { symclear(blevel); }
+               ;
+
+struct_declarator: declarator attr_var {
+                       NODE *p;
+
+                       $1 = aryfix($1);
+                       p = tymerge($<nodep>0, tymfix($1));
+                       if ($2)
+                               p->n_ap = attr_add(p->n_ap, gcc_attr_wrapper($2));
+                       soumemb(p, (char *)$1->n_sp, glval($<nodep>0));
+                       tfree(p);
+               }
+               |  ':' e {
+                       int ie = con_e($2);
+                       if (fldchk(ie))
+                               ie = 1;
+                       falloc(NULL, ie, $<nodep>0);
+               }
+               |  declarator ':' e {
+                       int ie = con_e($3);
+                       if (fldchk(ie))
+                               ie = 1;
+                       if ($1->n_op == NAME) {
+                               /* XXX - tymfix() may alter $1 */
+                               tymerge($<nodep>0, tymfix($1));
+                               soumemb($1, (char *)$1->n_sp, FIELD | ie);
+                               nfree($1);
+                       } else
+                               uerror("illegal declarator");
+               }
+               |  declarator ':' e attr_spec_list {
+                       int ie = con_e($3);
+                       if (fldchk(ie))
+                               ie = 1;
+                       if ($1->n_op == NAME) {
+                               /* XXX - tymfix() may alter $1 */
+                               tymerge($<nodep>0, tymfix($1));
+                               if ($4)
+                                       $1->n_ap = attr_add($1->n_ap,
+                                           gcc_attr_wrapper($4));
+                               soumemb($1, (char *)$1->n_sp, FIELD | ie);
+                               nfree($1);
+                       } else
+                               uerror("illegal declarator");
+               }
+               | /* unnamed member */ {
+                       NODE *p = $<nodep>0;
+                       char *c = permalloc(10);
+
+                       if (p->n_type != STRTY && p->n_type != UNIONTY)
+                               uerror("bad unnamed member type");
+                       snprintf(c, 10, "*%dFAKE", getlab());
+                       soumemb(p, c, 0);
+               }
+               ;
+
+               /* always preceeded by attributes */
+xnfdeclarator:    declarator attr_var {
+                       $$ = xnf = init_declarator($<nodep>0, $1, 1, $2);
+               }
+               |  declarator C_ASM '(' string ')' {
+                       pragma_renamed = newstring($4, strlen($4));
+                       $$ = xnf = init_declarator($<nodep>0, $1, 1, NULL);
+               }
+               ;
+
+/*
+ * Handles declarations and assignments.
+ * Returns nothing.
+ */
+init_declarator:   declarator attr_var { init_declarator($<nodep>0, $1, 0, $2);}
+               |  declarator C_ASM '(' string ')' attr_var {
+#ifdef GCC_COMPAT
+                       pragma_renamed = newstring($4, strlen($4));
+                       init_declarator($<nodep>0, $1, 0, $6);
+#else
+                       werror("gcc extension");
+                       init_declarator($<nodep>0, $1, 0, $6);
+#endif
+               }
+               |  xnfdeclarator '=' e { 
+                       if ($1->sclass == STATIC || $1->sclass == EXTDEF)
+                               statinit++;
+                       simpleinit($1, eve($3));
+                       if ($1->sclass == STATIC || $1->sclass == EXTDEF)
+                               statinit--;
+                       xnf = NULL;
+               }
+               |  xnfdeclarator '=' begbr init_list optcomma '}' {
+                       endinit(0);
+                       xnf = NULL;
+               }
+ /*COMPAT_GCC*/        |  xnfdeclarator '=' begbr '}' { endinit(0); xnf = NULL; }
+               |  xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; }
+               ;
+
+begbr:            '{' { beginit($<symp>-1); }
+               ;
+
+initializer:      e %prec ',' {  $$ = eve($1); }
+               |  addrlbl {  $$ = $1; }
+               |  ibrace init_list optcomma '}' { $$ = NULL; }
+               |  ibrace '}' { asginit(bcon(0)); $$ = NULL; }
+               ;
+
+init_list:        designation initializer { dainit($1, $2); }
+               |  init_list ','  designation initializer { dainit($3, $4); }
+               ;
+
+designation:      designator_list '=' { desinit($1); $$ = NIL; }
+               |  GCC_DESIG { desinit(bdty(NAME, $1)); $$ = NIL; }
+               |  '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); }
+               |  { $$ = NIL; }
+               ;
+
+designator_list:   designator { $$ = $1; }
+               |  designator_list designator { $$ = $2; $$->n_left = $1; }
+               ;
+
+designator:       '[' e ']' {
+                       int ie = con_e($2);
+                       if (ie < 0) {
+                               uerror("designator must be non-negative");
+                               ie = 0;
+                       }
+                       $$ = biop(LB, NIL, bcon(ie));
+               }
+               |  C_STROP C_TYPENAME {
+                       if ($1 != DOT)
+                               uerror("invalid designator");
+                       $$ = bdty(NAME, $2);
+               }
+               |  C_STROP C_NAME {
+                       if ($1 != DOT)
+                               uerror("invalid designator");
+                       $$ = bdty(NAME, $2);
+               }
+               ;
+
+optcomma       :       /* VOID */
+               |  ','
+               ;
+
+ibrace:                   '{' {  ilbrace(); }
+               ;
+
+/*     STATEMENTS      */
+
+compoundstmt:     begin block_item_list '}' { flend(); }
+               |  begin '}' { flend(); }
+               ;
+
+begin:           '{' {
+                       struct savbc *bc = tmpalloc(sizeof(struct savbc));
+                       if (blevel == 1) {
+#ifdef STABS
+                               if (gflag)
+                                       stabs_line(lineno);
+#endif
+                               dclargs();
+                       }
+#ifdef STABS
+                       if (gflag && blevel > 1)
+                               stabs_lbrac(blevel+1);
+#endif
+                       ++blevel;
+                       oldstyle = 0;
+                       bc->contlab = autooff;
+                       bc->next = savctx;
+                       savctx = bc;
+                       if (!isinlining && sspflag && blevel == 2)
+                               sspstart();
+               }
+               ;
+
+statement:        e ';' { /* fwalk($1, eprint, 0); */ ecomp(eve($1)); symclear(blevel); }
+               |  compoundstmt
+               |  ifprefix statement { plabel($1); reached = 1; }
+               |  ifelprefix statement {
+                       if ($1 != NOLAB) {
+                               plabel( $1);
+                               reached = 1;
+                       }
+               }
+               |  whprefix statement {
+                       branch(contlab);
+                       plabel( brklab );
+                       if( (flostat&FBRK) || !(flostat&FLOOP))
+                               reached = 1;
+                       else
+                               reached = 0;
+                       resetbc(0);
+               }
+               |  doprefix statement C_WHILE '(' e ')' ';' {
+                       plabel(contlab);
+                       if (flostat & FCONT)
+                               reached = 1;
+                       if (reached)
+                               cbranch(buildtree(NE, eve($5), bcon(0)),
+                                   bcon($1));
+                       else
+                               tfree(eve($5));
+                       plabel( brklab);
+                       reached = 1;
+                       resetbc(0);
+               }
+               |  forprefix .e ')' statement
+                       {  plabel( contlab );
+                           if( flostat&FCONT ) reached = 1;
+                           if( $2 ) ecomp( $2 );
+                           branch($1);
+                           plabel( brklab );
+                           if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1;
+                           else reached = 0;
+                           resetbc(0);
+                           symclear(blevel); /* if declaration inside for() */
+                           }
+               | switchpart statement
+                       { if( reached ) branch( brklab );
+                           plabel( $1 );
+                           swend();
+                           plabel( brklab);
+                           if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1;
+                           resetbc(FCONT);
+                           }
+               |  C_BREAK  ';' {
+                       if (brklab == NOLAB)
+                               uerror("illegal break");
+                       else if (reached)
+                               branch(brklab);
+                       flostat |= FBRK;
+                       reached = 0;
+               }
+               |  C_CONTINUE  ';' {
+                       if (contlab == NOLAB)
+                               uerror("illegal continue");
+                       else
+                               branch(contlab);
+                       flostat |= FCONT;
+                       goto rch;
+               }
+               |  C_RETURN  ';' {
+                       branch(retlab);
+                       if (cftnsp->stype != VOID && 
+                           (cftnsp->sflags & NORETYP) == 0 &&
+                           cftnsp->stype != VOID+FTN)
+                               uerror("return value required");
+                       rch:
+                       if (!reached)
+                               warner(Wunreachable_code);
+                       reached = 0;
+               }
+               |  C_RETURN e  ';' {
+                       NODE *p, *q;
+
+                       p = nametree(cftnsp);
+                       p->n_type = DECREF(p->n_type);
+                       q = eve($2);
+#ifndef NO_COMPLEX
+                       if (ANYCX(q) || ANYCX(p))
+                               q = cxret(q, p);
+#endif
+                       p = buildtree(RETURN, p, q);
+                       if (p->n_type == VOID) {
+                               ecomp(p->n_right);
+                       } else {
+                               if (cftnod == NIL)
+                                       cftnod = tempnode(0, p->n_type,
+                                           p->n_df, p->n_ap);
+                               ecomp(buildtree(ASSIGN,
+                                   ccopy(cftnod), p->n_right));
+                       }
+                       tfree(p->n_left);
+                       nfree(p);
+                       branch(retlab);
+                       reached = 0;
+               }
+               |  C_GOTO C_NAME ';' { gotolabel($2); goto rch; }
+               |  C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NIL)); }
+               |  asmstatement ';'
+               |   ';'
+               |  error  ';'
+               |  error '}'
+               |  label statement
+               ;
+
+asmstatement:     C_ASM mvol '(' string ')' { send_passt(IP_ASM, mkpstr($4)); }
+               |  C_ASM mvol '(' string xasm ')' { mkxasm($4, $5); }
+               ;
+
+mvol:             /* empty */
+               |  C_QUALIFIER { nfree($1); }
+               ;
+
+xasm:             ':' oplist { $$ = xcmop($2, NIL, NIL); }
+               |  ':' oplist ':' oplist { $$ = xcmop($2, $4, NIL); }
+               |  ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); }
+               ;
+
+oplist:                   /* nothing */ { $$ = NIL; }
+               |  oper { $$ = $1; }
+               ;
+
+oper:             string '(' e ')' { $$ = xasmop($1, eve($3)); }
+               |  oper ',' string '(' e ')' {
+                       $$ = cmop($1, xasmop($3, eve($5)));
+               }
+               ;
+
+cnstr:            string { $$ = xasmop($1, bcon(0)); }
+               |  cnstr ',' string { $$ = cmop($1, xasmop($3, bcon(0))); }
+                ;
+
+label:            C_NAME ':' attr_var { deflabel($1, $3); reached = 1; }
+               |  C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; }
+               |  C_CASE e ':' { addcase(eve($2)); reached = 1; }
+/* COMPAT_GCC */|  C_CASE e C_ELLIPSIS e ':' {
+#ifdef GCC_COMPAT
+                       gcccase(eve($2), eve($4)); reached = 1;
+#endif
+               }
+               |  C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; }
+               ;
+
+doprefix:      C_DO {
+                       savebc();
+                       brklab = getlab();
+                       contlab = getlab();
+                       plabel(  $$ = getlab());
+                       reached = 1;
+               }
+               ;
+ifprefix:      C_IF '(' e ')' {
+                       cbranch(buildtree(NOT, eve($3), NIL), bcon($$ = getlab()));
+                       reached = 1;
+               }
+               ;
+ifelprefix:      ifprefix statement C_ELSE {
+                       if (reached)
+                               branch($$ = getlab());
+                       else
+                               $$ = NOLAB;
+                       plabel( $1);
+                       reached = 1;
+               }
+               ;
+
+whprefix:        C_WHILE  '('  e  ')' {
+                       savebc();
+                       $3 = eve($3);
+                       if ($3->n_op == ICON && glval($3) != 0)
+                               flostat = FLOOP;
+                       plabel( contlab = getlab());
+                       reached = 1;
+                       brklab = getlab();
+                       if (flostat == FLOOP)
+                               tfree($3);
+                       else
+                               cbranch(buildtree(NOT, $3, NIL), bcon(brklab));
+               }
+               ;
+forprefix:       C_FOR  '('  .e  ';' .e  ';' {
+                       if ($3)
+                               ecomp($3);
+                       savebc();
+                       contlab = getlab();
+                       brklab = getlab();
+                       plabel( $$ = getlab());
+                       reached = 1;
+                       if ($5)
+                               cbranch(buildtree(NOT, $5, NIL), bcon(brklab));
+                       else
+                               flostat |= FLOOP;
+               }
+               |  C_FOR '(' { ++blevel; } declaration .e ';' {
+                       blevel--;
+                       savebc();
+                       contlab = getlab();
+                       brklab = getlab();
+                       plabel( $$ = getlab());
+                       reached = 1;
+                       if ($5)
+                               cbranch(buildtree(NOT, $5, NIL), bcon(brklab));
+                       else
+                               flostat |= FLOOP;
+               }
+               ;
+
+switchpart:       C_SWITCH  '('  e ')' {
+                       NODE *p;
+                       int num;
+                       TWORD t;
+
+                       savebc();
+                       brklab = getlab();
+                       $3 = eve($3);
+                       if (!ISINTEGER($3->n_type)) {
+                               uerror("switch expression must have integer "
+                                      "type");
+                               t = INT;
+                       } else {
+                               $3 = intprom($3);
+                               t = $3->n_type;
+                       }
+                       p = tempnode(0, t, 0, 0);
+                       num = regno(p);
+                       ecomp(buildtree(ASSIGN, p, $3));
+                       branch( $$ = getlab());
+                       swstart(num, t);
+                       reached = 0;
+               }
+               ;
+/*     EXPRESSIONS     */
+.e:               e { $$ = eve($1); }
+               |       { $$=0; }
+               ;
+
+elist:            { $$ = NIL; }
+               |  e %prec ','
+               |  elist  ','  e { $$ = biop(CM, $1, $3); }
+               |  elist  ','  cast_type { /* hack for stdarg */
+                       TYMFIX($3);
+                       $3->n_op = TYPE;
+                       $$ = biop(CM, $1, $3);
+               }
+               ;
+
+/*
+ * Precedence order of operators.
+ */
+e:                e ',' e { $$ = biop(COMOP, $1, $3); }
+               |  e '=' e { $$ = biop(ASSIGN, $1, $3); }
+               |  e C_ASOP e { $$ = biop($2, $1, $3); }
+               |  e '?' e ':' e {
+                       $$=biop(QUEST, $1, biop(COLON, $3, $5));
+               }
+               |  e '?' ':' e { 
+                       NODE *p = tempnode(0, $1->n_type, $1->n_df, $1->n_ap);
+                       $$ = biop(COLON, ccopy(p), $4);
+                       $$=biop(QUEST, biop(ASSIGN, p, $1), $$);
+               }
+               |  e C_OROR e { $$ = biop($2, $1, $3); }
+               |  e C_ANDAND e { $$ = biop($2, $1, $3); }
+               |  e '|' e { $$ = biop(OR, $1, $3); }
+               |  e '^' e { $$ = biop(ER, $1, $3); }
+               |  e '&' e { $$ = biop(AND, $1, $3); }
+               |  e C_EQUOP  e { $$ = biop($2, $1, $3); }
+               |  e C_RELOP e { $$ = biop($2, $1, $3); }
+               |  e C_SHIFTOP e { $$ = biop($2, $1, $3); }
+               |  e '+' e { $$ = biop(PLUS, $1, $3); }
+               |  e '-' e { $$ = biop(MINUS, $1, $3); }
+               |  e C_DIVOP e { $$ = biop($2, $1, $3); }
+               |  e '*' e { $$ = biop(MUL, $1, $3); }
+               |  e '=' addrlbl { $$ = biop(ASSIGN, $1, $3); }
+               |  term
+               ;
+
+xbegin:                   begin {
+                       $$ = getlab(); getlab(); getlab();
+                       branch($$); plabel(($$)+1); }
+               ;
+
+addrlbl:         C_ANDAND C_NAME {
+#ifdef GCC_COMPAT
+                       struct symtab *s = lookup($2, SLBLNAME);
+                       if (s->soffset == 0)
+                               s->soffset = -getlab();
+                       $$ = buildtree(ADDROF, nametree(s), NIL);
+#else
+                       uerror("gcc extension");
+#endif
+               }
+               ;
+
+term:             term C_INCOP {  $$ = biop($2, $1, bcon(1)); }
+               |  '*' term { $$ = biop(UMUL, $2, NIL); }
+               |  '&' term { $$ = biop(ADDROF, $2, NIL); }
+               |  '-' term { $$ = biop(UMINUS, $2, NIL ); }
+               |  '+' term { $$ = biop(PLUS, $2, bcon(0)); }
+               |  CXX_CASTS C_RELOP cast_type C_RELOP '(' e ')' {
+                       tfree($6);
+                       tfree($3);
+                       $$ = bcon(0);
+                       werror("CXX_CASTS unhandled");
+               }
+               |  C_UNOP term { $$ = biop($1, $2, NIL); }
+               |  C_INCOP term {
+                       $$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1));
+               }
+               |  C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $<intval>2; }
+               |  '(' cast_type ')' term  %prec C_INCOP {
+                       TYMFIX($2);
+                       $$ = biop(CAST, $2, $4);
+               }
+               |  C_SIZEOF xa '(' cast_type ')'  %prec C_SIZEOF {
+                       $$ = biop(SZOF, $4, bcon(1));
+                       inattr = $<intval>2;
+               }
+               |  C_ALIGNOF xa '(' cast_type ')' {
+                       int al;
+                       TYMFIX($4);
+                       al = talign($4->n_type, $4->n_ap);
+                       $$ = bcon(al/SZCHAR);
+                       inattr = $<intval>2;
+                       tfree($4);
+               }
+               | '(' cast_type ')' clbrace init_list optcomma '}' {
+                       endinit(0);
+                       $$ = bdty(NAME, $4);
+                       $$->n_op = CLOP;
+               }
+               | '(' cast_type ')' clbrace '}' {
+                       endinit(0);
+                       $$ = bdty(NAME, $4);
+                       $$->n_op = CLOP;
+               }
+               |  term '[' e ']' {
+                       if ($1->n_op == NEWKW) {
+                               $1->n_left = biop(LB, $1->n_left, $3);
+                       } else
+                               $$ = biop(LB, $1, $3);
+               }
+               |  C_NAME  '(' elist ')' {
+#if 0
+                       if ($3) tfree($3);
+                       $$ = bcon(0);
+#else
+                       $$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3);
+#endif
+               }
+               |  term  '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); }
+               |  term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); }
+               |  term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));}
+               |  C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); }
+               |  nmrec C_NAME %prec C_SIZEOF {
+                       $$ = biop(NMLIST, $1, bdty(NAME, $2));
+               }
+               |  PCC_OFFSETOF  '(' cast_type ',' term ')' {
+                       TYMFIX($3);
+                       $3->n_type = INCREF($3->n_type);
+                       $3 = biop(CAST, $3, bcon(0));
+                       if ($5->n_op == NAME) {
+                               $$ = biop(STREF, $3, $5);
+                       } else {
+                               NODE *p = $5;
+                               while (p->n_left->n_op != NAME)
+                                       p = p->n_left;
+                               p->n_left = biop(STREF, $3, p->n_left);
+                               $$ = $5;
+                       }
+                       $$ = biop(ADDROF, $$, NIL);
+                       $3 = block(NAME, NIL, NIL, ENUNSIGN(INTPTR), 0, 0);
+                       $$ = biop(CAST, $3, $$);
+               }
+               |  C_ICON { $$ = $1; }
+               |  C_FCON { $$ = $1; }
+               |  string { $$ = bdty(STRING, $1, widestr); }
+               |   '('  e  ')' { $$=$2; }
+               |  '(' xbegin block_item_list e ';' '}' ')' {
+                       /* XXX - check recursive ({ }) statements */
+                       branch(($2)+2);
+                       plabel($2);
+                       $$ = buildtree(COMOP,
+                           biop(GOTO, bcon(($2)+1), NIL), eve($4));
+                       flend();
+               }
+               |  '(' xbegin block_item_list '}' ')' { 
+                       /* XXX - check recursive ({ }) statements */
+                       branch(($2)+2);
+                       plabel($2);
+                       $$ = buildtree(COMOP,
+                           biop(GOTO, bcon(($2)+1), NIL), voidcon());
+                       flend();
+               }
+               |  CXX_NEW new_ds { $$ = biop(NEWKW, $2, bcon(0)); }
+               |  CXX_NEW '(' cast_type ')' { $$ = 0; uerror("new cast"); }
+               |  CXX_DELETE term %prec '-' {
+                       $$ = biop(DELETE, $2, bcon(NM_DEL));
+               }
+               |  CXX_DELETE '[' ']' term %prec '-' {
+                       $$ = biop(DELETE, $4, bcon(NM_DLA));
+               }
+               ;
+
+nmrec:           CXX_MORENM { $$ = bdty(NAME, $1); }
+               | CXX_MORENM nmrec { $$ = biop(NMLIST, $2, bdty(NAME, $1)); }
+               ;
+
+xa:              { $<intval>$ = inattr; inattr = 0; }
+               ;
+
+clbrace:          '{'  { NODE *q = $<nodep>-1; TYMFIX(q); $$ = clbrace(q); }
+               ;
+
+string:                   C_STRING { widestr = 0; $$ = stradd("", $1); }
+               |  string C_STRING { $$ = stradd($1, $2); }
+               ;
+
+cast_type:        specifier_qualifier_list {
+                       $$ = biop(TYMERGE, $1, bdty(NAME, NULL));
+               }
+               |  specifier_qualifier_list abstract_declarator {
+                       $$ = biop(TYMERGE, $1, aryfix($2));
+               }
+               ;
+
+%%
+
+NODE *
+mkty(TWORD t, union dimfun *d, struct attr *sue)
+{
+       return block(TYPE, NIL, NIL, t, d, sue);
+}
+
+NODE *
+bdty(int op, ...)
+{
+       va_list ap;
+       int val;
+       register NODE *q;
+
+       va_start(ap, op);
+       q = biop(op, NIL, NIL);
+
+       switch (op) {
+       case UMUL:
+       case UCALL:
+               q->n_left = va_arg(ap, NODE *);
+               q->n_rval = 0;
+               break;
+
+       case CALL:
+               q->n_left = va_arg(ap, NODE *);
+               q->n_right = va_arg(ap, NODE *);
+               break;
+
+       case LB:
+               q->n_left = va_arg(ap, NODE *);
+               if ((val = va_arg(ap, int)) <= 0) {
+                       uerror("array size must be positive");
+                       val = 1;
+               }
+               q->n_right = bcon(val);
+               break;
+
+       case NAME:
+               q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */
+               break;
+
+       case STRING:
+               q->n_name = va_arg(ap, char *);
+               val = va_arg(ap, int);
+               slval(q, val);
+               break;
+
+       default:
+               cerror("bad bdty");
+       }
+       va_end(ap);
+
+       return q;
+}
+
+static void
+flend(void)
+{
+       if (!isinlining && sspflag && blevel == 2)
+               sspend();
+#ifdef STABS
+       if (gflag && blevel > 2)
+               stabs_rbrac(blevel);
+#endif
+       --blevel;
+       if( blevel == 1 )
+               blevel = 0;
+       symclear(blevel); /* Clean ut the symbol table */
+       if (autooff > maxautooff)
+               maxautooff = autooff;
+       autooff = savctx->contlab;
+       savctx = savctx->next;
+}
+
+static void
+savebc(void)
+{
+       struct savbc *bc = tmpalloc(sizeof(struct savbc));
+
+       bc->brklab = brklab;
+       bc->contlab = contlab;
+       bc->flostat = flostat;
+       bc->next = savbc;
+       savbc = bc;
+       flostat = 0;
+}
+
+static void
+resetbc(int mask)
+{
+       flostat = savbc->flostat | (flostat&mask);
+       contlab = savbc->contlab;
+       brklab = savbc->brklab;
+       savbc = savbc->next;
+}
+
+struct swdef {
+       struct swdef *next;     /* Next in list */
+       int deflbl;             /* Label for "default" */
+       struct swents *ents;    /* Linked sorted list of case entries */
+       int nents;              /* # of entries in list */
+       int num;                /* Node value will end up in */
+       TWORD type;             /* Type of switch expression */
+} *swpole;
+
+/*
+ * add case to switch
+ */
+static void
+addcase(NODE *p)
+{
+       struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents));
+       CONSZ val;
+
+       p = optim(rmpconv(p));  /* change enum to ints */
+       if (p->n_op != ICON || p->n_sp != NULL) {
+               uerror( "non-constant case expression");
+               return;
+       }
+       if (swpole == NULL) {
+               uerror("case not in switch");
+               return;
+       }
+
+       if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) {
+               val = glval(p);
+               p = makety(p, swpole->type, 0, 0, 0);
+               if (p->n_op != ICON)
+                       cerror("could not cast case value to type of switch "
+                              "expression");
+               if (glval(p) != val)
+                       werror("case expression truncated");
+       }
+       sw->sval = glval(p);
+       tfree(p);
+       put = &swpole->ents;
+       if (ISUNSIGNED(swpole->type)) {
+               for (w = swpole->ents;
+                    w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval;
+                    w = w->next)
+                       put = &w->next;
+       } else {
+               for (w = swpole->ents; w != NULL && w->sval < sw->sval;
+                    w = w->next)
+                       put = &w->next;
+       }
+       if (w != NULL && w->sval == sw->sval) {
+               uerror("duplicate case in switch");
+               return;
+       }
+       plabel(sw->slab = getlab());
+       *put = sw;
+       sw->next = w;
+       swpole->nents++;
+}
+
+#ifdef GCC_COMPAT
+void
+gcccase(NODE *ln, NODE *hn)
+{
+       CONSZ i, l, h;
+
+       l = icons(optim(ln));
+       h = icons(optim(hn));
+
+       if (h < l)
+               i = l, l = h, h = i;
+
+       for (i = l; i <= h; i++)
+               addcase(xbcon(i, NULL, hn->n_type));
+}
+#endif
+
+/*
+ * add default case to switch
+ */
+static void
+adddef(void)
+{
+       if (swpole == NULL)
+               uerror("default not inside switch");
+       else if (swpole->deflbl != 0)
+               uerror("duplicate default in switch");
+       else
+               plabel( swpole->deflbl = getlab());
+}
+
+static void
+swstart(int num, TWORD type)
+{
+       struct swdef *sw = tmpalloc(sizeof(struct swdef));
+
+       sw->deflbl = sw->nents = 0;
+       sw->ents = NULL;
+       sw->next = swpole;
+       sw->num = num;
+       sw->type = type;
+       swpole = sw;
+}
+
+/*
+ * end a switch block
+ */
+static void
+swend(void)
+{
+       struct swents *sw, **swp;
+       int i;
+
+       sw = tmpalloc(sizeof(struct swents));
+       swp = tmpalloc(sizeof(struct swents *) * (swpole->nents+1));
+
+       sw->slab = swpole->deflbl;
+       swp[0] = sw;
+
+       for (i = 1; i <= swpole->nents; i++) {
+               swp[i] = swpole->ents;
+               swpole->ents = swpole->ents->next;
+       }
+       genswitch(swpole->num, swpole->type, swp, swpole->nents);
+
+       swpole = swpole->next;
+}
+
+/*
+ * num: tempnode the value of the switch expression is in
+ * type: type of the switch expression
+ *
+ * p points to an array of structures, each consisting
+ * of a constant value and a label.
+ * The first is >=0 if there is a default label;
+ * its value is the label number
+ * The entries p[1] to p[n] are the nontrivial cases
+ * n is the number of case statements (length of list)
+ */
+static void
+genswitch(int num, TWORD type, struct swents **p, int n)
+{
+       NODE *r, *q;
+       int i;
+
+       if (mygenswitch(num, type, p, n))
+               return;
+
+       /* simple switch code */
+       for (i = 1; i <= n; ++i) {
+               /* already in 1 */
+               r = tempnode(num, type, 0, 0);
+               q = xbcon(p[i]->sval, NULL, type);
+               r = buildtree(NE, r, clocal(q));
+               cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+       }
+       if (p[0]->slab > 0)
+               branch(p[0]->slab);
+}
+
+/*
+ * Declare a variable or prototype.
+ */
+static struct symtab *
+init_declarator(NODE *tn, NODE *p, int assign, NODE *a)
+{
+       int class = glval(tn);
+       struct symtab *sp;
+
+       p = aryfix(p);
+       if (p->n_op == NMLIST) {
+               tymerge(tn, p->n_right);
+       } else
+               p = tymerge(tn, p);
+       if (a) {
+               struct attr *ap = gcc_attr_wrapper(a);
+               p->n_ap = attr_add(p->n_ap, ap);
+       }
+
+       sp = cxxdeclvar(p);
+
+       if (fun_inline && ISFTN(p->n_type))
+               sp->sflags |= SINLINE;
+
+       if (!ISFTN(p->n_type)) {
+               if (assign) {
+                       defid(p, class);
+                       sp = p->n_sp;
+                       sp->sflags |= SASG;
+                       if (sp->sflags & SDYNARRAY)
+                               uerror("can't initialize dynamic arrays");
+                       lcommdel(sp);
+               } else
+                       nidcl(p, class);
+       } else {
+               extern NODE *parlink;
+               if (assign)
+                       uerror("cannot initialise function");
+               defid(p, uclass(class));
+               sp = p->n_sp;
+               if (parlink) {
+                       /* dynamic sized arrays in prototypes */
+                       tfree(parlink); /* Free delayed tree */
+                       parlink = NIL;
+               }
+       }
+       tfree(p);
+       return sp;
+}
+
+/*
+ * Declare old-stype function arguments.
+ */
+static void
+oldargs(NODE *p)
+{
+       blevel++;
+       p->n_op = TYPE;
+       p->n_type = FARG;
+       p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+       defid(p, PARAM);
+       blevel--;
+}
+
+/*
+ * Set NAME nodes to a null name and index of LB nodes to NOOFFSET
+ * unless clr is one, in that case preserve variable name.
+ */
+static NODE *
+namekill(NODE *p, int clr)
+{
+       NODE *q;
+       int o = p->n_op;
+
+       switch (coptype(o)) {
+       case LTYPE:
+               if (o == NAME) {
+                       if (clr)
+                               p->n_sp = NULL;
+                       else
+                               p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+               }
+               break;
+
+       case UTYPE:
+               p->n_left = namekill(p->n_left, clr);
+               break;
+
+        case BITYPE:
+                p->n_left = namekill(p->n_left, clr);
+               if (o == LB) {
+                       if (clr) {
+                               tfree(p->n_right);
+                               p->n_right = bcon(NOOFFSET);
+                       } else
+                               p->n_right = eve(p->n_right);
+               } else if (o == CALL)
+                       p->n_right = namekill(p->n_right, 1);
+               else
+                       p->n_right = namekill(p->n_right, clr);
+               if (o == TYMERGE) {
+                       q = tymerge(p->n_left, p->n_right);
+                       q->n_ap = attr_add(q->n_ap, p->n_ap);
+                       tfree(p->n_left);
+                       nfree(p);
+                       p = q;
+               }
+               break;
+       }
+       return p;
+}
+
+/*
+ * Declare function arguments.
+ */
+static NODE *
+funargs(NODE *p)
+{
+       extern NODE *arrstk[10];
+
+       if (p->n_op == ELLIPSIS)
+               return p;
+
+       p = namekill(p, 0);
+       if (ISFTN(p->n_type))
+               p->n_type = INCREF(p->n_type);
+       if (ISARY(p->n_type)) {
+               p->n_type += (PTR-ARY);
+               if (p->n_df->ddim == -1)
+                       tfree(arrstk[0]), arrstk[0] = NIL;
+               p->n_df++;
+       }
+       if (p->n_type == VOID && p->n_sp->sname == NULL)
+               return p; /* sanitycheck later */
+       else if (p->n_sp->sname == NULL)
+               ; /* uerror("argument missing"); */
+       else
+               defid(p, PARAM);
+       return p;
+}
+
+static NODE *
+listfw(NODE *p, NODE * (*f)(NODE *))
+{
+        if (p->n_op == CM) {
+                p->n_left = listfw(p->n_left, f);
+                p->n_right = (*f)(p->n_right);
+        } else
+                p = (*f)(p);
+       return p;
+}
+
+
+/*
+ * Declare a function.
+ */
+static struct symtab *
+fundef(NODE *tp, NODE *p)
+{
+       extern int prolab;
+       struct symtab *s, *nsthis;
+       NODE *q, *typ;
+       int class = glval(tp), oclass, ctval;
+       char *c;
+
+       /*
+        * We discard all names except for those needed for
+        * parameter declaration. While doing that, also change
+        * non-constant array sizes to unknown.
+        */
+       ctval = tvaloff;
+       for (q = p; coptype(q->n_op) != LTYPE &&
+           q->n_left->n_op != NAME &&
+           q->n_left->n_op != NMLIST; q = q->n_left) {
+               if (q->n_op == CALL)
+                       q->n_right = namekill(q->n_right, 1);
+       }
+       if (q->n_op != CALL && q->n_op != UCALL) {
+               uerror("invalid function definition");
+               p = bdty(UCALL, p);
+       } else if (q->n_op == CALL) {
+               blevel = 1;
+               argoff = ARGINIT;
+               if (oldstyle == 0)
+                       q->n_right = listfw(q->n_right, funargs);
+               ftnarg(q);
+               blevel = 0;
+       }
+
+       if (p->n_op == CALL && p->n_left->n_op == NMLIST) {
+               NODE *r = p->n_left;
+               p->n_left = r->n_right;
+               r->n_right = typ = tymerge(tp, p);
+               p = r;
+       } else
+               typ = tymerge(tp, p);
+
+#ifdef GCC_COMPAT
+       /* gcc seems to discard __builtin_ when declaring functions */
+       if (strncmp("__builtin_", (char *)typ->n_sp, 10) == 0)
+               typ->n_sp = (struct symtab *)((char *)typ->n_sp + 10);
+#endif
+
+       s = cxxftnfind(p, SNORMAL);
+       nsthis = nscur;
+       nscur = s->sdown; /* XXX fun in fun? */
+
+       oclass = s->sclass;
+       if (class == STATIC && oclass == EXTERN)
+               werror("%s was first declared extern, then static", s->sname);
+
+       if (fun_inline) {
+               /* special syntax for inline functions */
+               if (! strcmp(s->sname,"main")) 
+                       uerror("cannot inline main()");
+
+               s->sflags |= SINLINE;
+               inline_start(s);
+               if (class == EXTERN)
+                       class = EXTDEF;
+       } else if (class == EXTERN)
+               class = SNULL; /* same result */
+
+       cftnsp = s;
+#if 0
+       defid(p, class);
+#endif
+
+#ifdef GCC_COMPAT
+       if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) {
+               /* Temporary turn on temps to make always_inline work */
+               alwinl = 1;
+               if (xtemps == 0) alwinl |= 2;
+               xtemps = 1;
+       }
+#endif
+       prolab = getlab();
+       if ((c = cftnsp->soname) == NULL)
+               c = addname(exname(cftnsp->sname));
+       send_passt(IP_PROLOG, -1, c, cftnsp->stype,
+           cftnsp->sclass == EXTDEF, prolab, ctval);
+       blevel++;
+#ifdef STABS
+       if (gflag)
+               stabs_func(s);
+#endif
+       tfree(tp);
+       tfree(p);
+       return nsthis;
+}
+
+static void
+fend(struct symtab *ns)
+{
+       if (blevel)
+               cerror("function level error");
+       ftnend();
+       fun_inline = 0;
+       if (alwinl & 2) xtemps = 0;
+       alwinl = 0;
+       cftnsp = NULL;
+       nscur = ns;
+}
+
+NODE *
+structref(NODE *p, int f, char *name)
+{
+       NODE *r;
+
+       if (f == DOT)
+               p = buildtree(ADDROF, p, NIL);
+       r = biop(NAME, NIL, NIL);
+       r->n_name = name;
+       r = buildtree(STREF, p, r);
+       return r;
+}
+
+static void
+olddecl(NODE *p, NODE *a)
+{
+       struct symtab *s;
+
+       p = namekill(p, 0);
+       s = p->n_sp;
+       if (s->slevel != 1 || s->stype == UNDEF)
+               uerror("parameter '%s' not defined", s->sname);
+       else if (s->stype != FARG)
+               uerror("parameter '%s' redefined", s->sname);
+
+       s->stype = p->n_type;
+       s->sdf = p->n_df;
+       s->sap = p->n_ap;
+       if (ISARY(s->stype)) {
+               s->stype += (PTR-ARY);
+               s->sdf++;
+       } else if (s->stype == FLOAT)
+               s->stype = DOUBLE;
+       if (a)
+               attr_add(s->sap, gcc_attr_wrapper(a));
+       nfree(p);
+}
+
+void
+branch(int lbl)
+{
+       int r = reached++;
+       ecomp(biop(GOTO, bcon(lbl), NIL));
+       reached = r;
+}
+
+/*
+ * Create a printable string based on an encoded string.
+ */
+static char *
+mkpstr(char *str)
+{
+       char *s, *os;
+       int v, l = strlen(str)+3; /* \t + \n + \0 */
+
+       os = s = inlalloc(l);
+       *s++ = '\t';
+       for (; *str; ) {
+               if (*str++ == '\\')
+                       v = esccon(&str);
+               else
+                       v = str[-1];
+               *s++ = v;
+       }
+       *s++ = '\n';
+       *s = 0;
+       return os;
+}
+
+/*
+ * Estimate the max length a string will have in its internal 
+ * representation based on number of \ characters.
+ */
+static int
+maxstlen(char *str)
+{
+       int i;
+
+       for (i = 0; *str; str++, i++)
+               if (*str == '\\' || *str < 32 || *str > 0176)
+                       i += 3;
+       return i;
+}
+
+static char *
+voct(char *d, unsigned int v)
+{
+       v &= (1 << SZCHAR) - 1;
+       *d++ = '\\';
+       *d++ = v/64 + '0'; v &= 077;
+       *d++ = v/8 + '0'; v &= 7;
+       *d++ = v + '0';
+       return d;
+}
+       
+
+/*
+ * Convert a string to internal format.  The resulting string may be no
+ * more than len characters long.
+ */
+static void
+fixstr(char *d, char *s, int len)
+{
+       unsigned int v;
+
+       while (*s) {
+               if (len <= 0)
+                       cerror("fixstr");
+               if (*s == '\\') {
+                       s++;
+                       v = esccon(&s);
+                       d = voct(d, v);
+                       len -= 4;
+               } else if (*s < ' ' || *s > 0176) {
+                       d = voct(d, *s++);
+                       len -= 4;
+               } else
+                       *d++ = *s++, len--;
+       }
+       *d = 0;
+}
+
+/*
+ * Add "raw" string new to cleaned string old.
+ */
+static char *
+stradd(char *old, char *new)
+{
+       char *rv;
+       int len;
+
+       if (*new == 'L' && new[1] == '\"')
+               widestr = 1, new++;
+       if (*new == '\"') {
+               new++;                   /* remove first " */
+               new[strlen(new) - 1] = 0;/* remove last " */
+       }
+       len = strlen(old) + maxstlen(new) + 1;
+       rv = tmpalloc(len);
+       strlcpy(rv, old, len);
+       fixstr(rv + strlen(old), new, maxstlen(new) + 1);
+       return rv;
+}
+
+/*
+ * Fake a symtab entry for compound literals.
+ */
+static struct symtab *
+clbrace(NODE *p)
+{
+       struct symtab *sp;
+
+       sp = getsymtab(simname("cl"), STEMP);
+       sp->stype = p->n_type;
+       sp->squal = p->n_qual;
+       sp->sdf = p->n_df;
+       sp->sap = p->n_ap;
+       tfree(p);
+       if (blevel == 0 && xnf != NULL) {
+               sp->sclass = STATIC;
+               sp->slevel = 2;
+               sp->soffset = getlab();
+       } else {
+               sp->sclass = blevel ? AUTO : STATIC;
+               if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) {
+                       sp->soffset = NOOFFSET;
+                       oalloc(sp, &autooff);
+               }
+       }
+       beginit(sp);
+       return sp;
+}
+
+char *
+simname(char *s)
+{
+       int len = strlen(s) + 10 + 1;
+       char *w = tmpalloc(len);
+
+       snprintf(w, len, "%s%d", s, getlab());
+       return w;
+}
+
+NODE *
+biop(int op, NODE *l, NODE *r)
+{
+       return block(op, l, r, INT, 0, 0);
+}
+
+static NODE *
+cmop(NODE *l, NODE *r)
+{
+       return biop(CM, l, r);
+}
+
+static NODE *
+voidcon(void)
+{
+       return block(ICON, NIL, NIL, STRTY, 0, 0);
+}
+
+/* Support for extended assembler a' la' gcc style follows below */
+
+static NODE *
+xmrg(NODE *out, NODE *in)
+{
+       NODE *p = in;
+
+       if (p->n_op == XARG) {
+               in = cmop(out, p);
+       } else {
+               while (p->n_left->n_op == CM)
+                       p = p->n_left;
+               p->n_left = cmop(out, p->n_left);
+       }
+       return in;
+}
+
+/*
+ * Put together in and out node lists in one list, and balance it with
+ * the constraints on the right side of a CM node.
+ */
+static NODE *
+xcmop(NODE *out, NODE *in, NODE *str)
+{
+       NODE *p, *q;
+
+       if (out) {
+               /* D out-list sanity check */
+               for (p = out; p->n_op == CM; p = p->n_left) {
+                       q = p->n_right;
+                       if (q->n_name[0] != '=' && q->n_name[0] != '+')
+                               uerror("output missing =");
+               }
+               if (p->n_name[0] != '=' && p->n_name[0] != '+')
+                       uerror("output missing =");
+               if (in == NIL)
+                       p = out;
+               else
+                       p = xmrg(out, in);
+       } else if (in) {
+               p = in;
+       } else
+               p = voidcon();
+
+       if (str == NIL)
+               str = voidcon();
+       return cmop(p, str);
+}
+
+/*
+ * Generate a XARG node based on a string and an expression.
+ */
+static NODE *
+xasmop(char *str, NODE *p)
+{
+
+       p = biop(XARG, p, NIL);
+       p->n_name = isinlining ? newstring(str, strlen(str)) : str;
+       return p;
+}
+
+/*
+ * Generate a XASM node based on a string and an expression.
+ */
+static void
+mkxasm(char *str, NODE *p)
+{
+       NODE *q;
+
+       q = biop(XASM, p->n_left, p->n_right);
+       q->n_name = isinlining ? newstring(str, strlen(str)) : str;
+       nfree(p);
+       ecomp(q);
+}
+
+static struct attr *
+gcc_attr_wrapper(NODE *p)
+{
+#ifdef GCC_COMPAT
+       return gcc_attr_parse(p);
+#else
+       uerror("gcc attribute used");
+       return NULL;
+#endif
+}
+
+
+#ifdef GCC_COMPAT
+static NODE *
+tyof(NODE *p)
+{
+       static struct symtab spp;
+       NODE *q = block(TYPE, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+       q->n_qual = p->n_qual;
+       q->n_sp = &spp; /* for typenode */
+       tfree(p);
+       return q;
+}
+#else
+static NODE *
+tyof(NODE *p)
+{
+       uerror("typeof gcc extension");
+       return bcon(0);
+}
+#endif
+
+/*
+ * Rewrite ++/-- to (t=p, p++, t) ops on types that do not act act as usual.
+ */
+static NODE *
+rewincop(NODE *p1, NODE *p2, int op)
+{
+       NODE *t, *r;
+
+       t = cstknode(p1->n_type, 0, 0);
+       r = buildtree(ASSIGN, ccopy(t), ccopy(p1));
+       r = buildtree(COMOP, r, buildtree(op, p1, eve(p2)));
+       return buildtree(COMOP, r, t);
+}
+
+/*
+ * Traverse an unhandled expression tree bottom-up and call buildtree()
+ * or equivalent as needed.
+ */
+NODE *
+eve(NODE *p)
+{
+       struct symtab *sp;
+       NODE *r, *p1, *p2;
+       int x;
+
+       p1 = p->n_left;
+       p2 = p->n_right;
+       switch (p->n_op) {
+       case NMLIST:
+       case NAME:
+               sp = cxxlookup(p, SNORMAL|SNOCREAT);
+               if (sp->sflags & SINLINE)
+                       inline_ref(sp);
+               r = nametree(sp);
+               if (sp->sflags & SDYNARRAY)
+                       r = buildtree(UMUL, r, NIL);
+#ifdef GCC_COMPAT
+               if (attr_find(sp->sap, GCC_ATYP_DEPRECATED))
+                       warner(Wdeprecated_declarations, sp->sname);
+#endif
+               break;
+
+       case DOT:
+       case STREF:
+               r = cxxstructref(eve(p1), p->n_op, (char *)p2->n_sp);
+               nfree(p2);
+               break;
+
+       case CAST:
+               p1 = buildtree(CAST, p1, eve(p2));
+               nfree(p1->n_left);
+               r = p1->n_right;
+               nfree(p1);
+               break;
+
+
+       case SZOF:
+               x = xinline; xinline = 0; /* XXX hack */
+               if (glval(p2) == 0)
+                       p1 = eve(p1);
+               else
+                       TYMFIX(p1);
+               nfree(p2);
+               r = doszof(p1);
+               xinline = x;
+               break;
+
+       case LB:
+               p1 = eve(p->n_left);
+               r = buildtree(UMUL, buildtree(PLUS, p1, eve(p2)), NIL);
+               break;
+
+       case COMPL:
+#ifndef NO_COMPLEX
+               p1 = eve(p1);
+               if (ANYCX(p1))
+                       r = cxconj(p1);
+               else
+                       r = buildtree(COMPL, p1, NIL);
+               break;
+#endif
+       case UMINUS:
+       case NOT:
+       case UMUL:
+               r = buildtree(p->n_op, eve(p->n_left), NIL);
+               break;
+
+       case ADDROF:
+               r = eve(p1);
+               if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){
+#ifdef notdef
+                       werror( "& before array or function: ignored" );
+#endif
+               } else
+                       r = buildtree(ADDROF, r, NIL);
+               break;
+
+       case CALL:
+       case UCALL:
+               if (p1->n_op == NAME || p1->n_op == NMLIST) {
+                       sp = cxxlookup(p1, SNORMAL);
+#ifndef NO_C_BUILTINS
+                       if (sp->sflags & SBUILTIN) {
+                               nfree(p1);
+                               r = builtin_check(sp, p2);
+                               break;
+                       }
+#endif
+                       if (sp->stype == UNDEF) {
+                               p1->n_type = FTN|INT;
+                               p1->n_sp = sp;
+                               p1->n_ap = NULL;
+                               defid(p1, EXTERN);
+                       }
+                       nfree(p1);
+#ifdef GCC_COMPAT
+                       if (attr_find(sp->sap, GCC_ATYP_DEPRECATED))
+                               warner(Wdeprecated_declarations, sp->sname);
+#endif
+                       p2 = p->n_op == CALL ? eve(p2) : NIL;
+                       r = doacall(sp, nametree(sp), p2, 0);
+               } else if (p1->n_op == DOT || p1->n_op == STREF) {
+                       /*
+                        * function as member of a struct.
+                        * - check args for correct overloaded function
+                        * - add hidden arg0 as pointer to this struct
+                        */
+
+                       p2 = p->n_op == CALL ? eve(p2) : NIL;
+                       p1->n_left = eve(p1->n_left); /* eval rest */
+                       r = cxxmatchftn(p1, p2);
+                       if (p1->n_op == DOT)
+                               p1->n_left = buildtree(ADDROF, p1->n_left, NIL);
+                       nfree(p1->n_right);
+                       p1 = nfree(p1);
+                       p2 = cxxaddhidden(p2, p1);
+                       r = doacall(NULL, r, p2, 1);
+               } else {
+                       p2 = p->n_op == CALL ? eve(p2) : NIL;
+                       r = doacall(NULL, eve(p1), p2, 0);
+               }
+               break;
+
+#ifndef NO_COMPLEX
+       case XREAL:
+       case XIMAG:
+               p1 = eve(p1);
+               r = cxelem(p->n_op, p1);
+               break;
+#endif
+
+       case MUL:
+       case DIV:
+       case PLUS:
+       case MINUS:
+       case ASSIGN:
+       case EQ:
+       case NE:
+#ifndef NO_COMPLEX
+               p1 = eve(p1);
+               p2 = eve(p2);
+               if (ANYCX(p1) || ANYCX(p2)) {
+                       r = cxop(p->n_op, p1, p2);
+               } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) {
+                       r = imop(p->n_op, p1, p2);
+               } else
+                       r = buildtree(p->n_op, p1, p2);
+               break;
+#endif
+       case MOD:
+       case CM:
+       case GT:
+       case GE:
+       case LT:
+       case LE:
+       case RS:
+       case LS:
+       case RSEQ:
+       case LSEQ:
+       case AND:
+       case OR:
+       case ER:
+       case OROR:
+       case ANDAND:
+       case EREQ:
+       case OREQ:
+       case ANDEQ:
+       case QUEST:
+       case COLON:
+               p1 = eve(p1);
+eve2:          r = buildtree(p->n_op, p1, eve(p2));
+               break;
+
+       case INCR:
+       case DECR:
+               p1 = eve(p1);
+               if (p1->n_type >= FLOAT && p1->n_type <= LDOUBLE) {
+                       /* ++/-- on floats isn't ((d+=1)-1) */
+                       /* rewrite to (t=d,d++,t) */
+                       /* XXX - side effects */
+                       r = rewincop(p1, p2, p->n_op);
+                       break;
+               }
+               if (p1->n_type != BOOL)
+                       goto eve2;
+               /* Hey, fun.  ++ will always be 1, and -- will toggle result */
+               if (p->n_op == INCR) {
+                       /* (t=d,d=1,t) */
+                       r = rewincop(p1, p2, ASSIGN);
+               } else {
+                       /* (t=d,d^=1,t) */
+                       r = rewincop(p1, p2, EREQ);
+               }
+               break;
+
+       case MODEQ:
+       case MINUSEQ:
+       case PLUSEQ:
+       case MULEQ:
+       case DIVEQ:
+               p1 = eve(p1);
+               p2 = eve(p2);
+#ifndef NO_COMPLEX
+               if (ANYCX(p1) || ANYCX(p2)) {
+                       r = cxop(UNASG p->n_op, ccopy(p1), p2);
+                       r = cxop(ASSIGN, p1, r);
+                       break;
+               } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) {
+                       r = imop(UNASG p->n_op, ccopy(p1), p2);
+                       r = cxop(ASSIGN, p1, r);
+                       break;
+               }
+               /* FALLTHROUGH */
+#endif
+               if (p1->n_type == BOOL) {
+                       r = buildtree(UNASG p->n_op, ccopy(p1), p2);
+                       r = buildtree(ASSIGN, p1, r);
+               } else {
+                       r = buildtree(p->n_op, p1, p2);
+               }
+               break;
+
+       case STRING:
+               r = strend(glval(p), p->n_name);
+               break;
+
+       case COMOP:
+               if (p1->n_op == GOTO) {
+                       /* inside ({ }), eve already called */
+                       r = buildtree(p->n_op, p1, p2);
+               } else {
+                       p1 = eve(p1);
+                       r = buildtree(p->n_op, p1, eve(p2));
+               }
+               break;
+
+       case TYPE:
+       case ICON:
+       case FCON:
+       case TEMP:
+               return p;
+
+       case CLOP:
+               r = nametree(p->n_sp);
+               break;
+
+       case DELETE:
+               p1 = eve(p1);
+               r = cxx_delete(p1, glval(p2));
+               nfree(p2);
+               break;
+
+       case NEWKW:
+               r = cxx_new(p1);
+               nfree(p2);
+               break;
+
+       default:
+#ifdef PCC_DEBUG
+               fwalk(p, eprint, 0);
+#endif
+               cerror("eve");
+               r = NIL;
+       }
+       nfree(p);
+       return r;
+}
+
+int
+con_e(NODE *p)
+{
+#ifdef WORD_ADDRESSED
+       return icons(optim(eve(p)));
+#else
+       return icons(optim(rmpconv(eve(p))));
+#endif
+}
+
+void
+uawarn(NODE *p, char *s)
+{
+       if (p == 0)
+               return;
+       if (attrwarn)
+               werror("unhandled %s attribute", s);
+       tfree(p);
+}
+
+static void
+dainit(NODE *d, NODE *a)
+{
+       if (d == NULL) {
+               asginit(a);
+       } else if (d->n_op == CM) {
+               int is = con_e(d->n_left);
+               int ie = con_e(d->n_right);
+               int i;
+
+               nfree(d);
+               if (ie < is)
+                       uerror("negative initializer range");
+               desinit(biop(LB, NIL, bcon(is)));
+               for (i = is; i < ie; i++)
+                       asginit(ccopy(a));
+               asginit(a);
+       } else {
+               cerror("dainit");
+       }
+}
+
+/*
+ * Traverse down and tymerge() where appropriate.
+ */
+static NODE *
+tymfix(NODE *p)
+{
+       NODE *q;
+       int o = coptype(p->n_op);
+
+       switch (o) {
+       case LTYPE:
+               break;
+       case UTYPE:
+               p->n_left = tymfix(p->n_left);
+               break;
+       case BITYPE:
+               p->n_left = tymfix(p->n_left);
+               p->n_right = tymfix(p->n_right);
+               if (p->n_op == TYMERGE) {
+                       q = tymerge(p->n_left, p->n_right);
+                       q->n_ap = attr_add(q->n_ap, p->n_ap);
+                       tfree(p->n_left);
+                       nfree(p);
+                       p = q;
+               }
+               break;
+       }
+       return p;
+}
+
+static NODE *
+aryfix(NODE *p)
+{
+       NODE *q;
+
+       for (q = p; q->n_op != NAME; q = q->n_left) {
+               if (q->n_op == LB) {
+                       q->n_right = optim(rmpconv(eve(q->n_right)));
+                       if ((blevel == 0 || rpole != NULL) &&
+                           !nncon(q->n_right))
+                               uerror("array size not constant"); 
+                       /*
+                        * Checks according to 6.7.5.2 clause 1:
+                        * "...the expression shall have an integer type."
+                        * "If the expression is a constant expression,  
+                        * it shall have a value greater than zero."
+                        */
+                       if (!ISINTEGER(q->n_right->n_type))
+                               werror("array size is not an integer");
+                       else if (q->n_right->n_op == ICON &&
+                           glval(q->n_right) < 0 &&
+                           glval(q->n_right) != NOOFFSET) {
+                                       uerror("array size cannot be negative");
+                                       slval(q->n_right, 1);
+                       }
+               } else if (q->n_op == CALL)
+                       q->n_right = namekill(q->n_right, 1);
+       }
+       return p;
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/cxxcode.c b/lang/pcc/pcc/cc/cxxcom/cxxcode.c
new file mode 100644 (file)
index 0000000..2f998de
--- /dev/null
@@ -0,0 +1,830 @@
+/*     $Id: cxxcode.c,v 1.6 2014/05/03 09:57:57 ragge Exp $    */
+/*
+ * Copyright (c) 2011 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+
+struct symtab spole0 = { 0, 0, 0, 0, 0, 0, 0, "base", "base", };
+struct symtab *spole = &spole0;
+struct symtab *nscur = &spole0;
+int elnk, nsptr;
+
+static struct symtab *sfind(char *n, struct symtab *sp);
+/*
+ * Declare a namespace.
+ */
+void
+dclns(NODE *attr, char *n)
+{
+       struct symtab *sp;
+#ifdef GCC_COMPAT
+       struct attr *ap = gcc_attr_parse(attr);
+#else
+       struct attr *ap = NULL;
+#endif
+
+       if (cppdebug)printf("declaring namespace %s\n", n);
+       n = addname(n);
+
+       sp = sfind(n, nscur->sup);
+       while (sp != NULL) {
+               if (sp->sname == n && sp->sclass == NSPACE)
+                       break;
+               sp = sfind(n, sp->snext);
+       }
+       if (sp == NULL) {
+               /* New namespace */
+               sp = getsymtab(n, 0);
+               sp->sclass = NSPACE;
+               INSSYM(sp);
+       }
+       nscur = sp;
+       if (cppdebug)printf("declaring namespace2 %s\n", nscur->sname);
+       sp->sap = attr_add(sp->sap, ap); /* XXX check attributes */
+}
+
+/*
+ * Generate a call tree to function named n.
+ */
+static NODE *
+callftn(char *n, ...)
+{
+       struct symtab *sp = getsymtab(n, 0);
+       NODE *p, *a, *b;
+       va_list ap;
+
+       sp->stype = (FTN|VOID) | (PTR << TSHIFT);
+       va_start(ap, n);
+
+       a = va_arg(ap, NODE *);
+       if (a != NULL) {
+               do {
+                       b = va_arg(ap, NODE *);
+                       if (b != NULL)
+                               a = buildtree(CM, a, b);
+               } while (b != NULL);
+       }
+       
+       p = doacall(sp, nametree(sp), a, 0);
+       va_end(ap);
+       return p;
+}
+
+/*
+ * Sanitycheck "new" keyword.
+ */
+NODE *
+cxx_new(NODE *p)
+{
+       NODE *q = p;
+       NODE *t1 = bcon(1);
+       int nw = NM_NEW;
+
+       while (p->n_op == LB) {
+               nw = NM_NWA;
+               t1 = buildtree(MUL, t1, eve(p->n_right));
+               p->n_right = bcon(0);
+               p = p->n_left;
+       }
+       if (p->n_op != TYPE)
+               uerror("new used illegally");
+       t1 = buildtree(MUL, t1, 
+           xbcon(tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR));
+       tfree(q);
+       return callftn(decoratename(NULL, nw), t1, NULL);
+}
+
+/*
+ * Handle "delete" keyword.
+ */
+NODE *
+cxx_delete(NODE *p, int del)
+{
+       return callftn(decoratename(NULL, del), p, NULL);
+}
+
+/*
+  <operator-name> ::= nw       # new           
+                 ::= na        # new[]
+                 ::= dl        # delete        
+                 ::= da        # delete[]      
+                 ::= ps        # + (unary)
+                 ::= ng        # - (unary)     
+                 ::= ad        # & (unary)     
+                 ::= de        # * (unary)     
+                 ::= co        # ~             
+                 ::= pl        # +             
+                 ::= mi        # -             
+                 ::= ml        # *             
+                 ::= dv        # /             
+                 ::= rm        # %             
+                 ::= an        # &             
+                 ::= or        # |             
+                 ::= eo        # ^             
+                 ::= aS        # =             
+                 ::= pL        # +=            
+                 ::= mI        # -=            
+                 ::= mL        # *=            
+                 ::= dV        # /=            
+                 ::= rM        # %=            
+                 ::= aN        # &=            
+                 ::= oR        # |=            
+                 ::= eO        # ^=            
+                 ::= ls        # <<            
+                 ::= rs        # >>            
+                 ::= lS        # <<=           
+                 ::= rS        # >>=           
+                 ::= eq        # ==            
+                 ::= ne        # !=            
+                 ::= lt        # <             
+                 ::= gt        # >             
+                 ::= le        # <=            
+                 ::= ge        # >=            
+                 ::= nt        # !             
+                 ::= aa        # &&            
+                 ::= oo        # ||            
+                 ::= pp        # ++ (postfix in <expression> context)
+                 ::= mm        # -- (postfix in <expression> context)           
+                 ::= cm        # ,             
+                 ::= pm        # ->*           
+                 ::= pt        # ->            
+                 ::= cl        # ()            
+                 ::= ix        # []            
+                 ::= qu        # ?             
+                 ::= st        # sizeof (a type)
+                 ::= sz        # sizeof (an expression)
+                  ::= at        # alignof (a type)
+                  ::= az        # alignof (an expression)
+                 ::= cv <type> # (cast)        
+                 ::= v <digit> <source-name>   # vendor extended operator
+*/
+
+/*
+  <builtin-type> ::= v # void
+                ::= w  # wchar_t
+                ::= b  # bool
+                ::= c  # char
+                ::= a  # signed char
+                ::= h  # unsigned char
+                ::= s  # short
+                ::= t  # unsigned short
+                ::= i  # int
+                ::= j  # unsigned int
+                ::= l  # long
+                ::= m  # unsigned long
+                ::= x  # long long, __int64
+                ::= y  # unsigned long long, __int64
+                ::= n  # __int128
+                ::= o  # unsigned __int128
+                ::= f  # float
+                ::= d  # double
+                ::= e  # long double, __float80
+                ::= g  # __float128
+                ::= z  # ellipsis
+                 ::= Dd # IEEE 754r decimal floating point (64 bits)
+                 ::= De # IEEE 754r decimal floating point (128 bits)
+                 ::= Df # IEEE 754r decimal floating point (32 bits)
+                 ::= Dh # IEEE 754r half-precision floating point (16 bits)
+                 ::= Di # char32_t
+                 ::= Ds # char16_t
+                 ::= Da # auto (in dependent new-expressions)
+                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+                ::= u <source-name>    # vendor extended type
+*/
+
+/* matches type numbering in manifest.h */
+static char chmap[] = { 'v', 'b', 'c', 'h', 's', 't', 'i', 'j', 'l', 'm',
+       'x', 'y', 'f', 'd', 'e' };
+
+static int
+typch(int typ)
+{
+       int c = BTYPE(typ);
+       if (c == VOID)
+               c = 0;
+       return chmap[c];
+}
+
+#define        MAXNM   255     /* max length of mangled name */
+static char nmblk[MAXNM];
+static int nmptr, subptr;
+
+/* push character */
+static void
+nmch(int c)
+{
+       if (nmptr >= MAXNM)
+               cerror("Too long mangled name");
+       nmblk[nmptr++] = c;
+}
+
+/* Push length and string */
+static void
+pshsln(char *c)
+{
+       int i, j, ln = strlen(c);
+
+#define cnt(v,n) for (v = 0; ln >= n; v++, ln -= n)
+       cnt(i,100);
+       cnt(j,10);
+       if (i) nmch(i+'0');
+       if (j || i) nmch(j+'0');
+       nmch(ln+'0');
+       for (; *c; c++)
+               nmch(*c);
+}
+
+/* Recurse to push namespace names */
+static void
+recnpsh(struct symtab *sp)
+{
+       if (sp == spole)
+               return;
+       if (sp == sp->sdown)
+               cerror("sp == sp->sdown");
+       if (sp->sdown)
+               recnpsh(sp->sdown);
+       pshsln(sp->sname);
+}
+
+static void
+pshargs(union arglist *al)
+{
+       TWORD t;
+       
+
+       for (; al->type != TNULL; al++) {
+               t = al->type;
+               if (t == TELLIPSIS) {
+                       nmch('z');
+                       continue;
+               }
+               while (t > BTMASK) {
+                       if (ISPTR(t))
+                               nmch('P');
+                       else
+                               uerror("pshargs2: %lx\n", t);
+                       t = DECREF(t);
+               }
+               if (t > LDOUBLE)
+                       uerror("pshargs: %lx\n", t);
+               /* XXX - cannot emit const/volatile */
+               nmch(typch(t));
+       }
+}
+
+/*
+ * Do name mangling of a symbol table entry.
+ * The resulting name is saved in soname.
+ */
+char *
+decoratename(struct symtab *sp, int type)
+{
+       char *n;
+
+#define        QNM(m,s) case m: n = s; break
+       switch (type) {
+       QNM(NM_NEW,"_Znwm");
+       QNM(NM_NWA,"_Znam");
+       QNM(NM_DEL,"_ZdlPv");
+       QNM(NM_DLA,"_ZdaPv");
+       case NM_NORMAL: /* Defined in defid() */
+               break;
+       default:
+               uerror("missed mangling %d\n", type);
+               return "";
+       }
+       if (type != NM_NORMAL)
+               return addname(n);
+
+       /* special non-mangled cases:
+        * "C" linkage
+        * main() function
+        * variables outside namespaces and classes
+        */
+       if (elnk == LINK_C || strcmp(sp->sname, "main") == 0 ||
+           (sp->sdown == spole && !ISFTN(sp->stype))) {
+               n = exname(sp->sname);
+               return addname(n);
+       }
+       /* Compute the mangled name for other symbols */
+       nmptr = 0;
+       subptr = 0;
+       nmch('_'); nmch('Z');
+       if (sp->sdown != NULL) {
+               nmch('N');
+               recnpsh(sp->sdown);
+       }
+       pshsln(sp->sname);
+       if (sp->sdown != NULL)
+               nmch('E');
+       if (ISFTN(sp->stype) && sp->sdf->dfun)
+               pshargs(sp->sdf->dfun);
+       nmch(0);
+       return addname(nmblk);
+}
+
+/*
+ * find a symtab entry in the given link.
+ */
+static struct symtab *
+sfind(char *n, struct symtab *sp)
+{
+       while (sp) {
+       if (cppdebug)printf("sfind: checking %s against %s\n", n, sp->sname);
+               if (sp->sname == n)
+                       return sp;
+               sp = sp->snext;
+       }
+       return NULL;
+}
+
+/* class or namespace? */
+#define        CLORNS(sp) (sp->sclass == STNAME || sp->sclass == CLNAME || \
+       sp->sclass == UNAME || sp->sclass == NSPACE)
+
+/*
+ * find a symtab path entry in the given path.
+ * p is expected to be a link of NMNAMEs.
+ * It is supposed to return a sup value of the last found class.
+ */
+static struct symtab *
+pfind(NODE *p, struct symtab *sp)
+{
+       char *n;
+
+       if (cppdebug)printf("pfind: op %d searching %s\n", p->n_op, p->n_op == NAME ?
+(char *)p->n_sp:(char *)p->n_right->n_sp);
+
+       if (p->n_op == NAME) {
+               n = (char *)p->n_sp;
+               if ((sp = sfind(n, sp)) == NULL)
+                       return NULL;
+       if (cppdebug)printf("pfind: NAME class %d name %s\n", sp->sclass, sp->sname);
+               while (!CLORNS(sp)) {
+                       if ((sp = sfind(n, sp->snext)) == NULL)
+                               return NULL;
+               }
+       if (cppdebug)printf("pfind: FOUND %s\n", sp->sname);
+               sp = sp->sup;
+       } else {
+               n = (char *)p->n_right->n_sp;
+               if ((sp = sfind(n, sp)) == NULL)
+                       return NULL;
+       if (cppdebug)printf("pfind: NMLIST class %d name %s\n", sp->sclass, sp->sname);
+               while (!CLORNS(sp)) {
+                       if ((sp = sfind(n, sp->snext)) == NULL)
+                               return NULL;
+               }
+               sp = pfind(p->n_left, sp->sup);
+       }
+       return sp;
+}
+
+/*
+ * Declare a variable.
+ */
+struct symtab *
+cxxdeclvar(NODE *p)
+{
+       struct symtab *sp;
+
+       if (blevel && p->n_op == NAME) {
+               sp = p->n_sp = lookup((char *)p->n_sp, 0);
+       } else {
+               sp = cxxlookup(p, SNORMAL);
+       }
+       return sp;
+}
+
+/*
+ * class is MOS if variable is member of a CLASS, NORMAL otherwise.
+ * A CLASS as member of a class has symbol type CLASS.
+ */
+char *symclass[] = { "NORMAL", "CLASS", "LABEL", "MOS", "STRING" };
+
+/*
+ * Do a name lookup.  p can be either just a NAME or NMLIST.
+ * The first symbol instance on its level is returned, which may or
+ * may not be correct.
+ * If no symbol is found, return a new symtab entry.
+ * p should be a NAME after this with n_sp filled in accordingly.
+ * It's the responsibility of the declaration routine to add it to 
+ * the symbol table.
+ * nfree() will be called on p after this function.
+ */
+struct symtab *
+cxxlookup(NODE *p, int flags)
+{
+       struct symtab *sp, *ns;
+       int ftyp = flags & SMASK;
+       NODE *q;
+       char *n, *s;
+
+#define SPNAME(p) ((char *)(p->n_op == NAME ? p->n_sp : p->n_right->n_sp))
+#ifdef PCC_DEBUG
+       if (cppdebug){ printf("cxxlookup %s\n", SPNAME(p)); symtree(); }
+#endif
+
+       q = p;
+       if (p->n_op == NAME) {
+               s = (char *)p->n_sp;
+               if (blevel) {
+                       sp = lookup(s, SNOCREAT); /* check if auto var */
+                       if (sp == NULL) {
+                               /* check if in classes */
+                               for (ns = nscur; ns != spole; ns = ns->sdown)
+                                       if ((sp = sfind(s, ns->sup)))
+                                               break;
+                               if (sp == NULL)
+                                       sp = sfind(s, spole->sup);
+                       }
+                       if (sp == NULL)
+                               sp = lookup(s, 0); /* fallback */
+               } else {
+                       ns = nscur;
+                       sp = sfind(s, ns);
+                       while (sp != NULL) {
+                               if ((sp->sflags & SMASK) == ftyp)
+                                       break;
+                               sp = sfind(s, sp->snext);
+                       }
+                       if (sp == NULL) {
+                               sp = getsymtab(s, ftyp);
+                               if ((flags & SNOCREAT) == 0) {
+#ifdef PCC_DEBUG
+       if (cppdebug)printf("cxxlookup: adding %s %s %s at %s\n", symclass[ftyp], s, sp->soname, nscur ? nscur->sname : "base");
+#endif
+                                       INSSYM(sp);
+                                       cxxsetname(sp);
+                               }
+                       }
+               }
+       } else {
+               /* Search through namespaces/classes for it */
+               n = SPNAME(p);
+               ns = pfind(p->n_left, spole->sup);
+               if (ns == NULL) {
+                       uerror("undeclared class in chain");
+                       return getsymtab(n, ftyp);
+               }
+               if ((sp = sfind(n, ns)) == NULL) {
+                       sp = getsymtab(n, ftyp);
+                       if ((flags & SNOCREAT) == 0) {
+                               sp->snext = ns->snext;
+                               ns->snext = sp;
+                       }
+               }
+       }
+       
+       /* make top node a NAME */
+       if (q->n_op != NAME) {
+               tfree(q->n_left);
+               p = q->n_right;
+               *q = *q->n_right;
+               nfree(p);
+       }
+       q->n_sp = sp;
+       return sp;
+}
+
+void
+cxxsetname(struct symtab *sp)
+{
+       if (elnk == LINK_C)
+               return; /* leave to target */
+       sp->soname = decoratename(sp, NM_NORMAL);
+}
+
+/*
+ * Create a symbol out of a struct.
+ * We call the symbol "__%THIS" to avoid interference.
+ */
+struct symtab *
+cxxstrvar(struct symtab *so)
+{
+       struct symtab *sp;
+       NODE *p;
+
+       sp = lookup("__%THIS", 0);
+       p = block(NAME, 0, 0, INCREF(so->stype), so->sdf, so->sap);
+       p->n_sp = sp;
+       defid(p, PARAM);
+       nfree(p);
+       return sp;
+}
+
+/*
+ * Declare a struct (class) based on its name n.
+ * Assumed that nmcur is correctly pointing to either:
+ * - nothing (class at level 0)
+ * - current namespace
+ * - parent class
+ */
+struct symtab *
+cxxdclstr(char *n)
+{
+       struct symtab *sp;
+
+       sp = sfind(n, nscur->sup);
+       while (sp && !CLORNS(sp))
+               sp = sfind(n, sp->snext);
+       if (sp == 0)
+               sp = getsymtab(n, STAGNAME);
+//     else
+//             uerror("class/namespace redefined");
+//     INSSYM(sp);
+//     nscur = sp;
+
+if (cppdebug)printf("declaring2 struct %s %p nscur %s\n", n, sp, nscur->sname);
+       return sp;
+}
+
+#ifdef PCC_DEBUG
+static void
+symwalk(struct symtab *sp, int indent)
+{
+       int i; 
+
+       while (sp) {
+               for (i = 0; i < indent; i++)
+                       printf("  ");
+               printf("%s (%p) %s\n", sp->sname, sp, scnames(sp->sclass));
+               if (sp->sup)
+                       symwalk(sp->sup, indent+1);
+               sp = sp->snext;
+       }
+}
+
+void
+symtree(void)
+{
+       symwalk(spole, 0);
+}
+#endif
+
+/*
+ * Compare a matching prototype for a function.
+ */
+static int
+cxxpcmp(struct symtab *sp, NODE *p)
+{
+       union arglist *a1, *a2;
+       int i;
+
+       if (!ISFTN(sp->stype) || p->n_df == NULL || sp->sdf == NULL)
+               return 0; /* no dimfun */
+       if ((a1 = sp->sdf->dfun) == NULL || (a2 = p->n_df->dfun) == NULL)
+               return 0; /* no argument */
+
+       for (i = 0; ; i++) {
+               if (a1[i].type == TNULL && a2[i].type == TNULL)
+                       return 1; /* equal prototypes */
+               if (a1[i].type != a2[i].type)
+                       return 1; /* unequal prototypes */
+       }
+}
+
+struct ckstr {
+       int rv;
+       union arglist *al;
+};
+
+static void
+cxxckproto(NODE *p, void *arg)
+{
+       struct ckstr *cp = arg;
+
+       if (cp->rv == -1)
+               return;
+
+       if (cp->al[0].type != p->n_type)
+               goto fail;
+       if (BTYPE(cp->al[0].type) > LDOUBLE)
+               uerror("cxxckproto");
+       cp->al++;
+       return;
+fail:
+       cp->rv = -1;
+}
+
+/*
+ * Compare a matching prototype for an argument tree.
+ * Here we can expand to also do inexact matches.
+ * Return 0 if equal, -1 if failed.
+ */
+static int
+cxxptreecmp(struct symtab *sp, NODE *p)
+{
+       struct ckstr ckstr;
+       union arglist *a1;
+
+       if (!ISFTN(sp->stype) || sp->sdf == NULL ||
+           (a1 = sp->sdf->dfun) == NULL)
+               return 0; /* no dimfun */
+
+       if (p == NULL && a1[0].type == TNULL)
+               return 1; /* arg-less */
+
+       ckstr.rv = 0;
+       ckstr.al = a1;
+       flist(p, cxxckproto, &ckstr);
+
+       if (ckstr.al[0].type != TNULL)
+               return -1; /* arg number error */
+       return ckstr.rv;
+}
+
+/*
+ * Search for (and declare) a function.
+ */
+struct symtab *
+cxxftnfind(NODE *p, int flags)
+{
+       struct symtab *sp, *ns;
+       char *s;
+
+       if (p->n_op == NAME) {
+               s = (char *)p->n_sp;
+               /* Search for equally named functions */
+               sp = sfind(s, nscur->sup);
+               while (sp != NULL) {
+                       if (cxxpcmp(sp, p)) {
+                               if (sp->sclass != NSPACE ||
+                                   sp->sclass == EXTDEF) {
+                                       uerror("%s redefined", s);
+                                       return sp;
+                               } else
+                                       break;
+                       }
+                       sp = sfind(s, sp->snext);
+               }
+               if (sp == NULL) {
+                       sp = getsymtab(s, SNORMAL);
+                       sp->stype = p->n_type;
+                       sp->squal = p->n_qual;
+                       sp->sdf = p->n_df;
+                       sp->sap = p->n_ap;
+                       INSSYM(sp);
+                       if (nscur->sclass != NSPACE && nscur != &spole0)
+                               uerror("inside struct");
+               }
+               sp->sclass = EXTDEF;
+               if (sp->soname == 0)
+                       sp->soname = decoratename(sp, NM_NORMAL);
+       } else {
+               /*
+                * declared outside class, tree-style reference
+                * Must have been defined already
+                * This will be an external declaration (not spooled).
+                */
+               s = SPNAME(p);
+               if ((ns = pfind(p->n_left, spole->sup)) == NULL) {
+                       uerror("undeclared class in chain");
+                       goto undecl;
+               }
+               /* Search for an EXTERN or EXTDEF declaration within */
+               /* EXTDEF causes redeclaration. */
+               sp = sfind(s, ns);
+               while (sp != NULL) {
+                       if (sp->sclass == EXTERN || sp->sclass == EXTDEF) {
+                               if (cxxpcmp(sp, p->n_right)) {
+                                       if (sp->sclass == EXTDEF)
+                                               uerror("%s redefined", s);
+                                       break;
+                               }
+                       }
+                       sp = sfind(s, sp->snext);
+               }
+               if (sp == NULL) {
+                       uerror("%s undeclared", s);
+                       goto undecl;
+               }
+               sp->sclass = EXTDEF;
+       }
+       return sp;
+
+undecl:
+       return getsymtab(s, SNORMAL);
+}
+
+/*
+ * Reference to a struct as a :: name.
+ */
+NODE *
+cxxrstruct(int soru, NODE *attr, NODE *t, char *n)
+{
+       struct symtab *ns, *sp;
+
+       ns = pfind(t, spole->sup);
+       if (ns == NULL)
+               goto undecl;
+
+       tfree(t);
+       sp = sfind(n, ns);
+       while (sp != NULL) {
+               if (sp->sclass == soru)
+                       return mkty(sp->stype, 0, sp->sap);
+               sp = sfind(n, sp->snext);
+       }
+undecl:
+       uerror("%s undeclared", n);
+       return mkty(INT, 0, 0);
+}
+
+/*
+ * Search for correct matching function in a struct depending on 
+ * argument list a.  Return a call node for this function.
+ * Do not touch neither f nor a.
+ * return a name tree suitable for a function call.
+ * We know here that f is a struct reference.
+ */
+NODE *
+cxxmatchftn(NODE *f, NODE *a)
+{
+       struct attr *ap;
+       struct symtab *sp;
+       char *n = (char *)f->n_right->n_sp;
+
+       f = f->n_left;
+
+       if ((ap = attr_find(f->n_ap, ATTR_STRUCT)) == NULL) {
+               uerror("undefined class");
+               sp = getsymtab(n, 0);
+       } else
+               sp = ap->amlist;
+       sp = sfind(n, sp);
+       while (sp != NULL) {
+               if (ISFTN(sp->stype) && cxxptreecmp(sp, a) == 0)
+                       break;
+               sp = sfind(n, sp->snext);
+       }
+       if (sp == NULL)
+               uerror("undefined class member");
+       return nametree(sp);
+}
+
+/*
+ * Add hidden argument f first in node list a. Return resulting a.
+ */
+NODE *
+cxxaddhidden(NODE *a, NODE *f)
+{
+       NODE *q;
+
+       if (a == NULL)
+               return f;
+       if (a->n_op != CM)
+               return block(CM, f, a, INT, 0, 0);
+       for (q = a; q->n_left->n_op == CM; q = q->n_left)
+               ;
+       q->n_left = block(CM, f, q->n_left, INT, 0, 0);
+       return a;
+}
+
+/*
+ * Watch out for references to static members.
+ */
+NODE *
+cxxstructref(NODE *p, int f, char *n)
+{
+       struct symtab *sp = strmemb(p->n_ap);
+
+       if (sp == NULL)
+               cerror("ref to unknown struct");
+       sp = sfind(n, sp);
+       while (sp != NULL) {
+               if (!ISFTN(sp->stype)) {
+                       if (sp->sclass == STATIC || sp->sclass == USTATIC) {
+                               tfree(p);
+                               return nametree(sp);
+                       }
+                       break;
+               }
+               sp = sfind(n, sp->snext);
+       }
+       return structref(p, f, n);
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/cxxdefs.h b/lang/pcc/pcc/cc/cxxcom/cxxdefs.h
new file mode 100644 (file)
index 0000000..daca34e
--- /dev/null
@@ -0,0 +1,46 @@
+
+
+enum { NM_NEW, NM_NWA, NM_DEL, NM_DLA, NM_NORMAL, };
+
+enum { LINK_DEF, LINK_C }; /* linkage definitions */
+extern int elnk;
+#define        SCLINK  00020   /* for symtab */
+
+extern int cppdebug;
+
+/* spole is symbol at base, nscur is where we are in the stack. */
+extern struct symtab *spole, *nscur;
+
+/* insert a symbol into this something */
+#define        INSSYM(sp) (sp->snext = nscur->sup, nscur->sup = sp, sp->sdown = nscur)
+#define        POPSYM()   (nscur = nscur->sdown)
+
+/* C++-specific node types */
+#define                CONST_CAST      (MAXOP+35)
+#define                DYN_CAST        (MAXOP+36)
+#define                REINT_CAST      (MAXOP+37)
+#define                STATIC_CAST     (MAXOP+38)
+#define                NEWKW           (MAXOP+39)
+#define                DELETE          (MAXOP+40)
+#define                NMLIST          (MAXOP+41)
+
+/* C++-specific symtab types */
+#define        CLNAME  (MAXSTCL+1)     /* symtab entry is class */
+#define        NSPACE  (MAXSTCL+2)     /* symtab entry is namespace */
+char *decoratename(struct symtab *sp, int type);
+NODE *cxx_new(NODE *p);
+NODE *cxx_delete(NODE *p, int del);
+void dclns(NODE *attr, char *n);
+struct symtab *cxxlookup(NODE *p, int declare);
+void cxxsetname(struct symtab *sp);
+void cxxmember(struct symtab *sp);
+struct symtab *cxxstrvar(struct symtab *so);
+struct symtab *cxxdclstr(char *n);
+struct symtab *cxxftnfind(NODE *p, int flags);
+struct symtab *cxxdeclvar(NODE *p);
+void symtree(void);
+NODE *cxxrstruct(int soru, NODE *attr, NODE *t, char *tag);
+NODE *cxxmatchftn(NODE *, NODE *);
+NODE *cxxaddhidden(NODE *, NODE *);
+NODE *cxxstructref(NODE *p, int f, char *name);
diff --git a/lang/pcc/pcc/cc/cxxcom/gcc_compat.c b/lang/pcc/pcc/cc/cxxcom/gcc_compat.c
new file mode 100644 (file)
index 0000000..7c52831
--- /dev/null
@@ -0,0 +1,573 @@
+/*      $Id: gcc_compat.c,v 1.10 2015/01/05 21:31:01 plunky Exp $     */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Routines to support some of the gcc extensions to C.
+ */
+#ifdef GCC_COMPAT
+
+#include "pass1.h"
+#include "cgram.h"
+
+#include <string.h>
+
+static struct kw {
+       char *name, *ptr;
+       int rv;
+} kw[] = {
+/*
+ * Do NOT change the order of these entries unless you know 
+ * what you're doing!
+ */
+/* 0 */        { "__asm", NULL, C_ASM },
+/* 1 */        { "__signed", NULL, 0 },
+/* 2 */        { "__inline", NULL, C_FUNSPEC },
+/* 3 */        { "__const", NULL, 0 },
+/* 4 */        { "__asm__", NULL, C_ASM },
+/* 5 */        { "__inline__", NULL, C_FUNSPEC },
+/* 6 */        { "__thread", NULL, 0 },
+/* 7 */        { "__FUNCTION__", NULL, 0 },
+/* 8 */        { "__volatile", NULL, 0 },
+/* 9 */        { "__volatile__", NULL, 0 },
+/* 10 */{ "__restrict", NULL, -1 },
+/* 11 */{ "__typeof__", NULL, C_TYPEOF },
+/* 12 */{ "typeof", NULL, C_TYPEOF },
+/* 13 */{ "__extension__", NULL, -1 },
+/* 14 */{ "__signed__", NULL, 0 },
+/* 15 */{ "__attribute__", NULL, 0 },
+/* 16 */{ "__attribute", NULL, 0 },
+/* 17 */{ "__real__", NULL, 0 },
+/* 18 */{ "__imag__", NULL, 0 },
+/* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF },
+/* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 },
+/* 21 */{ "__alignof__", NULL, C_ALIGNOF },
+/* 22 */{ "__typeof", NULL, C_TYPEOF },
+/* 23 */{ "__alignof", NULL, C_ALIGNOF },
+/* 24 */{ "__restrict__", NULL, -1 },
+       { NULL, NULL, 0 },
+};
+
+/* g77 stuff */
+#if SZFLOAT == SZLONG
+#define G77_INTEGER LONG
+#define G77_UINTEGER ULONG
+#elif SZFLOAT == SZINT
+#define G77_INTEGER INT
+#define G77_UINTEGER UNSIGNED
+#else
+#error fix g77 stuff
+#endif
+#if SZFLOAT*2 == SZLONG
+#define G77_LONGINT LONG
+#define G77_ULONGINT ULONG
+#elif SZFLOAT*2 == SZLONGLONG
+#define G77_LONGINT LONGLONG
+#define G77_ULONGINT ULONGLONG
+#else
+#error fix g77 long stuff
+#endif
+
+static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT };
+static char *g77n[] = { "__g77_integer", "__g77_uinteger",
+       "__g77_longint", "__g77_ulongint" };
+
+void
+gcc_init(void)
+{
+       struct kw *kwp;
+       NODE *p;
+       TWORD t;
+       int i;
+
+       for (kwp = kw; kwp->name; kwp++)
+               kwp->ptr = addname(kwp->name);
+
+       for (i = 0; i < 4; i++) {
+               struct symtab *sp;
+               t = ctype(g77t[i]);
+               p = block(NAME, NIL, NIL, t, NULL, 0);
+               sp = lookup(addname(g77n[i]), 0);
+               p->n_sp = sp;
+               defid(p, TYPEDEF);
+               nfree(p);
+       }
+}
+
+#define        TS      "\n#pragma tls\n# %d\n"
+#define        TLLEN   sizeof(TS)+10
+/*
+ * See if a string matches a gcc keyword.
+ */
+int
+gcc_keyword(char *str, NODE **n)
+{
+       extern int inattr, parlvl, parbal;
+       YYSTYPE *yyl = (YYSTYPE *)n; /* XXX should pass yylval */
+       char tlbuf[TLLEN], *tw;
+       struct kw *kwp;
+       int i;
+
+       /* XXX hack, should pass everything in expressions */
+       if (str == kw[21].ptr)
+               return kw[21].rv;
+
+       if (inattr)
+               return 0;
+
+       for (i = 0, kwp = kw; kwp->name; kwp++, i++)
+               if (str == kwp->ptr)
+                       break;
+       if (kwp->name == NULL)
+               return 0;
+       if (kwp->rv)
+               return kwp->rv;
+       switch (i) {
+       case 1:  /* __signed */
+       case 14: /* __signed__ */
+               *n = mkty((TWORD)SIGNED, 0, 0);
+               return C_TYPE;
+       case 3: /* __const */
+               *n = block(QUALIFIER, NIL, NIL, CON, 0, 0);
+               (*n)->n_qual = CON;
+               return C_QUALIFIER;
+       case 6: /* __thread */
+               snprintf(tlbuf, TLLEN, TS, lineno);
+               tw = &tlbuf[strlen(tlbuf)];
+               while (tw > tlbuf)
+                       cunput(*--tw);
+               return -1;
+       case 7: /* __FUNCTION__ */
+       case 20: /* __PRETTY_FUNCTION__ */
+               if (cftnsp == NULL) {
+                       uerror("%s outside function", kwp->name);
+                       yylval.strp = "";
+               } else
+                       yylval.strp = cftnsp->sname; /* XXX - not C99 */
+               return C_STRING;
+       case 8: /* __volatile */
+       case 9: /* __volatile__ */
+               *n = block(QUALIFIER, NIL, NIL, VOL, 0, 0);
+               (*n)->n_qual = VOL;
+               return C_QUALIFIER;
+       case 15: /* __attribute__ */
+       case 16: /* __attribute */
+               inattr = 1;
+               parlvl = parbal;
+               return C_ATTRIBUTE;
+       case 17: /* __real__ */
+               yyl->intval = XREAL;
+               return C_UNOP;
+       case 18: /* __imag__ */
+               yyl->intval = XIMAG;
+               return C_UNOP;
+       }
+       cerror("gcc_keyword");
+       return 0;
+}
+
+#ifndef TARGET_ATTR
+#define        TARGET_ATTR(p, sue)             0
+#endif
+#ifndef        ALMAX
+#define        ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG)
+#endif
+
+/* allowed number of args */
+#define        A_0ARG  0x01
+#define        A_1ARG  0x02
+#define        A_2ARG  0x04
+#define        A_3ARG  0x08
+/* arg # is a name */
+#define        A1_NAME 0x10
+#define        A2_NAME 0x20
+#define        A3_NAME 0x40
+#define        A_MANY  0x80
+/* arg # is "string" */
+#define        A1_STR  0x100
+#define        A2_STR  0x200
+#define        A3_STR  0x400
+
+#ifdef __MSC__
+#define        CS(x)
+#else
+#define CS(x) [x] =
+#endif
+
+struct atax {
+       int typ;
+       char *name;
+} atax[GCC_ATYP_MAX] = {
+       CS(ATTR_NONE)           { 0, NULL },
+       CS(ATTR_COMPLEX)        { 0, NULL },
+       CS(xxxATTR_BASETYP)     { 0, NULL },
+       CS(ATTR_QUALTYP)        { 0, NULL },
+       CS(ATTR_STRUCT)         { 0, NULL },
+       CS(ATTR_ALIGNED)        { A_0ARG|A_1ARG, "aligned" },
+       CS(GCC_ATYP_PACKED)     { A_0ARG|A_1ARG, "packed" },
+       CS(GCC_ATYP_SECTION)    { A_1ARG|A1_STR, "section" },
+       CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" },
+       CS(GCC_ATYP_UNUSED)     { A_0ARG, "unused" },
+       CS(GCC_ATYP_DEPRECATED) { A_0ARG, "deprecated" },
+       CS(GCC_ATYP_MAYALIAS)   { A_0ARG, "may_alias" },
+       CS(GCC_ATYP_MODE)       { A_1ARG|A1_NAME, "mode" },
+       CS(GCC_ATYP_NORETURN)   { A_0ARG, "noreturn" },
+       CS(GCC_ATYP_FORMAT)     { A_3ARG|A1_NAME, "format" },
+       CS(GCC_ATYP_NONNULL)    { A_MANY, "nonnull" },
+       CS(GCC_ATYP_SENTINEL)   { A_0ARG|A_1ARG, "sentinel" },
+       CS(GCC_ATYP_WEAK)       { A_0ARG, "weak" },
+       CS(GCC_ATYP_FORMATARG)  { A_1ARG, "format_arg" },
+       CS(GCC_ATYP_GNU_INLINE) { A_0ARG, "gnu_inline" },
+       CS(GCC_ATYP_MALLOC)     { A_0ARG, "malloc" },
+       CS(GCC_ATYP_NOTHROW)    { A_0ARG, "nothrow" },
+       CS(GCC_ATYP_CONST)      { A_0ARG, "const" },
+       CS(GCC_ATYP_PURE)       { A_0ARG, "pure" },
+       CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" },
+       CS(GCC_ATYP_DESTRUCTOR) { A_0ARG, "destructor" },
+       CS(GCC_ATYP_VISIBILITY) { A_1ARG|A1_STR, "visibility" },
+       CS(GCC_ATYP_STDCALL)    { A_0ARG, "stdcall" },
+       CS(GCC_ATYP_CDECL)      { A_0ARG, "cdecl" },
+       CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" },
+       CS(GCC_ATYP_USED)       { A_0ARG, "used" },
+       CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" },
+       CS(GCC_ATYP_NOINLINE)   { A_0ARG, "noinline" },
+       CS(GCC_ATYP_ALIAS)      { A_1ARG|A1_STR, "alias" },
+       CS(GCC_ATYP_WEAKREF)    { A_0ARG|A_1ARG|A1_STR, "weakref" },
+       CS(GCC_ATYP_ALLOCSZ)    { A_1ARG|A_2ARG, "alloc_size" },
+       CS(GCC_ATYP_ALW_INL)    { A_0ARG, "always_inline" },
+       CS(GCC_ATYP_TLSMODEL)   { A_1ARG|A1_STR, "tls_model" },
+       CS(GCC_ATYP_ALIASWEAK)  { A_1ARG|A1_STR, "aliasweak" },
+       CS(GCC_ATYP_REGPARM)    { A_1ARG, "regparm" },
+       CS(GCC_ATYP_FASTCALL)   { A_0ARG, "fastcall" },
+
+       CS(GCC_ATYP_BOUNDED)    { A_3ARG|A_MANY|A1_NAME, "bounded" },
+};
+
+#if SZPOINT(CHAR) == SZLONGLONG
+#define        GPT     LONGLONG
+#else
+#define        GPT     INT
+#endif
+
+struct atax mods[] = {
+       { 0, NULL },
+       { INT, "SI" },
+       { INT, "word" },
+       { GPT, "pointer" },
+       { CHAR, "byte" },
+       { CHAR, "QI" },
+       { SHORT, "HI" },
+       { LONGLONG, "DI" },
+       { FLOAT, "SF" },
+       { DOUBLE, "DF" },
+       { LDOUBLE, "XF" },
+       { FCOMPLEX, "SC" },
+       { COMPLEX, "DC" },
+       { LCOMPLEX, "XC" },
+#ifdef TARGET_MODS
+       TARGET_MODS
+#endif
+};
+#define        ATSZ    (sizeof(mods)/sizeof(mods[0]))
+
+static int
+amatch(char *s, struct atax *at, int mx)
+{
+       int i, len;
+
+       if (s[0] == '_' && s[1] == '_')
+               s += 2;
+       len = strlen(s);
+       if (len > 2 && s[len-1] == '_' && s[len-2] == '_')
+               len -= 2;
+       for (i = 0; i < mx; i++) {
+               char *t = at[i].name;
+               if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0)
+                       return i;
+       }
+       return 0;
+}
+
+static void
+setaarg(int str, union aarg *aa, NODE *p)
+{
+       if (str) {
+               if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) ||
+                   ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME))
+                       uerror("bad arg to attribute");
+               if (p->n_op == STRING) {
+                       aa->sarg = newstring(p->n_name, strlen(p->n_name));
+               } else
+                       aa->sarg = (char *)p->n_sp;
+               nfree(p);
+       } else
+               aa->iarg = (int)icons(eve(p));
+}
+
+/*
+ * Parse attributes from an argument list.
+ */
+static struct attr *
+gcc_attribs(NODE *p)
+{
+       NODE *q, *r;
+       struct attr *ap;
+       char *name = NULL, *c;
+       int cw, attr, narg, i;
+
+       if (p->n_op == NAME) {
+               name = (char *)p->n_sp;
+       } else if (p->n_op == CALL || p->n_op == UCALL) {
+               name = (char *)p->n_left->n_sp;
+       } else if (p->n_op == ICON && p->n_type == STRTY) {
+               return NULL;
+       } else
+               cerror("bad variable attribute");
+
+       if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) {
+               warner(Wattributes, name);
+               ap = NULL;
+               goto out;
+       }
+       narg = 0;
+       if (p->n_op == CALL)
+               for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left)
+                       narg++;
+
+       cw = atax[attr].typ;
+       if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) {
+               uerror("wrong attribute arg count");
+               return NULL;
+       }
+       ap = attr_new(attr, 3); /* XXX should be narg */
+       q = p->n_right;
+
+       switch (narg) {
+       default:
+               /* XXX */
+               while (narg-- > 3) {
+                       r = q;
+                       q = q->n_left;
+                       tfree(r->n_right);
+                       nfree(r);
+               }
+               /* FALLTHROUGH */
+       case 3:
+               setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right);
+               r = q;
+               q = q->n_left;
+               nfree(r);
+               /* FALLTHROUGH */
+       case 2:
+               setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right);
+               r = q;
+               q = q->n_left;
+               nfree(r);
+               /* FALLTHROUGH */
+       case 1:
+               setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q);
+               p->n_op = UCALL;
+               /* FALLTHROUGH */
+       case 0:
+               break;
+       }
+
+       /* some attributes must be massaged special */
+       switch (attr) {
+       case ATTR_ALIGNED:
+               if (narg == 0)
+                       ap->aa[0].iarg = ALMAX;
+               else
+                       ap->aa[0].iarg *= SZCHAR;
+               break;
+       case GCC_ATYP_PACKED:
+               if (narg == 0)
+                       ap->aa[0].iarg = 1; /* bitwise align */
+               else
+                       ap->aa[0].iarg *= SZCHAR;
+               break;
+
+       case GCC_ATYP_MODE:
+               if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0)
+                       werror("unknown mode arg %s", ap->aa[0].sarg);
+               ap->aa[0].iarg = ctype(mods[i].typ);
+               break;
+
+       case GCC_ATYP_VISIBILITY:
+               c = ap->aa[0].sarg;
+               if (strcmp(c, "default") && strcmp(c, "hidden") &&
+                   strcmp(c, "internal") && strcmp(c, "protected"))
+                       werror("unknown visibility %s", c);
+               break;
+
+       case GCC_ATYP_TLSMODEL:
+               c = ap->aa[0].sarg;
+               if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") &&
+                   strcmp(c, "initial-exec") && strcmp(c, "local-exec"))
+                       werror("unknown tls model %s", c);
+               break;
+
+       default:
+               break;
+       }
+out:
+       return ap;
+}
+
+/*
+ * Extract attributes from a node tree and return attribute entries 
+ * based on its contents.
+ */
+struct attr *
+gcc_attr_parse(NODE *p)
+{
+       struct attr *b, *c;
+
+       if (p == NIL)
+               return NULL;
+
+       if (p->n_op != CM) {
+               b = gcc_attribs(p);
+               tfree(p);
+       } else {
+               b = gcc_attr_parse(p->n_left);
+               c = gcc_attr_parse(p->n_right);
+               nfree(p);
+               b = b ? attr_add(b, c) : c;
+       }
+       return b;
+}
+
+/*
+ * Fixup struct/unions depending on attributes.
+ */
+void
+gcc_tcattrfix(NODE *p)
+{
+       struct symtab *sp;
+       struct attr *ap;
+       int sz, coff, csz, al, oal, mxal;
+
+       if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL)
+               return; /* nothing to fix */
+
+       al = ap->iarg(0);
+       mxal = 0;
+
+       /* Must repack struct */
+       coff = csz = 0;
+       for (sp = strmemb(ap); sp; sp = sp->snext) {
+               oal = talign(sp->stype, sp->sap);
+               if (oal > al)
+                       oal = al;
+               if (mxal < oal)
+                       mxal = oal;
+               if (sp->sclass & FIELD)
+                       sz = sp->sclass&FLDSIZ;
+               else
+                       sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+               sp->soffset = upoff(sz, oal, &coff);
+               if (coff > csz)
+                       csz = coff;
+               if (p->n_type == UNIONTY)
+                       coff = 0;
+       }
+       if (mxal < ALCHAR)
+               mxal = ALCHAR; /* for bitfields */
+       SETOFF(csz, mxal); /* Roundup to whatever */
+
+       ap = attr_find(p->n_ap, ATTR_STRUCT);
+       ap->amsize = csz;
+       ap = attr_find(p->n_ap, ATTR_ALIGNED);
+       ap->iarg(0) = mxal;
+
+}
+
+/*
+ * gcc-specific pragmas.
+ */
+int
+pragmas_gcc(char *t)
+{
+       char u;
+       extern char *pragstore;
+
+       if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) {
+               int warn, err;
+
+               if (strcmp((t = pragtok(NULL)), "ignored") == 0)
+                       warn = 0, err = 0;
+               else if (strcmp(t, "warning") == 0)
+                       warn = 1, err = 0;
+               else if (strcmp(t, "error") == 0)
+                       warn = 1, err = 1;
+               else
+                       return 1;
+
+               if (eat('\"') || eat('-'))
+                       return 1;
+
+               for (t = pragstore; *t && *t != '\"'; t++)
+                       ;
+
+               u = *t;
+               *t = 0;
+               Wset(pragstore + 1, warn, err);
+               *t = u;
+       } else if (strcmp(t, "poison") == 0) {
+               /* currently ignore */;
+       } else if (strcmp(t, "visibility") == 0) {
+               /* currently ignore */;
+       } else if (strcmp(t, "system_header") == 0) {
+               /* currently ignore */;
+       } else
+               werror("gcc pragma unsupported");
+       return 0;
+}
+
+#ifdef PCC_DEBUG
+void
+dump_attr(struct attr *ap)
+{
+       printf("attributes; ");
+       for (; ap; ap = ap->next) {
+               if (ap->atype >= GCC_ATYP_MAX) {
+                       printf("bad type %d, ", ap->atype);
+               } else if (atax[ap->atype].name == 0) {
+                       char *c = ap->atype == ATTR_COMPLEX ? "complex" :
+                           ap->atype == ATTR_STRUCT ? "struct" : "badtype";
+                       printf("%s, ", c);
+               } else {
+                       printf("%s: ", atax[ap->atype].name);
+                       printf("%d %d %d, ", ap->iarg(0),
+                           ap->iarg(1), ap->iarg(2));
+               }
+       }
+       printf("\n");
+}
+#endif
+#endif
diff --git a/lang/pcc/pcc/cc/cxxcom/init.c b/lang/pcc/pcc/cc/cxxcom/init.c
new file mode 100644 (file)
index 0000000..957e70a
--- /dev/null
@@ -0,0 +1,1224 @@
+/*     $Id: init.c,v 1.6 2015/11/24 17:30:20 ragge Exp $       */
+
+/*
+ * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass1.h"
+#include <string.h>
+
+/*
+ * The following machine-dependent routines may be called during
+ * initialization:
+ * 
+ * zbits(OFFSZ, int)   - sets int bits of zero at position OFFSZ.
+ * infld(CONSZ off, int fsz, CONSZ val)
+ *                     - sets the bitfield val starting at off and size fsz.
+ * ninval(CONSZ off, int fsz, NODE *)
+ *                     - prints an integer constant which may have
+ *                       a label associated with it, located at off and
+ *                       size fsz.
+ *
+ * Initialization may be of different kind:
+ * - Initialization at compile-time, all values are constants and laid
+ *   out in memory. Static or extern variables outside functions.
+ * - Initialization at run-time, written to their values as code.
+ *
+ * Currently run-time-initialized variables are only initialized by using
+ * move instructions.  An optimization might be to detect that it is
+ * initialized with constants and therefore copied from readonly memory.
+ */
+
+/*
+ * The base element(s) of an initialized variable is kept in a linked 
+ * list, allocated while initialized.
+ *
+ * When a scalar is found, entries are popped of the instk until it's
+ * possible to find an entry for a new scalar; then onstk() is called 
+ * to get the correct type and size of that scalar.
+ *
+ * If a right brace is found, pop the stack until a matching left brace
+ * were found while filling the elements with zeros.  This left brace is
+ * also marking where the current level is for designated initializations.
+ *
+ * Position entries are increased when traversing back down into the stack.
+ */
+
+/*
+ * Good-to-know entries from symtab:
+ *     soffset - # of bits from beginning of this structure.
+ */
+
+/*
+ * TO FIX:
+ * - Alignment of structs on like i386 char members.
+ */
+
+/*
+ * Struct used in array initialisation.
+ */
+static struct instk {
+       struct  instk *in_prev; /* linked list */
+       struct  symtab *in_lnk; /* member in structure initializations */
+       struct  symtab *in_sym; /* symtab index */
+       union   dimfun *in_df;  /* dimenston of array */
+       TWORD   in_t;           /* type for this level */
+       int     in_n;           /* number of arrays seen so far */
+       int     in_fl;  /* flag which says if this level is controlled by {} */
+} *pstk, pbase;
+
+int doing_init, statinit;
+static struct symtab *csym;
+
+#ifdef PCC_DEBUG
+static void prtstk(struct instk *in);
+#endif
+
+/*
+ * Linked lists for initializations.
+ */
+struct ilist {
+       struct ilist *next;
+       CONSZ off;      /* bit offset of this entry */
+       int fsz;        /* bit size of this entry */
+       NODE *n;        /* node containing this data info */
+};
+
+struct llist {
+       SLIST_ENTRY(llist) next;
+       CONSZ begsz;    /* bit offset of this entry */
+       struct ilist *il;
+};
+static SLIST_HEAD(llh, llist) lpole;
+static CONSZ basesz;
+static int numents; /* # of array entries allocated */
+
+static struct initctx {
+       struct initctx *prev;
+       struct instk *pstk;
+       struct symtab *psym;
+       struct llh lpole;
+       CONSZ basesz;
+       int numents;
+} *inilnk;
+
+static struct ilist *
+getil(struct ilist *next, CONSZ b, int sz, NODE *n)
+{
+       struct ilist *il = tmpalloc(sizeof(struct ilist));
+
+       il->off = b;
+       il->fsz = sz;
+       il->n = n;
+       il->next = next;
+       return il;
+}
+
+/*
+ * Allocate a new struct defining a block of initializers appended to the
+ * end of the llist. Return that entry.
+ */
+static struct llist *
+getll(void)
+{
+       struct llist *ll;
+
+       ll = tmpalloc(sizeof(struct llist));
+       ll->begsz = numents * basesz;
+       ll->il = NULL;
+       SLIST_INSERT_LAST(&lpole, ll, next);
+       numents++;
+       return ll;
+}
+
+/*
+ * Return structure containing off bitnumber.
+ * Allocate more entries, if needed.
+ */
+static struct llist *
+setll(OFFSZ off)
+{
+       struct llist *ll = NULL;
+
+       /* Ensure that we have enough entries */
+       while (off >= basesz * numents)
+                ll = getll();
+
+       if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off)
+               return ll;
+
+       SLIST_FOREACH(ll, &lpole, next)
+               if (ll->begsz <= off && ll->begsz + basesz > off)
+                       break;
+       return ll; /* ``cannot fail'' */
+}
+char *astypnames[] = { 0, 0, "\t.byte", "\t.byte", "\t.short", "\t.short",
+       "\t.word", "\t.word", "\t.long", "\t.long", "\t.quad", "\t.quad",
+       "ERR", "ERR", "ERR",
+};
+
+void
+inval(CONSZ off, int fsz, NODE *p)
+{
+       struct symtab *sp;
+       CONSZ val;
+       TWORD t;
+
+       if (p->n_op != ICON && p->n_op != FCON) {
+               uerror("constant required");
+               return;
+       }
+       if (p->n_type == BOOL) {
+               if ((U_CONSZ)glval(p) > 1)
+                       slval(p, 1);
+               p->n_type = BOOL_TYPE;
+       }
+       if (ninval(off, fsz, p))
+               return; /* dealt with in local.c */
+       t = p->n_type;
+       if (t > BTMASK)
+               t = INTPTR;
+
+       val = (CONSZ)(glval(p) & SZMASK(sztable[t]));
+       if (t <= ULONGLONG) {
+               sp = p->n_sp;
+               printf("%s ",astypnames[t]);
+               if (val || sp == NULL)
+                       printf(CONFMT, val);
+               if (val && sp != NULL)
+                       printf("+");
+               if (sp != NULL) {
+                       if ((sp->sclass == STATIC && sp->slevel > 0)) {
+                               printf(LABFMT, sp->soffset);
+                       } else
+                               printf("%s", sp->soname ?
+                                   sp->soname : exname(sp->sname));
+               }
+               printf("\n");
+       } else
+               cerror("inval: unhandled type %d", (int)t);
+}
+
+#ifndef MYBFINIT
+
+static int inbits;
+static CONSZ xinval;
+/*
+ * Initialize a bitfield.
+ * XXX - use U_CONSZ?
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("infld off " CONFMT ", fsz %d, val " CONFMT " inbits %d\n",
+                   off, fsz, val, inbits);
+#endif
+       val &= SZMASK(fsz);
+#if TARGET_ENDIAN == TARGET_BE
+       while (fsz + inbits >= SZCHAR) {
+               int shsz = SZCHAR-inbits;
+               xinval = (xinval << shsz) | (val >> (fsz - shsz));
+               printf("%s " CONFMT "\n",
+                   astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR)));
+               fsz -= shsz;
+               val &= SZMASK(fsz);
+               xinval = inbits = 0;
+       }
+       if (fsz) {
+               xinval = (xinval << fsz) | val;
+               inbits += fsz;
+       }
+#else
+       while (fsz + inbits >= SZCHAR) {
+               int shsz = SZCHAR-inbits;
+               xinval |= (val << inbits);
+               printf("%s " CONFMT "\n",
+                   astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR)));
+               fsz -= shsz;
+               val >>= shsz;
+               xinval = inbits = 0;
+       }
+       if (fsz) {
+               xinval |= (val << inbits);
+               inbits += fsz;
+       }
+#endif
+}
+
+char *asspace = "\t.space";
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+       int m;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("zbits off " CONFMT ", fsz %d inbits %d\n", off, fsz, inbits);
+#endif
+#if TARGET_ENDIAN == TARGET_BE
+       if ((m = (inbits % SZCHAR))) {
+               m = SZCHAR - m;
+               if (fsz < m) {
+                       inbits += fsz;
+                       xinval <<= fsz;
+                       return;
+               } else {
+                       fsz -= m;
+                       xinval <<= m;
+                       printf("%s " CONFMT "\n", 
+                           astypnames[CHAR], xinval & SZMASK(SZCHAR));
+                       xinval = inbits = 0;
+               }
+       }
+#else
+       if ((m = (inbits % SZCHAR))) {
+               m = SZCHAR - m;
+               if (fsz < m) {
+                       inbits += fsz;
+                       return;
+               } else {
+                       fsz -= m;
+                       printf("%s " CONFMT "\n", 
+                           astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR)));
+                       xinval = inbits = 0;
+               }
+       }
+#endif
+       if (fsz >= SZCHAR) {
+               printf("%s %d\n", asspace, fsz/SZCHAR);
+               fsz -= (fsz/SZCHAR) * SZCHAR;
+       }
+       if (fsz) {
+               xinval = 0;
+               inbits = fsz;
+       }
+}
+#endif
+
+/*
+ * beginning of initialization; allocate space to store initialized data.
+ * remember storage class for writeout in endinit().
+ * p is the newly declarated type.
+ */
+void
+beginit(struct symtab *sp)
+{
+       struct initctx *ict;
+       struct instk *is = &pbase;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass));
+#endif
+
+       if (pstk) {
+#ifdef PCC_DEBUG
+               if (idebug)
+                       printf("beginit: saving ctx pstk %p\n", pstk);
+#endif
+               /* save old context */
+               ict = tmpalloc(sizeof(struct initctx));
+               ict->prev = inilnk;
+               inilnk = ict;
+               ict->pstk = pstk;
+               ict->psym = csym;
+               ict->lpole = lpole;
+               ict->basesz = basesz;
+               ict->numents = numents;
+               is = tmpalloc(sizeof(struct instk));
+       }
+       csym = sp;
+
+       numents = 0; /* no entries in array list */
+       if (ISARY(sp->stype)) {
+               basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap);
+               if (basesz == 0) {
+                       uerror("array has incomplete type");
+                       basesz = SZINT;
+               }
+       } else
+               basesz = tsize(sp->stype, sp->sdf, sp->sap);
+       SLIST_INIT(&lpole);
+
+       /* first element */
+       if (ISSOU(sp->stype)) {
+               is->in_lnk = strmemb(sp->sap);
+       } else
+               is->in_lnk = NULL;
+       is->in_n = 0;
+       is->in_t = sp->stype;
+       is->in_sym = sp;
+       is->in_df = sp->sdf;
+       is->in_fl = 0;
+       is->in_prev = NULL;
+       pstk = is;
+       doing_init++;
+       if (sp->sclass == STATIC || sp->sclass == EXTDEF)
+               statinit++;
+}
+
+/*
+ * Push a new entry on the initializer stack.
+ * The new entry will be "decremented" to the new sub-type of the previous
+ * entry when called.
+ * Popping of entries is done elsewhere.
+ */
+static void
+stkpush(void)
+{
+       struct instk *is;
+       struct symtab *sq, *sp;
+       TWORD t;
+
+       if (pstk == NULL) {
+               sp = csym;
+               t = 0;
+       } else {
+               t = pstk->in_t;
+               sp = pstk->in_sym;
+       }
+
+#ifdef PCC_DEBUG
+       if (idebug) {
+               printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass));
+               tprint(t, 0);
+       }
+#endif
+
+       /*
+        * Figure out what the next initializer will be, and push it on 
+        * the stack.  If this is an array, just decrement type, if it
+        * is a struct or union, extract the next element.
+        */
+       is = tmpalloc(sizeof(struct instk));
+       is->in_fl = 0;
+       is->in_n = 0;
+       if (pstk == NULL) {
+               /* stack empty */
+               is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL;
+               is->in_t = sp->stype;
+               is->in_sym = sp;
+               is->in_df = sp->sdf;
+       } else if (ISSOU(t)) {
+               sq = pstk->in_lnk;
+               if (sq == NULL) {
+                       uerror("excess of initializing elements");
+               } else {
+                       is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL;
+                       is->in_t = sq->stype;
+                       is->in_sym = sq;
+                       is->in_df = sq->sdf;
+               }
+       } else if (ISARY(t)) {
+               is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0;
+               is->in_t = DECREF(t);
+               is->in_sym = sp;
+               if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim &&
+                   pstk->in_n >= pstk->in_df->ddim) {
+                       werror("excess of initializing elements");
+                       pstk->in_n--;
+               }
+               is->in_df = pstk->in_df+1;
+       } else
+               uerror("too many left braces");
+       is->in_prev = pstk;
+       pstk = is;
+
+#ifdef PCC_DEBUG
+       if (idebug) {
+               printf(" newtype ");
+               tprint(is->in_t, 0);
+               printf("\n");
+       }
+#endif
+}
+
+/*
+ * pop down to either next level that can handle a new initializer or
+ * to the next braced level.
+ */
+static void
+stkpop(void)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("stkpop\n");
+#endif
+       for (; pstk; pstk = pstk->in_prev) {
+               if (pstk->in_t == STRTY && pstk->in_lnk != NULL) {
+                       pstk->in_lnk = pstk->in_lnk->snext;
+                       if (pstk->in_lnk != NULL)
+                               break;
+               }
+               if (ISSOU(pstk->in_t) && pstk->in_fl)
+                       break; /* need } */
+               if (ISARY(pstk->in_t)) {
+                       pstk->in_n++;
+                       if (pstk->in_fl)
+                               break;
+                       if (pstk->in_df->ddim == NOOFFSET ||
+                           pstk->in_n < pstk->in_df->ddim)
+                               break; /* ger more elements */
+               }
+       }
+#ifdef PCC_DEBUG
+       if (idebug > 1)
+               prtstk(pstk);
+#endif
+}
+
+/*
+ * Count how many elements an array may consist of.
+ */
+static int
+acalc(struct instk *is, int n)
+{
+       if (is == NULL || !ISARY(is->in_t))
+               return 0;
+       return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n;
+}
+
+/*
+ * Find current bit offset of the top element on the stack from
+ * the beginning of the aggregate.
+ */
+static CONSZ
+findoff(void)
+{
+       struct instk *is;
+       OFFSZ off;
+
+#ifdef PCC_DEBUG
+       if (ISARY(pstk->in_t))
+               cerror("findoff on bad type %x", pstk->in_t);
+#endif
+
+       /*
+        * Offset calculations. If:
+        * - previous type is STRTY, soffset has in-struct offset.
+        * - this type is ARY, offset is ninit*stsize.
+        */
+       for (off = 0, is = pstk; is; is = is->in_prev) {
+               if (is->in_prev && is->in_prev->in_t == STRTY)
+                       off += is->in_sym->soffset;
+               if (ISARY(is->in_t)) {
+                       /* suesize is the basic type, so adjust */
+                       TWORD t = is->in_t;
+                       OFFSZ o;
+                       while (ISARY(t))
+                               t = DECREF(t);
+                       if (ISPTR(t)) {
+                               o = SZPOINT(t); /* XXX use tsize() */
+                       } else {
+                               o = tsize(t, is->in_sym->sdf, is->in_sym->sap);
+                       }
+                       off += o * acalc(is, 1);
+                       while (is->in_prev && ISARY(is->in_prev->in_t)) {
+                               if (is->in_prev->in_prev &&
+                                   is->in_prev->in_prev->in_t == STRTY)
+                                       off += is->in_sym->soffset;
+                               is = is->in_prev;
+                       }
+               }
+       }
+#ifdef PCC_DEBUG
+       if (idebug>1) {
+               printf("findoff: off " CONFMT "\n", off);
+               prtstk(pstk);
+       }
+#endif
+       return off;
+}
+
+/*
+ * Insert the node p with size fsz at position off.
+ * Bit fields are already dealt with, so a node of correct type
+ * with correct alignment and correct bit offset is given.
+ */
+static void
+nsetval(CONSZ off, int fsz, NODE *p)
+{
+       struct llist *ll;
+       struct ilist *il;
+
+       if (idebug>1)
+               printf("setval: off " CONFMT " fsz %d p %p\n", off, fsz, p);
+
+       if (fsz == 0)
+               return;
+
+       ll = setll(off);
+       off -= ll->begsz;
+       if (ll->il == NULL) {
+               ll->il = getil(NULL, off, fsz, p);
+       } else {
+               il = ll->il;
+               if (il->off > off) {
+                       ll->il = getil(ll->il, off, fsz, p);
+               } else {
+                       for (il = ll->il; il->next; il = il->next)
+                               if (il->off <= off && il->next->off > off)
+                                       break;
+                       if (il->off == off) {
+                               /* replace */
+                               nfree(il->n);
+                               il->n = p;
+                       } else
+                               il->next = getil(il->next, off, fsz, p);
+               }
+       }
+}
+
+/*
+ * take care of generating a value for the initializer p
+ * inoff has the current offset (last bit written)
+ * in the current word being generated
+ * Returns the offset.
+ */
+CONSZ
+scalinit(NODE *p)
+{
+       CONSZ woff;
+       NODE *q;
+       int fsz;
+
+#ifdef PCC_DEBUG
+       if (idebug > 2) {
+               printf("scalinit(%p)\n", p);
+               fwalk(p, eprint, 0);
+               prtstk(pstk);
+       }
+#endif
+
+       if (nerrors)
+               return 0;
+
+       p = optim(p);
+
+#ifdef notdef /* leave to the target to decide if useable */
+       if (csym->sclass != AUTO && p->n_op != ICON &&
+           p->n_op != FCON && p->n_op != NAME)
+               cerror("scalinit not leaf");
+#endif
+
+       /* Out of elements? */
+       if (pstk == NULL) {
+               uerror("excess of initializing elements");
+               return 0;
+       }
+
+       /*
+        * Get to the simple type if needed.
+        */
+       while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) {
+               stkpush();
+               /* If we are doing auto struct init */
+               if (ISSOU(pstk->in_t) && ISSOU(p->n_type) &&
+                   suemeq(pstk->in_sym->sap, p->n_ap))
+                       break;
+       }
+
+       if (ISSOU(pstk->in_t) == 0) {
+               /* let buildtree do typechecking (and casting) */
+               q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df,
+                   pstk->in_sym->sap);
+               p = buildtree(ASSIGN, q, p);
+               nfree(p->n_left);
+               q = p->n_right;
+               nfree(p);
+       } else
+               q = p;
+#ifndef WORD_ADDRESSED
+       if (csym->sclass != AUTO)
+               q = rmpconv(optim(rmpconv(q)));
+#endif
+       q = optim(q);
+
+       woff = findoff();
+
+       /* bitfield sizes are special */
+       if (pstk->in_sym->sclass & FIELD)
+               fsz = -(pstk->in_sym->sclass & FLDSIZ);
+       else
+               fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf,
+                   pstk->in_sym->sap);
+
+       nsetval(woff, fsz, q);
+
+       stkpop();
+#ifdef PCC_DEBUG
+       if (idebug > 2) {
+               printf("scalinit e(%p)\n", q);
+       }
+#endif
+       return woff;
+}
+
+/*
+ * Generate code to insert a value into a bitfield.
+ */
+static void
+insbf(OFFSZ off, int fsz, int val)
+{
+       struct symtab sym;
+       NODE *p, *r;
+       TWORD typ;
+
+#ifdef PCC_DEBUG
+       if (idebug > 1)
+               printf("insbf: off " CONFMT " fsz %d val %d\n", off, fsz, val);
+#endif
+
+       if (fsz == 0)
+               return;
+
+       /* small opt: do char instead of bf asg */
+       if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR)
+               typ = CHAR;
+       else
+               typ = INT;
+       /* Fake a struct reference */
+       p = buildtree(ADDROF, nametree(csym), NIL);
+       sym.stype = typ;
+       sym.squal = 0;
+       sym.sdf = 0;
+       sym.sap = NULL;
+       sym.soffset = (int)off;
+       sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU);
+       r = xbcon(0, &sym, typ);
+       p = block(STREF, p, r, INT, 0, 0);
+       ecomp(buildtree(ASSIGN, stref(p), bcon(val)));
+}
+
+/*
+ * Clear a bitfield, starting at off and size fsz.
+ */
+static void
+clearbf(OFFSZ off, OFFSZ fsz)
+{
+       /* Pad up to the next even initializer */
+       if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) {
+               int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off);
+               if (ba > fsz)
+                       ba = (int)fsz;
+               insbf(off, ba, 0);
+               off += ba;
+               fsz -= ba;
+       }
+       while (fsz >= SZCHAR) {
+               insbf(off, SZCHAR, 0);
+               off += SZCHAR;
+               fsz -= SZCHAR;
+       }
+       if (fsz)
+               insbf(off, fsz, 0);
+}
+
+/*
+ * final step of initialization.
+ * print out init nodes and generate copy code (if needed).
+ */
+void
+endinit(int seg)
+{
+       struct llist *ll;
+       struct ilist *il;
+       int fsz;
+       OFFSZ lastoff, tbit;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("endinit()\n");
+#endif
+
+       /* Calculate total block size */
+       if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) {
+               tbit = numents*basesz; /* open-ended arrays */
+               csym->sdf->ddim = numents;
+               if (csym->sclass == AUTO) { /* Get stack space */
+                       csym->soffset = NOOFFSET;
+                       oalloc(csym, &autooff);
+               }
+       } else
+               tbit = tsize(csym->stype, csym->sdf, csym->sap);
+
+       /* Setup symbols */
+       if (csym->sclass != AUTO) {
+               locctr(seg ? UDATA : DATA, csym);
+               defloc(csym);
+       }
+
+       /* Traverse all entries and print'em out */
+       lastoff = 0;
+       SLIST_FOREACH(ll, &lpole, next) {
+               for (il = ll->il; il; il = il->next) {
+#ifdef PCC_DEBUG
+                       if (idebug > 1) {
+                               printf("off " CONFMT " size %d val " CONFMT " type ",
+                                   ll->begsz+il->off, il->fsz, glval(il->n));
+                               tprint(il->n->n_type, 0);
+                               printf("\n");
+                       }
+#endif
+                       fsz = il->fsz;
+                       if (csym->sclass == AUTO) {
+                               struct symtab sym;
+                               NODE *p, *r, *n;
+
+                               if (ll->begsz + il->off > lastoff)
+                                       clearbf(lastoff,
+                                           (ll->begsz + il->off) - lastoff);
+
+                               /* Fake a struct reference */
+                               p = buildtree(ADDROF, nametree(csym), NIL);
+                               n = il->n;
+                               sym.stype = n->n_type;
+                               sym.squal = n->n_qual;
+                               sym.sdf = n->n_df;
+                               sym.sap = n->n_ap;
+                               sym.soffset = (int)(ll->begsz + il->off);
+                               sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0);
+                               r = xbcon(0, &sym, INT);
+                               p = block(STREF, p, r, INT, 0, 0);
+                               ecomp(buildtree(ASSIGN, stref(p), il->n));
+                               if (fsz < 0)
+                                       fsz = -fsz;
+
+                       } else {
+                               if (ll->begsz + il->off > lastoff)
+                                       zbits(lastoff,
+                                           (ll->begsz + il->off) - lastoff);
+                               if (fsz < 0) {
+                                       fsz = -fsz;
+                                       infld(il->off, fsz, glval(il->n));
+                               } else
+                                       inval(il->off, fsz, il->n);
+                               tfree(il->n);
+                       }
+                       lastoff = ll->begsz + il->off + fsz;
+               }
+       }
+       if (csym->sclass == AUTO) {
+               clearbf(lastoff, tbit-lastoff);
+       } else
+               zbits(lastoff, tbit-lastoff);
+       
+       doing_init--;
+       if (csym->sclass == STATIC || csym->sclass == EXTDEF)
+               statinit--;
+       endictx();
+}
+
+void
+endictx(void)
+{
+       struct initctx *ict = inilnk;
+
+       if (ict == NULL)
+               return;
+
+       pstk = ict->pstk;
+       csym = ict->psym;
+       lpole = ict->lpole;
+       basesz = ict->basesz;
+       numents = ict->numents;
+       inilnk = inilnk->prev;
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("endinit: restoring ctx pstk %p\n", pstk);
+#endif
+}
+
+/*
+ * process an initializer's left brace
+ */
+void
+ilbrace(void)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("ilbrace()\n");
+#endif
+
+       if (pstk == NULL)
+               return;
+
+       stkpush();
+       pstk->in_fl = 1; /* mark lbrace */
+#ifdef PCC_DEBUG
+       if (idebug > 1)
+               prtstk(pstk);
+#endif
+}
+
+/*
+ * called when a '}' is seen
+ */
+void
+irbrace(void)
+{
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("irbrace()\n");
+       if (idebug > 2)
+               prtstk(pstk);
+#endif
+
+       if (pstk == NULL)
+               return;
+
+       /* Got right brace, search for corresponding in the stack */
+       for (; pstk->in_prev != NULL; pstk = pstk->in_prev) {
+               if(!pstk->in_fl)
+                       continue;
+
+               /* we have one now */
+
+               pstk->in_fl = 0;  /* cancel { */
+               if (ISARY(pstk->in_t))
+                       pstk->in_n = pstk->in_df->ddim;
+               else if (pstk->in_t == STRTY) {
+                       while (pstk->in_lnk != NULL &&
+                           pstk->in_lnk->snext != NULL)
+                               pstk->in_lnk = pstk->in_lnk->snext;
+               }
+               stkpop();
+               return;
+       }
+}
+
+/*
+ * Create a new init stack based on given elements.
+ */
+static void
+mkstack(NODE *p)
+{
+
+#ifdef PCC_DEBUG
+       if (idebug) {
+               printf("mkstack: %p\n", p);
+               if (idebug > 1 && p)
+                       fwalk(p, eprint, 0);
+       }
+#endif
+
+       if (p == NULL)
+               return;
+       mkstack(p->n_left);
+
+       switch (p->n_op) {
+       case LB: /* Array index */
+               if (p->n_right->n_op != ICON)
+                       cerror("mkstack");
+               if (!ISARY(pstk->in_t))
+                       uerror("array indexing non-array");
+               pstk->in_n = (int)glval(p->n_right);
+               nfree(p->n_right);
+               break;
+
+       case NAME:
+               if (pstk->in_lnk) {
+                       for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext)
+                               if (pstk->in_lnk->sname == (char *)p->n_sp)
+                                       break;
+                       if (pstk->in_lnk == NULL)
+                               uerror("member missing");
+               } else {
+                       uerror("not a struct/union");
+               }
+               break;
+       default:
+               cerror("mkstack2");
+       }
+       nfree(p);
+       stkpush();
+
+}
+
+/*
+ * Initialize a specific element, as per C99.
+ */
+void
+desinit(NODE *p)
+{
+       int op = p->n_op;
+
+       if (pstk == NULL)
+               stkpush(); /* passed end of array */
+       while (pstk->in_prev && pstk->in_fl == 0)
+               pstk = pstk->in_prev; /* Empty stack */
+
+       if (ISSOU(pstk->in_t))
+               pstk->in_lnk = strmemb(pstk->in_sym->sap);
+
+       mkstack(p);     /* Setup for assignment */
+
+       /* pop one step if SOU, ilbrace will push */
+       if (op == NAME || op == LB)
+               pstk = pstk->in_prev;
+
+#ifdef PCC_DEBUG
+       if (idebug > 1) {
+               printf("desinit e\n");
+               prtstk(pstk);
+       }
+#endif
+}
+
+/*
+ * Convert a string to an array of char/wchar for asginit.
+ */
+static void
+strcvt(NODE *p)
+{
+       NODE *q = p;
+       char *s;
+       int i;
+
+#ifdef mach_arm
+       /* XXX */
+       if (p->n_op == UMUL && p->n_left->n_op == ADDROF)
+               p = p->n_left->n_left;
+#endif
+
+       for (s = p->n_sp->sname; *s != 0; ) {
+               if (*s++ == '\\') {
+                       i = esccon(&s);  
+               } else
+                       i = (unsigned char)s[-1];
+               asginit(bcon(i));
+       } 
+       tfree(q);
+}
+
+/*
+ * Do an assignment to a struct element.
+ */
+void
+asginit(NODE *p)
+{
+       int g;
+
+#ifdef PCC_DEBUG
+       if (idebug)
+               printf("asginit %p\n", p);
+       if (idebug > 1 && p)
+               fwalk(p, eprint, 0);
+#endif
+
+       /* convert string to array of char/wchar */
+       if (p && (DEUNSIGN(p->n_type) == ARY+CHAR ||
+           p->n_type == ARY+WCHAR_TYPE)) {
+               struct instk *is;
+               TWORD t;
+
+               t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR;
+               /*
+                * ...but only if next element is ARY+CHAR, otherwise 
+                * just fall through.
+                */
+
+               /* HACKHACKHACK */
+               is = pstk;
+
+               if (pstk == NULL)
+                       stkpush();
+               while (ISSOU(pstk->in_t) || ISARY(pstk->in_t))
+                       stkpush();
+               if (pstk->in_prev && 
+                   (DEUNSIGN(pstk->in_prev->in_t) == t ||
+                   pstk->in_prev->in_t == t)) {
+                       pstk = pstk->in_prev;
+                       if ((g = pstk->in_fl) == 0)
+                               pstk->in_fl = 1; /* simulate ilbrace */
+
+                       strcvt(p);
+                       if (g == 0)
+                               irbrace(); /* will fill with zeroes */
+                       return;
+               } else
+                       pstk = is; /* no array of char */
+               /* END HACKHACKHACK */
+       }
+
+       if (p == NULL) { /* only end of compound stmt */
+               irbrace();
+       } else /* assign next element */
+               scalinit(p);
+}
+
+#ifdef PCC_DEBUG
+void
+prtstk(struct instk *in)
+{
+       int i, o = 0;
+
+       printf("init stack:\n");
+       for (; in != NULL; in = in->in_prev) {
+               for (i = 0; i < o; i++)
+                       printf("  ");
+               printf("%p) '%s' ", in, in->in_sym->sname);
+               tprint(in->in_t, 0);
+               printf(" %s ", scnames(in->in_sym->sclass));
+               if (in->in_df /* && in->in_df->ddim */)
+                   printf("arydim=%d ", in->in_df->ddim);
+               printf("ninit=%d ", in->in_n);
+               if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t))
+                       printf("stsize=%d ",
+                           (int)tsize(in->in_t, in->in_df, in->in_sym->sap));
+               if (in->in_fl) printf("{ ");
+               printf("soff=%d ", in->in_sym->soffset);
+               if (in->in_t == STRTY) {
+                       if (in->in_lnk)
+                               printf("curel %s ", in->in_lnk->sname);
+                       else
+                               printf("END struct");
+               }
+               printf("\n");
+               o++;
+       }
+}
+#endif
+
+/*
+ * Do a simple initialization.
+ * At block 0, just print out the value, at higher levels generate
+ * appropriate code.
+ */
+void
+simpleinit(struct symtab *sp, NODE *p)
+{
+       NODE *q, *r, *nt;
+       TWORD t;
+       int sz;
+
+       /* May be an initialization of an array of char by a string */
+       if ((DEUNSIGN(p->n_type) == ARY+CHAR &&
+           DEUNSIGN(sp->stype) == ARY+CHAR) ||
+           (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) &&
+           DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) {
+               /* Handle "aaa" as { 'a', 'a', 'a' } */
+               beginit(sp);
+               strcvt(p);
+               if (csym->sdf->ddim == NOOFFSET)
+                       scalinit(bcon(0)); /* Null-term arrays */
+               endinit(0);
+               return;
+       }
+
+       nt = nametree(sp);
+       switch (sp->sclass) {
+       case STATIC:
+       case EXTDEF:
+               q = nt;
+               locctr(DATA, sp);
+               defloc(sp);
+#ifndef NO_COMPLEX
+               if (ANYCX(q) || ANYCX(p)) {
+                       r = cxop(ASSIGN, q, p);
+                       /* XXX must unwind the code generated here */
+                       /* We can rely on correct code generated */
+                       p = r->n_left->n_right->n_left;
+                       r->n_left->n_right->n_left = bcon(0);
+                       tfree(r);
+                       r = p->n_left->n_right;
+                       sz = (int)tsize(r->n_type, r->n_df, r->n_ap);
+                       inval(0, sz, r);
+                       inval(0, sz, p->n_right->n_right);
+                       tfree(p);
+                       break;
+               }
+#endif
+               p = optim(buildtree(ASSIGN, nt, p));
+#ifndef WORD_ADDRESSED
+               p = optim(rmpconv(p));
+#endif
+               q = p->n_right;
+               t = q->n_type;
+               sz = (int)tsize(t, q->n_df, q->n_ap);
+               inval(0, sz, q);
+               tfree(p);
+               break;
+
+       case AUTO:
+       case REGISTER:
+               if (ISARY(sp->stype))
+                       cerror("no array init");
+               q = nt;
+#ifndef NO_COMPLEX
+
+               if (ANYCX(q) || ANYCX(p))
+                       r = cxop(ASSIGN, q, p);
+               else
+#endif
+                       r = buildtree(ASSIGN, q, p);
+               ecomp(r);
+               break;
+
+       default:
+               uerror("illegal initialization");
+       }
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/inline.c b/lang/pcc/pcc/cc/cxxcom/inline.c
new file mode 100644 (file)
index 0000000..4afb4d7
--- /dev/null
@@ -0,0 +1,573 @@
+/*     $Id: inline.c,v 1.6 2015/11/24 17:30:20 ragge Exp $     */
+/*
+ * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#include <stdarg.h>
+
+/*
+ * Simple description of how the inlining works:
+ * A function found with the keyword "inline" is always saved.
+ * If it also has the keyword "extern" it is written out thereafter.
+ * If it has the keyword "static" it will be written out if it is referenced.
+ * inlining will only be done if -xinline is given, and only if it is 
+ * possible to inline the function.
+ */
+static void printip(struct interpass *pole);
+
+struct ntds {
+       int temp;
+       TWORD type;
+       union dimfun *df;
+       struct attr *attr;
+};
+
+/*
+ * ilink from ipole points to the next struct in the list of functions.
+ */
+static struct istat {
+       SLIST_ENTRY(istat) link;
+       struct symtab *sp;
+       int flags;
+#define        CANINL  1       /* function is possible to inline */
+#define        WRITTEN 2       /* function is written out */
+#define        REFD    4       /* Referenced but not yet written out */
+       struct ntds *nt;/* Array of arg temp type data */
+       int nargs;      /* number of args in array */
+       int retval;     /* number of return temporary, if any */
+       struct interpass shead;
+} *cifun;
+
+static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw };
+static int nlabs;
+
+#define        IP_REF  (MAXIP+1)
+#ifdef PCC_DEBUG
+#define        SDEBUG(x)       if (sdebug) printf x
+#else
+#define        SDEBUG(x)
+#endif
+
+int isinlining;
+int inlnodecnt, inlstatcnt;
+
+#define        SZSI    sizeof(struct istat)
+#define        ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
+
+static void
+tcnt(NODE *p, void *arg)
+{
+       inlnodecnt++;
+       if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
+           regno(p) == FPREG)
+               SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */
+       if (p->n_op == NAME || p->n_op == ICON)
+               p->n_sp = NULL; /* let symtabs be freed for inline funcs */
+       if (ndebug)
+               printf("locking node %p\n", p);
+}
+
+static struct istat *
+findfun(struct symtab *sp)
+{
+       struct istat *is;
+
+       SLIST_FOREACH(is, &ipole, link)
+               if (is->sp == sp)
+                       return is;
+       return NULL;
+}
+
+static void
+refnode(struct symtab *sp)
+{
+       struct interpass *ip;
+
+       SDEBUG(("refnode(%s)\n", sp->sname));
+
+       ip = permalloc(sizeof(*ip));
+       ip->type = IP_REF;
+       ip->ip_name = (char *)sp;
+       inline_addarg(ip);
+}
+
+void
+inline_addarg(struct interpass *ip)
+{
+       extern NODE *cftnod;
+
+       SDEBUG(("inline_addarg(%p)\n", ip));
+       DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem);
+       if (ip->type == IP_DEFLAB)
+               nlabs++;
+       if (ip->type == IP_NODE)
+               walkf(ip->ip_node, tcnt, 0); /* Count as saved */
+       if (cftnod)
+               cifun->retval = regno(cftnod);
+}
+
+/*
+ * Called to setup for inlining of a new function.
+ */
+void
+inline_start(struct symtab *sp)
+{
+       struct istat *is;
+
+       SDEBUG(("inline_start(\"%s\")\n", sp->sname));
+
+       if (isinlining)
+               cerror("already inlining function");
+
+       if ((is = findfun(sp)) != 0) {
+               if (!DLIST_ISEMPTY(&is->shead, qelem))
+                       uerror("inline function already defined");
+       } else {
+               is = ialloc();
+               is->sp = sp;
+               SLIST_INSERT_FIRST(&ipole, is, link);
+               DLIST_INIT(&is->shead, qelem);
+       }
+       cifun = is;
+       nlabs = 0;
+       isinlining++;
+}
+
+/*
+ * End of an inline function. In C99 an inline function declared "extern"
+ * should also have external linkage and are therefore printed out.
+ *
+ * Gcc inline syntax is a mess, see matrix below on emitting functions:
+ *                 without extern
+ *     -std=           -       gnu89   gnu99   
+ *     gcc 3.3.5:      ja      ja      ja
+ *     gcc 4.1.3:      ja      ja      ja
+ *     gcc 4.3.1       ja      ja      nej     
+ * 
+ *                  with extern
+ *     gcc 3.3.5:      nej     nej     nej
+ *     gcc 4.1.3:      nej     nej     nej
+ *     gcc 4.3.1       nej     nej     ja      
+ *
+ * The attribute gnu_inline sets gnu89 behaviour.
+ * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate.
+ */
+void
+inline_end(void)
+{
+       struct symtab *sp = cifun->sp;
+
+       SDEBUG(("inline_end()\n"));
+
+       if (sdebug)printip(&cifun->shead);
+       isinlining = 0;
+
+#ifdef GCC_COMPAT
+       if (sp->sclass != STATIC &&
+           (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) {
+               if (sp->sclass == EXTDEF)
+                       sp->sclass = 0;
+               else
+                       sp->sclass = EXTDEF;
+       }
+#endif
+       if (sp->sclass == EXTDEF) {
+               cifun->flags |= REFD;
+               inline_prtout();
+       }
+}
+
+/*
+ * Called when an inline function is found, to be sure that it will
+ * be written out.
+ * The function may not be defined when inline_ref() is called.
+ */
+void
+inline_ref(struct symtab *sp)
+{
+       struct istat *w;
+
+       SDEBUG(("inline_ref(\"%s\")\n", sp->sname));
+       if (sp->sclass == SNULL)
+               return; /* only inline, no references */
+       if (isinlining) {
+               refnode(sp);
+       } else {
+               SLIST_FOREACH(w,&ipole, link) {
+                       if (w->sp != sp)
+                               continue;
+                       w->flags |= REFD;
+                       return;
+               }
+               /* function not yet defined, print out when found */
+               w = ialloc();
+               w->sp = sp;
+               w->flags |= REFD;
+               SLIST_INSERT_FIRST(&ipole, w, link);
+               DLIST_INIT(&w->shead, qelem);
+       }
+}
+
+static void
+puto(struct istat *w)
+{
+       struct interpass_prolog *ipp, *epp, *pp;
+       struct interpass *ip, *nip;
+       extern int crslab;
+       int lbloff = 0;
+
+       /* Copy the saved function and print it out */
+       ipp = 0; /* XXX data flow analysis */
+       DLIST_FOREACH(ip, &w->shead, qelem) {
+               switch (ip->type) {
+               case IP_EPILOG:
+               case IP_PROLOG:
+                       if (ip->type == IP_PROLOG) {
+                               ipp = (struct interpass_prolog *)ip;
+                               /* fix label offsets */
+                               lbloff = crslab - ipp->ip_lblnum;
+                       } else {
+                               epp = (struct interpass_prolog *)ip;
+                               crslab += (epp->ip_lblnum - ipp->ip_lblnum);
+                       }
+                       pp = tmpalloc(sizeof(struct interpass_prolog));
+                       memcpy(pp, ip, sizeof(struct interpass_prolog));
+                       pp->ip_lblnum += lbloff;
+#ifdef PCC_DEBUG
+                       if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum)
+                               cerror("puto: %d != %d", crslab, pp->ip_lblnum);
+#endif
+                       pass2_compile((struct interpass *)pp);
+                       break;
+
+               case IP_REF:
+                       inline_ref((struct symtab *)ip->ip_name);
+                       break;
+
+               default:
+                       nip = tmpalloc(sizeof(struct interpass));
+                       *nip = *ip;
+                       if (nip->type == IP_NODE) {
+                               NODE *p;
+
+                               p = nip->ip_node = ccopy(nip->ip_node);
+                               if (p->n_op == GOTO)
+                                       glval(p->n_left) += lbloff;
+                               else if (p->n_op == CBRANCH)
+                                       glval(p->n_right) += lbloff;
+                       } else if (nip->type == IP_DEFLAB)
+                               nip->ip_lbl += lbloff;
+                       pass2_compile(nip);
+                       break;
+               }
+       }
+       w->flags |= WRITTEN;
+}
+
+/*
+ * printout functions that are referenced.
+ */
+void
+inline_prtout(void)
+{
+       struct istat *w;
+       int gotone = 0;
+
+       SLIST_FOREACH(w, &ipole, link) {
+               if ((w->flags & (REFD|WRITTEN)) == REFD &&
+                   !DLIST_ISEMPTY(&w->shead, qelem)) {
+                       locctr(PROG, w->sp);
+                       defloc(w->sp);
+                       puto(w);
+                       w->flags |= WRITTEN;
+                       gotone++;
+               }
+       }
+       if (gotone)
+               inline_prtout();
+}
+
+#if 1
+static void
+printip(struct interpass *pole)
+{
+       static char *foo[] = {
+          0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+       struct interpass *ip;
+       struct interpass_prolog *ipplg, *epplg;
+
+       DLIST_FOREACH(ip, pole, qelem) {
+               if (ip->type > MAXIP)
+                       printf("IP(%d) (%p): ", ip->type, ip);
+               else
+                       printf("%s (%p): ", foo[ip->type], ip);
+               switch (ip->type) {
+               case IP_NODE: printf("\n");
+#ifdef PCC_DEBUG
+                       fwalk(ip->ip_node, eprint, 0); break;
+#endif
+               case IP_PROLOG:
+                       ipplg = (struct interpass_prolog *)ip;
+                       printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
+                           ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "",
+                           (long)ipplg->ipp_regs[0], ipplg->ipp_autos,
+                           ipplg->ip_tmpnum, ipplg->ip_lblnum);
+                       break;
+               case IP_EPILOG:
+                       epplg = (struct interpass_prolog *)ip;
+                       printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
+                           epplg->ipp_name, epplg->ipp_vis ? "(local)" : "",
+                           (long)epplg->ipp_regs[0], epplg->ipp_autos,
+                           epplg->ip_tmpnum, epplg->ip_lblnum);
+                       break;
+               case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
+               case IP_DEFNAM: printf("\n"); break;
+               case IP_ASM: printf("%s", ip->ip_asm); break;
+               default:
+                       break;
+               }
+       }
+}
+#endif
+
+static int toff;
+
+static NODE *
+mnode(struct ntds *nt, NODE *p)
+{
+       NODE *q;
+       int num = nt->temp + toff;
+
+       if (p->n_op == CM) {
+               q = p->n_right;
+               q = tempnode(num, nt->type, nt->df, nt->attr);
+               nt--;
+               p->n_right = buildtree(ASSIGN, q, p->n_right);
+               p->n_left = mnode(nt, p->n_left);
+               p->n_op = COMOP;
+       } else {
+               p = pconvert(p);
+               q = tempnode(num, nt->type, nt->df, nt->attr);
+               p = buildtree(ASSIGN, q, p);
+       }
+       return p;
+}
+
+static void
+rtmps(NODE *p, void *arg)
+{
+       if (p->n_op == TEMP)
+               regno(p) += toff;
+}
+
+/*
+ * Inline a function. Returns the return value.
+ * There are two major things that must be converted when 
+ * inlining a function:
+ * - Label numbers must be updated with an offset.
+ * - The stack block must be relocated (add to REG or OREG).
+ * - Temporaries should be updated (but no must)
+ */
+NODE *
+inlinetree(struct symtab *sp, NODE *f, NODE *ap)
+{
+       extern int crslab, tvaloff;
+       struct istat *is = findfun(sp);
+       struct interpass *ip, *ipf, *ipl;
+       int lmin, l0, l1, l2, gainl;
+       NODE *p, *rp;
+
+       if (is == NULL || nerrors) {
+               inline_ref(sp); /* prototype of not yet declared inline ftn */
+               return NIL;
+       }
+
+       SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL));
+
+#ifdef GCC_COMPAT
+       gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL;
+#else
+       gainl = 0;
+#endif
+
+       if ((is->flags & CANINL) == 0 && gainl)
+               werror("cannot inline but always_inline");
+
+       if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) {
+               if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
+                       inline_ref(sp);
+               return NIL;
+       }
+
+       if (isinlining && cifun->sp == sp) {
+               /* Do not try to inline ourselves */
+               inline_ref(sp);
+               return NIL;
+       }
+
+#ifdef mach_i386
+       if (kflag) {
+               is->flags |= REFD; /* if static inline, emit */
+               return NIL; /* XXX cannot handle hidden ebx arg */
+       }
+#endif
+
+       /* emit jumps to surround inline function */
+       branch(l0 = getlab());
+       plabel(l1 = getlab());
+       l2 = getlab();
+       SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2));
+
+       ipf = DLIST_NEXT(&is->shead, qelem); /* prolog */
+       ipl = DLIST_PREV(&is->shead, qelem); /* epilog */
+
+       /* Fix label & temp offsets */
+#define        IPP(x) ((struct interpass_prolog *)x)
+       SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff));
+       lmin = crslab - IPP(ipf)->ip_lblnum;
+       crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1;
+       toff = tvaloff - IPP(ipf)->ip_tmpnum;
+       tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1;
+       SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
+           crslab, lmin, tvaloff, toff));
+
+       /* traverse until first real label */
+       ipf = DLIST_NEXT(ipf, qelem);
+       do
+               ipf = DLIST_NEXT(ipf, qelem);
+       while (ipf->type != IP_DEFLAB);
+
+       /* traverse backwards to last label */
+       do
+               ipl = DLIST_PREV(ipl, qelem);
+       while (ipl->type != IP_DEFLAB);
+
+       /* So, walk over all statements and emit them */
+       for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) {
+               switch (ip->type) {
+               case IP_NODE:
+                       p = ccopy(ip->ip_node);
+                       if (p->n_op == GOTO)
+                               glval(p->n_left) += lmin;
+                       else if (p->n_op == CBRANCH)
+                               glval(p->n_right) += lmin;
+                       walkf(p, rtmps, 0);
+#ifdef PCC_DEBUG
+                       if (sdebug) {
+                               printf("converted node\n");
+                               fwalk(ip->ip_node, eprint, 0);
+                               fwalk(p, eprint, 0);
+                       }
+#endif
+                       send_passt(IP_NODE, p);
+                       break;
+
+               case IP_DEFLAB:
+                       SDEBUG(("converted label %d to %d\n",
+                           ip->ip_lbl, ip->ip_lbl + lmin));
+                       send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+                       break;
+
+               case IP_ASM:
+                       send_passt(IP_ASM, ip->ip_asm);
+                       break;
+
+               case IP_REF:
+                       inline_ref((struct symtab *)ip->ip_name);
+                       break;
+
+               default:
+                       cerror("bad inline stmt %d", ip->type);
+               }
+       }
+       SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin));
+       send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+
+       branch(l2);
+       plabel(l0);
+
+       rp = block(GOTO, bcon(l1), NIL, INT, 0, 0);
+       if (is->retval)
+               p = tempnode(is->retval + toff, DECREF(sp->stype),
+                   sp->sdf, sp->sap);
+       else
+               p = bcon(0);
+       rp = buildtree(COMOP, rp, p);
+
+       if (is->nargs) {
+               p = mnode(&is->nt[is->nargs-1], ap);
+               rp = buildtree(COMOP, p, rp);
+       }
+
+       tfree(f);
+       return rp;
+}
+
+void
+inline_args(struct symtab **sp, int nargs)
+{
+       union arglist *al;
+       struct istat *cf;
+       TWORD t;
+       int i;
+
+       SDEBUG(("inline_args\n"));
+       cf = cifun;
+       /*
+        * First handle arguments.  We currently do not inline anything if:
+        * - function has varargs
+        * - function args are volatile, checked if no temp node is asg'd.
+        */
+       /* XXX - this is ugly, invent something better */
+       if (cf->sp->sdf->dfun == NULL)
+               return; /* no prototype */
+       for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) {
+               t = al->type;
+               if (t == TELLIPSIS)
+                       return; /* cannot inline */
+               if (ISSOU(BTYPE(t)))
+                       al++;
+               for (; t > BTMASK; t = DECREF(t))
+                       if (ISARY(t) || ISFTN(t))
+                               al++;
+       }
+
+       if (nargs) {
+               for (i = 0; i < nargs; i++)
+                       if ((sp[i]->sflags & STNODE) == 0)
+                               return; /* not temporary */
+               cf->nt = permalloc(sizeof(struct ntds)*nargs);
+               for (i = 0; i < nargs; i++) {
+                       cf->nt[i].temp = sp[i]->soffset;
+                       cf->nt[i].type = sp[i]->stype;
+                       cf->nt[i].df = sp[i]->sdf;
+                       cf->nt[i].attr = sp[i]->sap;
+               }
+       }
+       cf->nargs = nargs;
+       cf->flags |= CANINL;
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/main.c b/lang/pcc/pcc/cc/cxxcom/main.c
new file mode 100644 (file)
index 0000000..255ea22
--- /dev/null
@@ -0,0 +1,357 @@
+/*     $Id: main.c,v 1.6 2014/10/12 11:52:13 ragge Exp $       */
+
+/*
+ * Copyright (c) 2002 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+int bdebug, ddebug, edebug, idebug, ndebug;
+int odebug, pdebug, sdebug, tdebug, xdebug, cppdebug, wdebug;
+int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug;
+int r2debug, s2debug, t2debug, u2debug, x2debug;
+int gflag, kflag, pflag, sflag;
+int sspflag;
+int xssa, xtailcall, xtemps, xdeljumps, xdce, xinline, xccp, xgnu89, xgnu99;
+int xuchar;
+int freestanding;
+char *prgname;
+
+static void prtstats(void);
+
+static void
+usage(void)
+{
+       (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n",
+           prgname);
+       exit(1);
+}
+
+static void
+segvcatch(int a)
+{
+       char buf[1024];
+
+       snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n",
+           nerrors ? "" : "major ", ftitle, lineno);
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+       _exit(1);
+}
+
+static void
+xopt(char *str)
+{
+       if (strcmp(str, "ssa") == 0)
+               xssa++;
+       else if (strcmp(str, "tailcall") == 0)
+               xtailcall++;
+       else if (strcmp(str, "temps") == 0)
+               xtemps++;
+       else if (strcmp(str, "deljumps") == 0)
+               xdeljumps++;
+       else if (strcmp(str, "dce") == 0)
+               xdce++;
+       else if (strcmp(str, "inline") == 0)
+               xinline++;
+       else if (strcmp(str, "ccp") == 0)
+               xccp++;
+       else if (strcmp(str, "gnu89") == 0)
+               xgnu89++;
+       else if (strcmp(str, "gnu99") == 0)
+               xgnu99++;
+       else if (strcmp(str, "uchar") == 0)
+               xuchar++;
+       else {
+               fprintf(stderr, "unknown -x option '%s'\n", str);
+               usage();
+       }
+}
+
+static void
+fflags(char *str)
+{
+       int flagval = 1;
+
+       if (strncmp("no-", str, 3) == 0) {
+               str += 3;
+               flagval = 0;
+       }
+
+       if (strcmp(str, "stack-protector") == 0)
+               sspflag = flagval;
+       else if (strcmp(str, "stack-protector-all") == 0)
+               sspflag = flagval;
+       else if (strncmp(str, "pack-struct", 11) == 0)
+               pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1);
+       else if (strcmp(str, "freestanding") == 0)
+               freestanding = flagval;
+       else {
+               fprintf(stderr, "unknown -f option '%s'\n", str);
+               usage();
+       }
+}
+
+/* control multiple files */
+int
+main(int argc, char *argv[])
+{
+       int ch;
+
+#ifdef TIMING
+       struct timeval t1, t2;
+
+       (void)gettimeofday(&t1, NULL);
+#endif
+
+       prgname = argv[0];
+
+       while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gkm:psvwx:")) != -1) {
+               switch (ch) {
+#if !defined(MULTIPASS) || defined(PASS1)
+               case 'X':       /* pass1 debugging */
+                       while (*optarg)
+                               switch (*optarg++) {
+                               case 'b': ++bdebug; break; /* buildtree */
+                               case 'd': ++ddebug; break; /* declarations */
+                               case 'e': ++edebug; break; /* pass1 exit */
+                               case 'i': ++idebug; break; /* initializations */
+                               case 'n': ++ndebug; break; /* node allocation */
+                               case 'o': ++odebug; break; /* optim */
+                               case 'p': ++pdebug; break; /* prototype */
+                               case 's': ++sdebug; break; /* inline */
+                               case 't': ++tdebug; break; /* type match */
+                               case 'x': ++xdebug; break; /* MD code */
+                               case '+': ++cppdebug; break; /* C++ */
+                               default:
+                                       fprintf(stderr, "unknown -X flag '%c'\n",
+                                           optarg[-1]);
+                                       exit(1);
+                               }
+                       break;
+#endif
+#if !defined(MULTIPASS) || defined(PASS2)
+               case 'Z':       /* pass2 debugging */
+                       while (*optarg)
+                               switch (*optarg++) {
+                               case 'b': /* basic block and SSA building */
+                                       ++b2debug;
+                                       break;
+                               case 'c': /* code printout */
+                                       ++c2debug;
+                                       break;
+                               case 'e': /* print tree upon pass2 enter */
+                                       ++e2debug;
+                                       break;
+                               case 'f': /* instruction matching */
+                                       ++f2debug;
+                                       break;
+                               case 'g': /* print flow graphs */
+                                       ++g2debug;
+                                       break;
+                               case 'n': /* node allocation */
+                                       ++ndebug;
+                                       break;
+                               case 'o': /* instruction generator */
+                                       ++o2debug;
+                                       break;
+                               case 'r': /* register alloc/graph coloring */
+                                       ++r2debug;
+                                       break;
+                               case 's': /* shape matching */
+                                       ++s2debug;
+                                       break;
+                               case 't': /* type matching */
+                                       ++t2debug;
+                                       break;
+                               case 'u': /* Sethi-Ullman debugging */
+                                       ++u2debug;
+                                       break;
+                               case 'x': /* target specific */
+                                       ++x2debug;
+                                       break;
+                               default:
+                                       fprintf(stderr, "unknown -Z flag '%c'\n",
+                                           optarg[-1]);
+                                       exit(1);
+                               }
+                       break;
+#endif
+               case 'f': /* Language */
+                       fflags(optarg);
+                       break;
+
+               case 'g': /* Debugging */
+                       gflag = 1;
+                       break;
+
+               case 'k': /* PIC code */
+                       ++kflag;
+                       break;
+
+               case 'm': /* Target-specific */
+                       mflags(optarg);
+                       break;
+
+               case 'p': /* Profiling */
+                       pflag = 1;
+                       break;
+
+               case 's': /* Statistics */
+                       ++sflag;
+                       break;
+
+               case 'W': /* Enable different warnings */
+                       Wflags(optarg);
+                       break;
+
+               case 'x': /* Different settings */
+                       xopt(optarg);
+                       break;
+
+               case 'v':
+                       printf("ccom: %s\n", VERSSTR);
+                       break;
+
+               case '?':
+               default:
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc > 0 && strcmp(argv[0], "-") != 0) {
+               if (freopen(argv[0], "r", stdin) == NULL) {
+                       fprintf(stderr, "open input file '%s':",
+                           argv[0]);
+                       perror(NULL);
+                       exit(1);
+               }
+       }
+       if (argc > 1 && strcmp(argv[1], "-") != 0) {
+               if (freopen(argv[1], "w", stdout) == NULL) {
+                       fprintf(stderr, "open output file '%s':",
+                           argv[1]);
+                       perror(NULL);
+                       exit(1);
+               }
+       }
+
+       mkdope();
+       signal(SIGSEGV, segvcatch);
+#ifdef SIGBUS
+       signal(SIGBUS, segvcatch);
+#endif
+       fregs = FREGS;  /* number of free registers */
+       lineno = 1;
+#ifdef GCC_COMPAT
+       gcc_init();
+#endif
+
+       /* starts past any of the above */
+       reached = 1;
+
+       bjobcode();
+#ifndef TARGET_VALIST
+       {
+               NODE *p = block(NAME, NIL, NIL, PTR|CHAR, NULL, 0);
+               struct symtab *sp = lookup(addname("__builtin_va_list"), 0);
+               p->n_sp = sp;
+               defid(p, TYPEDEF);
+               nfree(p);
+       }
+#endif
+       complinit();
+
+#ifdef STABS
+       if (gflag) {
+               stabs_file(argc ? argv[0] : "");
+               stabs_init();
+       }
+#endif
+
+       if (sspflag)
+               sspinit();
+
+       (void) yyparse();
+       yyaccpt();
+
+       if (!nerrors)
+               lcommprint();
+
+#ifdef STABS
+       if (gflag)
+               stabs_efile(argc ? argv[0] : "");
+#endif
+
+       ejobcode( nerrors ? 1 : 0 );
+
+#ifdef TIMING
+       (void)gettimeofday(&t2, NULL);
+       t2.tv_sec -= t1.tv_sec;
+       t2.tv_usec -= t1.tv_usec;
+       if (t2.tv_usec < 0) {
+               t2.tv_usec += 1000000;
+               t2.tv_sec -= 1;
+       }
+       fprintf(stderr, "ccom total time: %ld s %ld us\n",
+           t2.tv_sec, t2.tv_usec);
+#endif
+
+       if (sflag)
+               prtstats();
+
+       return(nerrors?1:0);
+}
+
+void
+prtstats(void)
+{
+       extern int nametabs, namestrlen, tmpallocsize, permallocsize;
+       extern int lostmem, arglistcnt, dimfuncnt, inlnodecnt, inlstatcnt;
+       extern int symtabcnt, suedefcnt;
+
+       fprintf(stderr, "Name table entries:            %d pcs\n", nametabs);
+       fprintf(stderr, "Name string size:              %d B\n", namestrlen);
+       fprintf(stderr, "Permanent allocated memory:    %d B\n", permallocsize);
+       fprintf(stderr, "Temporary allocated memory:    %d B\n", tmpallocsize);
+       fprintf(stderr, "Lost memory:                   %d B\n", lostmem);
+       fprintf(stderr, "Argument list unions:          %d pcs\n", arglistcnt);
+       fprintf(stderr, "Dimension/function unions:     %d pcs\n", dimfuncnt);
+       fprintf(stderr, "Struct/union/enum blocks:      %d pcs\n", suedefcnt);
+       fprintf(stderr, "Inline node count:             %d pcs\n", inlnodecnt);
+       fprintf(stderr, "Inline control blocks:         %d pcs\n", inlstatcnt);
+       fprintf(stderr, "Permanent symtab entries:      %d pcs\n", symtabcnt);
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/optim.c b/lang/pcc/pcc/cc/cxxcom/optim.c
new file mode 100644 (file)
index 0000000..0da5d7e
--- /dev/null
@@ -0,0 +1,426 @@
+/*     $Id: optim.c,v 1.5 2015/11/24 17:30:20 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+# define SWAP(p,q) {sp=p; p=q; q=sp;}
+# define RCON(p) (p->n_right->n_op==ICON)
+# define RO(p) p->n_right->n_op
+# define RV(p) glval(p->n_right)
+# define LCON(p) (p->n_left->n_op==ICON)
+# define LO(p) p->n_left->n_op
+# define LV(p) glval(p->n_left)
+
+/* remove left node */
+static NODE *
+zapleft(NODE *p)
+{
+       NODE *q;
+
+       q = p->n_left;
+       nfree(p->n_right);
+       nfree(p);
+       return q;
+}
+
+/*
+ * fortran function arguments
+ */
+static NODE *
+fortarg(NODE *p)
+{
+       if( p->n_op == CM ){
+               p->n_left = fortarg( p->n_left );
+               p->n_right = fortarg( p->n_right );
+               return(p);
+       }
+
+       while( ISPTR(p->n_type) ){
+               p = buildtree( UMUL, p, NIL );
+       }
+       return( optim(p) );
+}
+
+       /* mapping relationals when the sides are reversed */
+short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT };
+
+/*
+ * local optimizations, most of which are probably
+ * machine independent
+ */
+NODE *
+optim(NODE *p)
+{
+       int o, ty;
+       NODE *sp, *q;
+       OFFSZ sz;
+       int i;
+
+       if (odebug) return(p);
+
+       ty = coptype(p->n_op);
+       if( ty == LTYPE ) return(p);
+
+       if( ty == BITYPE ) p->n_right = optim(p->n_right);
+       p->n_left = optim(p->n_left);
+
+       /* collect constants */
+again: o = p->n_op;
+       switch(o){
+
+       case SCONV:
+               if (concast(p->n_left, p->n_type)) {
+                       q = p->n_left;
+                       nfree(p);
+                       p = q;
+                       break;
+               }
+               /* FALLTHROUGH */
+       case PCONV:
+               if (p->n_type != VOID)
+                       p = clocal(p);
+               break;
+
+       case FORTCALL:
+               p->n_right = fortarg( p->n_right );
+               break;
+
+       case ADDROF:
+               if (LO(p) == TEMP)
+                       break;
+               if( LO(p) != NAME ) cerror( "& error" );
+
+               if( !andable(p->n_left) && !statinit)
+                       break;
+
+               LO(p) = ICON;
+
+               setuleft:
+               /* paint over the type of the left hand side with the type of the top */
+               p->n_left->n_type = p->n_type;
+               p->n_left->n_df = p->n_df;
+               p->n_left->n_ap = p->n_ap;
+               q = p->n_left;
+               nfree(p);
+               p = q;
+               break;
+
+       case NOT:
+       case UMINUS:
+       case COMPL:
+               if (LCON(p) && conval(p->n_left, o, p->n_left))
+                       p = nfree(p);
+               break;
+
+       case UMUL:
+               /* Do not discard ADDROF TEMP's */
+               if (LO(p) == ADDROF && LO(p->n_left) != TEMP) {
+                       q = p->n_left->n_left;
+                       nfree(p->n_left);
+                       nfree(p);
+                       p = q;
+                       break;
+               }
+               if( LO(p) != ICON ) break;
+               LO(p) = NAME;
+               goto setuleft;
+
+       case RS:
+               if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
+                       goto zapright;
+
+               sz = tsize(p->n_type, p->n_df, p->n_ap);
+
+               if (LO(p) == RS && RCON(p->n_left) && RCON(p) &&
+                   (RV(p) + RV(p->n_left)) < sz) {
+                       /* two right-shift  by constants */
+                       RV(p) += RV(p->n_left);
+                       p->n_left = zapleft(p->n_left);
+               }
+#if 0
+                 else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
+                       RV(p) -= RV(p->n_left);
+                       if (RV(p) < 0)
+                               o = p->n_op = LS, RV(p) = -RV(p);
+                       p->n_left = zapleft(p->n_left);
+               }
+#endif
+               if (RO(p) == ICON) {
+                       if (RV(p) < 0) {
+                               RV(p) = -RV(p);
+                               p->n_op = LS;
+                               goto again;
+                       }
+#ifdef notyet /* must check for side effects, --a >> 32; */
+                       if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) &&
+                           ISUNSIGNED(p->n_type)) { /* ignore signed shifts */
+                               /* too many shifts */
+                               tfree(p->n_left);
+                               nfree(p->n_right);
+                               p->n_op = ICON; glval(p) = 0; p->n_sp = NULL;
+                       } else
+#endif
+                       /* avoid larger shifts than type size */
+                       if (RV(p) >= sz) {
+                               RV(p) = RV(p) % sz;
+                               werror("shift larger than type");
+                       }
+                       if (RV(p) == 0)
+                               p = zapleft(p);
+               }
+               break;
+
+       case LS:
+               if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
+                       goto zapright;
+
+               sz = tsize(p->n_type, p->n_df, p->n_ap);
+
+               if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
+                       /* two left-shift  by constants */
+                       RV(p) += RV(p->n_left);
+                       p->n_left = zapleft(p->n_left);
+               }
+#if 0
+                 else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) {
+                       RV(p) -= RV(p->n_left);
+                       p->n_left = zapleft(p->n_left);
+               }
+#endif
+               if (RO(p) == ICON) {
+                       if (RV(p) < 0) {
+                               RV(p) = -RV(p);
+                               p->n_op = RS;
+                               goto again;
+                       }
+#ifdef notyet /* must check for side effects */
+                       if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) {
+                               /* too many shifts */
+                               tfree(p->n_left);
+                               nfree(p->n_right);
+                               p->n_op = ICON; glval(p) = 0; p->n_sp = NULL;
+                       } else
+#endif
+                       /* avoid larger shifts than type size */
+                       if (RV(p) >= sz) {
+                               RV(p) = RV(p) % sz;
+                               werror("shift larger than type");
+                       }
+                       if (RV(p) == 0)  
+                               p = zapleft(p);
+               }
+               break;
+
+       case MINUS:
+               if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) {
+                       /* link-time constants, but both are the same */
+                       /* solve it now by forgetting the symbols */
+                       p->n_left->n_sp = p->n_right->n_sp = NULL;
+               }
+               if( !nncon(p->n_right) ) break;
+               RV(p) = -RV(p);
+               o = p->n_op = PLUS;
+
+       case MUL:
+               /*
+                * Check for u=(x-y)+z; where all vars are pointers to
+                * the same struct. This has two advantages:
+                * 1: avoid a mul+div
+                * 2: even if not allowed, people may get surprised if this
+                *    calculation do not give correct result if using
+                *    unaligned structs.
+                */
+               if (p->n_type == INTPTR && RCON(p) &&
+                   LO(p) == DIV && RCON(p->n_left) &&
+                   RV(p) == RV(p->n_left) &&
+                   LO(p->n_left) == MINUS) {
+                       q = p->n_left->n_left;
+                       if (q->n_left->n_type == PTR+STRTY &&
+                           q->n_right->n_type == PTR+STRTY &&
+                           strmemb(q->n_left->n_ap) ==
+                           strmemb(q->n_right->n_ap)) {
+                               p = zapleft(p);
+                               p = zapleft(p);
+                       }
+               }
+               /* FALLTHROUGH */
+       case PLUS:
+       case AND:
+       case OR:
+       case ER:
+               /* commutative ops; for now, just collect constants */
+               /* someday, do it right */
+               if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) )
+                       SWAP( p->n_left, p->n_right );
+               /* make ops tower to the left, not the right */
+               if( RO(p) == o ){
+                       NODE *t1, *t2, *t3;
+                       t1 = p->n_left;
+                       sp = p->n_right;
+                       t2 = sp->n_left;
+                       t3 = sp->n_right;
+                       /* now, put together again */
+                       p->n_left = sp;
+                       sp->n_left = t1;
+                       sp->n_right = t2;
+                       sp->n_type = p->n_type;
+                       p->n_right = t3;
+                       }
+               if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) &&
+                  conval(p->n_right, MINUS, p->n_left->n_right)){
+                       zapleft:
+
+                       q = p->n_left->n_left;
+                       nfree(p->n_left->n_right);
+                       nfree(p->n_left);
+                       p->n_left = q;
+               }
+               if( RCON(p) && LO(p)==o && RCON(p->n_left) &&
+                   conval( p->n_right, o, p->n_left->n_right ) ){
+                       goto zapleft;
+                       }
+               else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){
+                       zapright:
+                       nfree(p->n_right);
+                       q = makety(p->n_left, p->n_type, p->n_qual,
+                           p->n_df, p->n_ap);
+                       nfree(p);
+                       p = clocal(q);
+                       break;
+                       }
+
+               /* change muls to shifts */
+
+               if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){
+                       if( i == 0 ) { /* multiplication by 1 */
+                               goto zapright;
+                               }
+                       o = p->n_op = LS;
+                       p->n_right->n_type = INT;
+                       p->n_right->n_df = NULL;
+                       RV(p) = i;
+                       }
+
+               /* change +'s of negative consts back to - */
+               if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){
+                       RV(p) = -RV(p);
+                       o = p->n_op = MINUS;
+                       }
+
+               /* remove ops with RHS 0 */
+               if ((o == PLUS || o == MINUS || o == OR || o == ER) &&
+                   nncon(p->n_right) && RV(p) == 0) {
+                       goto zapright;
+               }
+               break;
+
+       case DIV:
+               if( nncon( p->n_right ) && glval(p->n_right) == 1 )
+                       goto zapright;
+               if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right))
+                       goto zapright;
+               if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) {
+                       p->n_op = RS;
+                       RV(p) = i;
+                       q = p->n_right;
+                       if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT)
+                               p->n_right = makety(q, INT, 0, 0, 0);
+
+                       break;
+               }
+               break;
+
+       case MOD:
+               if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) {
+                       p->n_op = AND;
+                       RV(p) = RV(p) -1;
+                       break;
+               }
+               break;
+
+       case EQ:
+       case NE:
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+       case ULT:
+       case ULE:
+       case UGT:
+       case UGE:
+               if( !LCON(p) ) break;
+
+               /* exchange operands */
+
+               sp = p->n_left;
+               p->n_left = p->n_right;
+               p->n_right = sp;
+               p->n_op = revrel[p->n_op - EQ ];
+               break;
+
+#ifdef notyet
+       case ASSIGN:
+               /* Simple test to avoid two branches */
+               if (RO(p) != NE)
+                       break;
+               q = p->n_right;
+               if (RCON(q) && RV(q) == 0 && LO(q) == AND &&
+                   RCON(q->n_left) && (i = ispow2(RV(q->n_left))) &&
+                   q->n_left->n_type == INT) {
+                       q->n_op = RS;
+                       RV(q) = i;
+               }
+               break;
+#endif
+       }
+
+       return(p);
+       }
+
+int
+ispow2(CONSZ c)
+{
+       int i;
+       if( c <= 0 || (c&(c-1)) ) return(-1);
+       for( i=0; c>1; ++i) c >>= 1;
+       return(i);
+}
+
+int
+nncon(NODE *p)
+{
+       /* is p a constant without a name */
+       return( p->n_op == ICON && p->n_sp == NULL );
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/pass1.h b/lang/pcc/pcc/cc/cxxcom/pass1.h
new file mode 100644 (file)
index 0000000..984b4ad
--- /dev/null
@@ -0,0 +1,664 @@
+/*     $Id: pass1.h,v 1.20 2016/03/05 15:31:25 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+
+#ifndef MKEXT
+#include "external.h"
+#else
+typedef unsigned int bittype; /* XXX - for basicblock */
+#endif
+#include "manifest.h"
+#include "softfloat.h"
+
+/*
+ * Storage classes
+ */
+#define SNULL          0
+#define AUTO           1
+#define EXTERN         2
+#define STATIC         3
+#define REGISTER       4
+#define EXTDEF         5
+/* #define LABEL       6*/
+/* #define ULABEL      7*/
+#define MOS            8
+#define PARAM          9
+#define STNAME         10
+#define MOU            11
+#define UNAME          12
+#define TYPEDEF                13
+/* #define FORTRAN             14 */
+#define ENAME          15
+#define MOE            16
+/* #define UFORTRAN    17 */
+#define USTATIC                18
+#define        MAXSTCL         20
+
+       /* field size is ORed in */
+#define FIELD          0200
+#define FLDSIZ         0177
+extern char *scnames(int);
+
+/*
+ * Symbol table flags
+ */
+#define        SNORMAL         0
+#define        STAGNAME        01
+#define        SLBLNAME        02
+#define        SMOSNAME        03
+#define        SSTRING         04
+#define        NSTYPES         05
+#define        SMASK           07
+
+#define        STLS            00010   /* Thread Local Support variable */
+/* #define SREF                00020 */
+#define SNOCREAT       00040   /* don't create a symbol in lookup() */
+#define STEMP          00100   /* Allocate symtab from temp or perm mem */
+#define        SDYNARRAY       00200   /* symbol is dynamic array on stack */
+#define        SINLINE         00400   /* function is of type inline */
+#define        STNODE          01000   /* symbol shall be a temporary node */
+#define        SBUILTIN        02000   /* this is a builtin function */
+#define        SASG            04000   /* symbol is assigned to already */
+#define        SLOCAL1         010000
+#define        SLOCAL2         020000
+#define        SLOCAL3         040000
+
+       /* alignment of initialized quantities */
+#ifndef AL_INIT
+#define        AL_INIT ALINT
+#endif
+
+struct rstack;
+struct symtab;
+union arglist;
+#ifdef GCC_COMPAT
+struct gcc_attr_pack;
+#endif
+
+struct namespace;
+
+/*
+ * Dimension/prototype information.
+ *     ddim > 0 holds the dimension of an array.
+ *     ddim < 0 is a dynamic array and refers to a tempnode.
+ *     ...unless:
+ *             ddim == NOOFFSET, an array without dimenston, "[]"
+ *             ddim == -1, dynamic array while building before defid.
+ */
+union dimfun {
+       int     ddim;           /* Dimension of an array */
+       union arglist *dfun;    /* Prototype index */
+};
+
+/*
+ * Argument list member info when storing prototypes.
+ */
+union arglist {
+       TWORD type;
+       union dimfun *df;
+       struct attr *sap;
+};
+#define TNULL          INCREF(FARG) /* pointer to FARG -- impossible type */
+#define TELLIPSIS      INCREF(INCREF(FARG))
+
+/*
+ * Symbol table definition.
+ */
+struct symtab {
+       struct  symtab *snext;  /* link to other symbols in the same scope */
+       struct  symtab *sdown;  /* link to parent class */
+       struct  symtab *sup;    /* link to child class */
+       int     soffset;        /* offset or value */
+       char    sclass;         /* storage class */
+       char    slevel;         /* scope level */
+       short   sflags;         /* flags, see below */
+       char    *sname;         /* Symbol name */
+       char    *soname;        /* Written-out name */
+       TWORD   stype;          /* type word */
+       TWORD   squal;          /* qualifier word */
+       union   dimfun *sdf;    /* ptr to the dimension/prototype array */
+       struct  attr *sap;      /* the base type attribute list */
+};
+
+#define        ISSOU(ty)   ((ty) == STRTY || (ty) == UNIONTY)
+
+/*
+ * External definitions
+ */
+struct swents {                        /* switch table */
+       struct swents *next;    /* Next struct in linked list */
+       CONSZ   sval;           /* case value */
+       int     slab;           /* associated label */
+};
+int mygenswitch(int, TWORD, struct swents **, int);
+
+extern int blevel;
+extern int oldstyle;
+
+extern int lineno, nerrors;
+
+extern char *ftitle;
+extern struct symtab *cftnsp;
+extern int autooff, maxautooff, argoff;
+
+extern OFFSZ inoff;
+
+extern int reached;
+extern int isinlining;
+extern int xinline, xgnu89, xgnu99;
+extern int bdebug, ddebug, edebug, idebug, ndebug;
+extern int odebug, pdebug, sdebug, tdebug, xdebug;
+
+/* various labels */
+extern int brklab;
+extern int contlab;
+extern int flostat;
+extern int retlab;
+extern int doing_init, statinit;
+extern short sztable[];
+extern char *astypnames[];
+
+/* pragma globals */
+extern int pragma_allpacked, pragma_packed, pragma_aligned;
+extern char *pragma_renamed;
+
+/*
+ * Flags used in the (elementary) flow analysis ...
+ */
+#define FBRK           02
+#define FCONT          04
+#define FDEF           010
+#define FLOOP          020
+
+/*
+ * Location counters
+ */
+#define NOSEG          -1
+#define PROG           0               /* (ro) program segment */
+#define DATA           1               /* (rw) data segment */
+#define RDATA          2               /* (ro) data segment */
+#define LDATA          3               /* (rw) local data */
+#define UDATA          4               /* (rw) uninitialized data */
+#define STRNG          5               /* (ro) string segment */
+#define PICDATA                6               /* (rw) relocatable data segment */
+#define PICRDATA       7               /* (ro) relocatable data segment */
+#define PICLDATA       8               /* (rw) local relocatable data */
+#define TLSDATA                9               /* (rw) TLS data segment */
+#define TLSUDATA       10              /* (rw) TLS uninitialized segment */
+#define CTORS          11              /* constructor */
+#define DTORS          12              /* destructor */
+#define        NMSEG           13              /* other (named) segment */
+
+extern int lastloc;
+void locctr(int type, struct symtab *sp);
+void setseg(int type, char *name);
+void defalign(int al);
+void symdirec(struct symtab *sp);
+
+/*     mark an offset which is undefined */
+
+#define NOOFFSET       (-10201)
+
+/* declarations of various functions */
+extern NODE
+       *buildtree(int, NODE *, NODE *r),
+       *mkty(unsigned, union dimfun *, struct attr *),
+       *rstruct(char *, int),
+       *dclstruct(struct rstack *),
+       *strend(int gtype, char *),
+       *tymerge(NODE *, NODE *),
+       *stref(NODE *),
+#ifdef WORD_ADDRESSED
+       *offcon(OFFSZ, TWORD, union dimfun *, struct attr *),
+#endif
+       *bcon(int),
+       *xbcon(CONSZ, struct symtab *, TWORD),
+       *bpsize(NODE *),
+       *convert(NODE *, int),
+       *pconvert(NODE *),
+       *oconvert(NODE *),
+       *ptmatch(NODE *),
+       *makety(NODE *, TWORD, TWORD, union dimfun *, struct attr *),
+       *block(int, NODE *, NODE *, TWORD, union dimfun *, struct attr *),
+       *doszof(NODE *),
+       *talloc(void),
+       *optim(NODE *),
+       *clocal(NODE *),
+       *ccopy(NODE *),
+       *tempnode(int, TWORD, union dimfun *, struct attr *),
+       *eve(NODE *),
+       *doacall(struct symtab *, NODE *, NODE *, int);
+NODE   *intprom(NODE *);
+OFFSZ  tsize(TWORD, union dimfun *, struct attr *),
+       psize(NODE *);
+NODE * typenode(NODE *new);
+void   spalloc(NODE *, NODE *, OFFSZ);
+char   *exname(char *);
+NODE   *floatcon(char *);
+NODE   *fhexcon(char *);
+NODE   *bdty(int op, ...);
+extern struct rstack *rpole;
+
+int oalloc(struct symtab *, int *);
+void deflabel(char *, NODE *);
+void gotolabel(char *);
+unsigned int esccon(char **);
+void inline_start(struct symtab *);
+void inline_end(void);
+void inline_addarg(struct interpass *);
+void inline_ref(struct symtab *);
+void inline_prtout(void);
+void inline_args(struct symtab **, int);
+NODE *inlinetree(struct symtab *, NODE *, NODE *);
+void ftnarg(NODE *);
+struct rstack *bstruct(char *, int, NODE *);
+void moedef(char *);
+void beginit(struct symtab *);
+void simpleinit(struct symtab *, NODE *);
+struct symtab *lookup(char *, int);
+struct symtab *getsymtab(char *, int);
+char *addstring(char *);
+char *addname(char *);
+void symclear(int);
+struct symtab *hide(struct symtab *);
+void soumemb(NODE *, char *, int);
+int talign(unsigned int, struct attr *);
+void bfcode(struct symtab **, int);
+int chkftn(union arglist *, union arglist *);
+void branch(int);
+void cbranch(NODE *, NODE *);
+void extdec(struct symtab *);
+void defzero(struct symtab *);
+int falloc(struct symtab *, int, NODE *);
+TWORD ctype(TWORD);  
+void inval(CONSZ, int, NODE *);
+int ninval(CONSZ, int, NODE *);
+void infld(CONSZ, int, CONSZ);
+void zbits(CONSZ, int);
+void instring(struct symtab *);
+void inwstring(struct symtab *);
+void plabel(int);
+void bjobcode(void);
+void ejobcode(int);
+void calldec(NODE *, NODE *);
+int cisreg(TWORD);
+void asginit(NODE *);
+void desinit(NODE *);
+void endinit(int);
+void endictx(void);
+void sspinit(void);
+void sspstart(void);
+void sspend(void);
+void ilbrace(void);
+void irbrace(void);
+CONSZ scalinit(NODE *);
+void p1print(char *, ...);
+char *copst(int);
+int cdope(int);
+void myp2tree(NODE *);
+void lcommprint(void);
+void lcommdel(struct symtab *);
+NODE *funcode(NODE *);
+struct symtab *enumhd(char *);
+NODE *enumdcl(struct symtab *);
+NODE *enumref(char *);
+CONSZ icons(NODE *);
+CONSZ valcast(CONSZ v, TWORD t);
+int mypragma(char *);
+char *pragtok(char *);
+int eat(int);
+void fixdef(struct symtab *);
+int cqual(TWORD, TWORD);
+void defloc(struct symtab *);
+int fldchk(int);
+int nncon(NODE *);
+void cunput(char);
+NODE *nametree(struct symtab *sp);
+void *inlalloc(int size);
+void *blkalloc(int size);
+void pass1_lastchance(struct interpass *);
+void fldty(struct symtab *p);
+int getlab(void);
+struct suedef *sueget(struct suedef *p);
+void complinit(void);
+NODE *structref(NODE *p, int f, char *name);
+NODE *cxop(int op, NODE *l, NODE *r);
+NODE *imop(int op, NODE *l, NODE *r);
+NODE *cxelem(int op, NODE *p);
+NODE *cxconj(NODE *p);
+NODE *cxret(NODE *p, NODE *q);
+NODE *cast(NODE *p, TWORD t, TWORD q);
+NODE *ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue);
+int andable(NODE *);
+int conval(NODE *, int, NODE *);
+int ispow2(CONSZ);
+void defid(NODE *q, int class);
+void efcode(void);
+void ecomp(NODE *p);
+int upoff(int size, int alignment, int *poff);
+void nidcl(NODE *p, int class);
+void eprint(NODE *, int, int *, int *);
+int uclass(int class);
+int notlval(NODE *);
+void ecode(NODE *p);
+void ftnend(void);
+void dclargs(void);
+int suemeq(struct attr *s1, struct attr *s2);
+struct symtab *strmemb(struct attr *ap);
+int yylex(void);
+void yyerror(char *);
+int pragmas_gcc(char *t);
+NODE *cstknode(TWORD t, union dimfun *df, struct attr *ap);
+int concast(NODE *p, TWORD t);
+#ifdef WORD_ADDRESSED
+#define rmpconv(p) (p)
+#else
+NODE *rmpconv(NODE *);
+#endif
+NODE *nlabel(int label);
+int isbuiltin(char *n);
+char *getexname(struct symtab *);
+
+enum { ATTR_FIRST = ATTR_MI_MAX + 1,
+
+       /* PCC used attributes */
+       ATTR_COMPLEX,   /* Internal definition of complex */
+       xxxATTR_BASETYP,        /* Internal; see below */
+       ATTR_QUALTYP,   /* Internal; const/volatile, see below */
+       ATTR_ALIGNED,
+       ATTR_STRUCT,    /* Internal; element list */
+#define        ATTR_MAX ATTR_STRUCT
+
+       ATTR_SONAME,
+
+#ifdef GCC_COMPAT
+       /* type attributes */
+       GCC_ATYP_PACKED,
+       GCC_ATYP_SECTION,
+       GCC_ATYP_TRANSP_UNION,
+       GCC_ATYP_UNUSED,
+       GCC_ATYP_DEPRECATED,
+       GCC_ATYP_MAYALIAS,
+
+       /* variable attributes */
+       GCC_ATYP_MODE,
+
+       /* function attributes */
+       GCC_ATYP_NORETURN,
+       GCC_ATYP_FORMAT,
+       GCC_ATYP_NONNULL,
+       GCC_ATYP_SENTINEL,
+       GCC_ATYP_WEAK,
+       GCC_ATYP_FORMATARG,
+       GCC_ATYP_GNU_INLINE,
+       GCC_ATYP_MALLOC,
+       GCC_ATYP_NOTHROW,
+       GCC_ATYP_CONST,
+       GCC_ATYP_PURE,
+       GCC_ATYP_CONSTRUCTOR,
+       GCC_ATYP_DESTRUCTOR,
+       GCC_ATYP_VISIBILITY,
+       GCC_ATYP_WARN_UNUSED_RESULT,
+       GCC_ATYP_USED,
+       GCC_ATYP_NO_INSTR_FUN,
+       GCC_ATYP_NOINLINE,
+       GCC_ATYP_ALIAS,
+       GCC_ATYP_WEAKREF,
+       GCC_ATYP_ALLOCSZ,
+       GCC_ATYP_ALW_INL,
+       GCC_ATYP_TLSMODEL,
+       GCC_ATYP_ALIASWEAK,
+       GCC_ATYP_REGPARM,
+       GCC_ATYP_FASTCALL,
+
+       /* other stuff */
+       GCC_ATYP_BOUNDED,       /* OpenBSD extra boundary checks */
+
+       GCC_ATYP_MAX,
+#endif
+#ifdef ATTR_P1_TARGET
+       ATTR_P1_TARGET,
+#endif
+       ATTR_P1_MAX
+
+};
+
+struct flt {
+       long double fp;
+};
+typedef struct flt FLT;
+extern FLT flt_zero;
+#define        fltallo()       tmpalloc(sizeof(FLT))
+#define        FCAST(x)        ((FLT *)x)
+
+#define FLOAT_ZERO              (&flt_zero)
+#define FLOAT_PLUS(p1,p2)       (FCAST((p1)->n_dcon)->fp += FCAST((p2)->n_dcon)->fp)
+#define FLOAT_MINUS(p1,p2)      (FCAST((p1)->n_dcon)->fp -= FCAST((p2)->n_dcon)->fp)
+#define FLOAT_MUL(p1,p2)        (FCAST((p1)->n_dcon)->fp *= FCAST((p2)->n_dcon)->fp)
+#define FLOAT_DIV(p1,p2)        (FCAST((p1)->n_dcon)->fp /= FCAST((p2)->n_dcon)->fp)
+#define FLOAT_ISZERO(p)         ((p)->fp == 0.0)
+#define FLOAT_FP2FP(f,t)        (f->fp = (t == FLOAT ? (float)f->fp :   \
+        t == DOUBLE ? (double)f->fp : f->fp))
+#define FLOAT_INT2FP(d,p,v)     (ISUNSIGNED(v) ? \
+        (d->fp = (long double)(U_CONSZ)(p)) : (d->fp = (long double)(CONSZ)(p)))
+#define FLOAT_FP2INT(i,d,t)     (ISUNSIGNED(t) ? \
+        (i = (U_CONSZ)(d->fp)) : (i = d->fp))
+#define FLOAT_EQ(d1,d2)         (d1->fp == d2->fp)
+#define FLOAT_NE(d1,d2)         (d1->fp != d2->fp)
+#define FLOAT_GE(d1,d2)         (d1->fp >= d2->fp)
+#define FLOAT_GT(d1,d2)         (d1->fp > d2->fp)
+#define FLOAT_LE(d1,d2)         (d1->fp <= d2->fp)
+#define FLOAT_LT(d1,d2)         (d1->fp < d2->fp)
+#define FLOAT_NEG(p)            (p->fp = -p->fp)
+#define FLOAT_SETZERO(d)        (d)->fp = FLOAT_ZERO
+
+
+/*
+#ifdef notdef
+ * ATTR_BASETYP has the following layout:
+ * aa[0].iarg has size
+ * aa[1].iarg has alignment
+#endif
+ * ATTR_QUALTYP has the following layout:
+ * aa[0].iarg has CON/VOL + FUN/ARY/PTR
+ * Not defined yet...
+ * aa[3].iarg is dimension for arrays (XXX future)
+ * aa[3].varg is function defs for functions.
+ */
+#ifdef notdef
+#define        atypsz  aa[0].iarg
+#define        aalign  aa[1].iarg
+#endif
+
+/*
+ * ATTR_STRUCT member list.
+ */
+#define amlist  aa[0].varg
+#define amsize  aa[1].iarg
+#define        strattr(x)      (attr_find(x, ATTR_STRUCT))
+
+#define        iarg(x) aa[x].iarg
+#define        sarg(x) aa[x].sarg
+#define        varg(x) aa[x].varg
+
+void gcc_init(void);
+int gcc_keyword(char *, NODE **);
+struct attr *gcc_attr_parse(NODE *);
+void gcc_tcattrfix(NODE *);
+struct gcc_attrib *gcc_get_attr(struct suedef *, int);
+void dump_attr(struct attr *gap);
+
+#ifndef NO_C_BUILTINS
+struct bitable {
+       char *name;
+       NODE *(*fun)(const struct bitable *, NODE *a);
+       short flags;
+#define        BTNOPROTO       001
+#define        BTNORVAL        002
+#define        BTNOEVE         004
+       short narg;
+       TWORD *tp;
+       TWORD rt;
+};
+
+NODE *builtin_check(struct symtab *, NODE *a);
+void builtin_init(void);
+
+/* Some builtins targets need to implement */
+NODE *builtin_frame_address(const struct bitable *bt, NODE *a);
+NODE *builtin_return_address(const struct bitable *bt, NODE *a);
+NODE *builtin_cfa(const struct bitable *bt, NODE *a);
+#endif
+
+
+#ifdef STABS
+void stabs_init(void);
+void stabs_file(char *);
+void stabs_efile(char *);
+void stabs_line(int);
+void stabs_rbrac(int);
+void stabs_lbrac(int);
+void stabs_func(struct symtab *);
+void stabs_newsym(struct symtab *);
+void stabs_chgsym(struct symtab *);
+void stabs_struct(struct symtab *, struct attr *);
+#endif
+
+#ifndef CHARCAST
+/* to make character constants into character connstants */
+/* this is a macro to defend against cross-compilers, etc. */
+#define CHARCAST(x) (char)(x)
+#endif
+
+/* sometimes int is smaller than pointers */
+#if SZPOINT(CHAR) <= SZINT
+#define INTPTR  INT
+#elif SZPOINT(CHAR) <= SZLONG
+#define INTPTR  LONG
+#elif SZPOINT(CHAR) <= SZLONGLONG
+#define INTPTR  LONGLONG
+#else
+#error int size unknown
+#endif
+
+#ifdef TWOPASS
+#define PRTPREF "* "  
+#else
+#define PRTPREF "" 
+#endif 
+
+/* Generate a bitmask from a given type size */
+#define SZMASK(y) ((((1LL << ((y)-1))-1) << 1) | 1)
+
+/*
+ * C compiler first pass extra defines.
+ */
+#define        QUALIFIER       (MAXOP+1)
+#define        CLASS           (MAXOP+2)
+#define        RB              (MAXOP+3)
+#define        DOT             (MAXOP+4)
+#define        ELLIPSIS        (MAXOP+5)
+#define        TYPE            (MAXOP+6)
+#define        LB              (MAXOP+7)
+#define        COMOP           (MAXOP+8)
+#define        QUEST           (MAXOP+9)
+#define        COLON           (MAXOP+10)
+#define        ANDAND          (MAXOP+11)
+#define        OROR            (MAXOP+12)
+#define        NOT             (MAXOP+13)
+#define        CAST            (MAXOP+14)
+#define        STRING          (MAXOP+15)
+
+/* The following must be in the same order as their NOASG counterparts */
+#define        PLUSEQ          (MAXOP+16)
+#define        MINUSEQ         (MAXOP+17)
+#define        DIVEQ           (MAXOP+18)
+#define        MODEQ           (MAXOP+19)
+#define        MULEQ           (MAXOP+20)
+#define        ANDEQ           (MAXOP+21)
+#define        OREQ            (MAXOP+22)
+#define        EREQ            (MAXOP+23)
+#define        LSEQ            (MAXOP+24)
+#define        RSEQ            (MAXOP+25)
+
+#define        UNASG           (-(PLUSEQ-PLUS))+
+
+#define INCR           (MAXOP+26)
+#define DECR           (MAXOP+27)
+#define SZOF           (MAXOP+28)
+#define CLOP           (MAXOP+29)
+#define ATTRIB         (MAXOP+30)
+#define XREAL          (MAXOP+31)
+#define XIMAG          (MAXOP+32)
+#define TYMERGE                (MAXOP+33)
+#define LABEL          (MAXOP+34)
+#define STREF          (MAXOP+35)
+
+/*
+ * The following types are only used in pass1.
+ */
+#define SIGNED         (MAXTYPES+1)
+#define FARG           (MAXTYPES+2)
+#define        FIMAG           (MAXTYPES+3)
+#define        IMAG            (MAXTYPES+4)
+#define        LIMAG           (MAXTYPES+5)
+#define        FCOMPLEX        (MAXTYPES+6)
+#define        COMPLEX         (MAXTYPES+7)
+#define        LCOMPLEX        (MAXTYPES+8)
+#define        ENUMTY          (MAXTYPES+9)
+
+#define        ISFTY(x)        ((x) >= FLOAT && (x) <= LDOUBLE)
+#define        ISCTY(x)        ((x) >= FCOMPLEX && (x) <= LCOMPLEX)
+#define        ISITY(x)        ((x) >= FIMAG && (x) <= LIMAG)
+#define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX))
+
+#define coptype(o)     (cdope(o)&TYFLG)
+#define clogop(o)      (cdope(o)&LOGFLG)
+#define casgop(o)      (cdope(o)&ASGFLG)
+
+#define        slval   setlval
+#define        glval   getlval
+
+#include <cxxdefs.h>
+
diff --git a/lang/pcc/pcc/cc/cxxcom/pftn.c b/lang/pcc/pcc/cc/cxxcom/pftn.c
new file mode 100644 (file)
index 0000000..2e73c90
--- /dev/null
@@ -0,0 +1,3325 @@
+/*     $Id: pftn.c,v 1.16 2016/03/05 15:31:25 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Many changes from the 32V sources, among them:
+ * - New symbol table manager (moved to another file).
+ * - Prototype saving/checks.
+ */
+
+# include "pass1.h"
+
+#include "cgram.h"
+
+struct symtab *cftnsp;
+int arglistcnt, dimfuncnt;     /* statistics */
+int symtabcnt, suedefcnt;      /* statistics */
+int autooff,           /* the next unused automatic offset */
+    maxautooff,                /* highest used automatic offset in function */
+    argoff;            /* the next unused argument offset */
+int retlab = NOLAB;    /* return label for subroutine */
+int brklab;
+int contlab;
+int flostat;
+int blevel;
+int reached, prolab;
+
+struct params;
+
+#define MKTY(p, t, d, s) r = talloc(); *r = *p; \
+       r = argcast(r, t, d, s); *p = *r; nfree(r);
+
+/*
+ * Linked list stack while reading in structs.
+ */
+struct rstack {
+       struct  rstack *rnext;
+       int     rsou;
+       int     rstr;
+       struct  symtab *rsym;
+//     struct  symtab *rb;
+       struct  attr *ap;
+       int     flags;
+#define        LASTELM 1
+} *rpole;
+
+/*
+ * Linked list for parameter (and struct elements) declaration.
+ */
+static struct params {
+       struct params *prev;
+       struct symtab *sym;
+} *lparam;
+static int nparams;
+
+/* defines used for getting things off of the initialization stack */
+
+NODE *arrstk[10];
+int arrstkp;
+static int intcompare;
+NODE *parlink;
+
+void fixtype(NODE *p, int class);
+int fixclass(int class, TWORD type);
+static void dynalloc(struct symtab *p, int *poff);
+static void evalidx(struct symtab *p);
+int isdyn(struct symtab *p);
+void inforce(OFFSZ n);
+void vfdalign(int n);
+static void ssave(struct symtab *);
+#ifdef PCC_DEBUG
+static void alprint(union arglist *al, int in);
+#endif
+static void lcommadd(struct symtab *sp);
+static NODE *mkcmplx(NODE *p, TWORD dt);
+extern int fun_inline;
+
+FLT flt_zero = { .fp = 0.0, };
+
+/*
+ * Declaration of an identifier.  Handles redeclarations, hiding,
+ * incomplete types and forward declarations.
+ *
+ * q is a TYPE node setup after parsing with n_type, n_df and n_ap.
+ * n_sp is a pointer to the not-yet initalized symbol table entry
+ * unless it's a redeclaration or supposed to hide a variable.
+ */
+
+void
+defid(NODE *q, int class)
+{
+       struct attr *ap;
+       struct symtab *p;
+       TWORD type, qual;
+       TWORD stp, stq;
+       int scl;
+       union dimfun *dsym, *ddef;
+       int slev, temp, changed;
+
+       if (q == NIL)
+               return;  /* an error was detected */
+
+       p = q->n_sp;
+
+       if (p->sname == NULL)
+               cerror("defining null identifier");
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("defid(%s (%p), ", p->sname, p);
+               tprint(q->n_type, q->n_qual);
+               printf(", %s, (%p)), level %d\n\t", scnames(class),
+                   q->n_df, blevel);
+#ifdef GCC_COMPAT
+               dump_attr(q->n_ap);
+#endif
+       }
+#endif
+
+       fixtype(q, class);
+
+       type = q->n_type;
+       qual = q->n_qual;
+       class = fixclass(class, type);
+
+       stp = p->stype;
+       stq = p->squal;
+       slev = p->slevel;
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("        modified to ");
+               tprint(type, qual);
+               printf(", %s\n", scnames(class));
+               printf("        previous def'n: ");
+               tprint(stp, stq);
+               printf(", %s, (%p,%p)), level %d\n",
+                   scnames(p->sclass), p->sdf, p->sap, slev);
+       }
+#endif
+
+       if (blevel == 1) {
+               switch (class) {
+               default:
+                       if (!(class&FIELD) && !ISFTN(type))
+                               uerror("declared argument %s missing",
+                                   p->sname );
+               case MOS:
+               case MOU:
+                       cerror("field5");
+               case TYPEDEF:
+               case PARAM:
+                       ;
+               }
+       }
+
+       if (stp == UNDEF)
+               goto enter; /* New symbol */
+
+       if (type != stp)
+               goto mismatch;
+
+       if (blevel > slev && (class == AUTO || class == REGISTER))
+               /* new scope */
+               goto mismatch;
+
+       /*
+        * test (and possibly adjust) dimensions.
+        * also check that prototypes are correct.
+        */
+       dsym = p->sdf;
+       ddef = q->n_df;
+       changed = 0;
+       for (temp = type; temp & TMASK; temp = DECREF(temp)) {
+               if (ISARY(temp)) {
+                       if (dsym->ddim == NOOFFSET) {
+                               dsym->ddim = ddef->ddim;
+                               changed = 1;
+                       } else if (ddef->ddim != NOOFFSET &&
+                           dsym->ddim!=ddef->ddim) {
+                               goto mismatch;
+                       }
+                       ++dsym;
+                       ++ddef;
+               } else if (ISFTN(temp)) {
+                       /* add a late-defined prototype here */
+                       if (cftnsp == NULL && dsym->dfun == NULL)
+                               dsym->dfun = ddef->dfun;
+                       if (!oldstyle && ddef->dfun != NULL &&
+                           chkftn(dsym->dfun, ddef->dfun))
+                               uerror("declaration doesn't match prototype");
+                       dsym++, ddef++;
+               }
+       }
+#ifdef STABS
+       if (changed && gflag)
+               stabs_chgsym(p); /* symbol changed */
+#endif
+
+       /* check that redeclarations are to the same structure */
+       if (temp == STRTY || temp == UNIONTY) {
+               if (strmemb(p->sap) != strmemb(q->n_ap))
+                       goto mismatch;
+       }
+
+       scl = p->sclass;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("        previous class: %s\n", scnames(scl));
+#endif
+
+       /*
+        * Its allowed to add attributes to existing declarations.
+        * Be careful though not to trash existing attributes.
+        * XXX - code below is probably not correct.
+        */
+       if (p->sap && p->sap->atype <= ATTR_MAX) {
+               /* nothing special, just overwrite */
+               p->sap = q->n_ap;
+       } else {
+               if (p->slevel == blevel) {
+                       for (ap = q->n_ap; ap; ap = ap->next) {
+                               if (ap->atype > ATTR_MAX)
+                                       p->sap = attr_add(p->sap, attr_dup(ap));
+                       }
+               } else
+                       p->sap = q->n_ap;
+       }
+
+       if (class & FIELD)
+               cerror("field1");
+       switch(class) {
+
+       case EXTERN:
+               if (pragma_renamed)
+                       p->soname = pragma_renamed;
+               pragma_renamed = NULL;
+               switch( scl ){
+               case STATIC:
+               case USTATIC:
+                       if( slev==0 )
+                               goto done;
+                       break;
+               case EXTDEF:
+               case EXTERN:
+                       goto done;
+               case SNULL:
+                       if (p->sflags & SINLINE) {
+                               p->sclass = EXTDEF;
+                               inline_ref(p);
+                               goto done;
+                       }
+                       break;
+               }
+               break;
+
+       case STATIC:
+               if (scl==USTATIC || (scl==EXTERN && blevel==0)) {
+                       p->sclass = STATIC;
+                       goto done;
+               }
+               if (changed || (scl == STATIC && blevel == slev))
+                       goto done; /* identical redeclaration */
+               break;
+
+       case USTATIC:
+               if (scl==STATIC || scl==USTATIC)
+                       goto done;
+               break;
+
+       case TYPEDEF:
+               if (scl == class)
+                       goto done;
+               break;
+
+       case MOU:
+       case MOS:
+               cerror("field6");
+
+       case EXTDEF:
+               switch (scl) {
+               case EXTERN:
+                       p->sclass = EXTDEF;
+                       goto done;
+               case USTATIC:
+                       p->sclass = STATIC;
+                       goto done;
+               case SNULL:
+                       /*
+                        * Handle redeclarations of inlined functions.
+                        * This is allowed if the previous declaration is of
+                        * type gnu_inline.
+                        */
+#ifdef GCC_COMPAT
+                       if (attr_find(p->sap, GCC_ATYP_GNU_INLINE))
+                               goto done;
+#endif
+                       break;
+               }
+               break;
+
+       case AUTO:
+       case REGISTER:
+               break;  /* mismatch.. */
+       case SNULL:
+               if (fun_inline && ISFTN(type))
+                       goto done;
+               break;
+       }
+
+       mismatch:
+
+       /*
+        * Only allowed for automatic variables.
+        */
+       if (blevel <= slev || class == EXTERN) {
+               uerror("redeclaration of %s", p->sname);
+               return;
+       }
+       q->n_sp = p = hide(p);
+
+       enter:  /* make a new entry */
+
+#ifdef PCC_DEBUG
+       if(ddebug)
+               printf("        new entry made\n");
+#endif
+#ifdef GCC_COMPAT
+       if (type < BTMASK && (ap = attr_find(q->n_ap, GCC_ATYP_MODE))) {
+               type = ENUNSIGN(ap->iarg(0));
+               if (type == XTYPE)
+                       uerror("fix XTYPE basetyp");
+       }
+#endif
+       p->stype = type;
+       p->squal = qual;
+       p->sclass = (char)class;
+       p->slevel = (char)blevel;
+       p->soffset = NOOFFSET;
+#if 0
+       if (class != TYPEDEF && blevel == 0)
+               p->soname = decoratename(p, NM_NORMAL);
+#endif
+       if (q->n_ap)
+               p->sap = attr_add(q->n_ap, p->sap);
+
+       /* copy dimensions */
+       p->sdf = q->n_df;
+       /* Do not save param info for old-style functions */
+       if (ISFTN(type) && oldstyle)
+               p->sdf->dfun = NULL;
+
+       if (arrstkp)
+               evalidx(p);
+
+       /* allocate offsets */
+       if (class&FIELD) {
+               cerror("field2");  /* new entry */
+       } else switch (class) {
+
+       case REGISTER:
+               cerror("register var");
+
+       case AUTO:
+               if (isdyn(p)) {
+                       p->sflags |= SDYNARRAY;
+                       dynalloc(p, &autooff);
+               } else
+                       oalloc(p, &autooff);
+               break;
+
+       case PARAM:
+               if (q->n_type != FARG)
+                       oalloc(p, &argoff);
+               break;
+               
+       case STATIC:
+       case EXTDEF:
+       case EXTERN:
+               p->soffset = getlab();
+               if (pragma_renamed)
+                       p->soname = pragma_renamed;
+               pragma_renamed = NULL;
+               break;
+
+       case MOU:
+       case MOS:
+               cerror("field7");
+       case SNULL:
+#ifdef notdef
+               if (fun_inline) {
+                       p->slevel = 1;
+                       p->soffset = getlab();
+               }
+#endif
+               break;
+       }
+
+#ifdef STABS
+       if (gflag && p->stype != FARG)
+               stabs_newsym(p);
+#endif
+
+done:
+       cxxsetname(p);
+       fixdef(p);      /* Leave last word to target */
+#ifndef HAVE_WEAKREF
+       {
+               struct attr *at;
+
+               /* Refer renamed function */
+               if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF)))
+                       p->soname = at->sarg(0);
+       }
+#endif
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf( "       sdf, offset: %p, %d\n\t",
+                   p->sdf, p->soffset);
+#ifdef GCC_COMPAT
+               dump_attr(p->sap);
+#endif
+       }
+#endif
+}
+
+void
+ssave(struct symtab *sym)
+{
+       struct params *p;
+
+       p = tmpalloc(sizeof(struct params));
+       p->prev = lparam;
+       p->sym = sym;
+       lparam = p;
+}
+
+/*
+ * end of function
+ */
+void
+ftnend(void)
+{
+#ifdef GCC_COMPAT
+       struct attr *gc, *gd;
+#endif
+       extern NODE *cftnod;
+       extern struct savbc *savbc;
+       extern struct swdef *swpole;
+       extern int tvaloff;
+       char *c;
+
+       if (retlab != NOLAB && nerrors == 0) { /* inside a real function */
+               plabel(retlab);
+               if (cftnod)
+                       ecomp(buildtree(FORCE, cftnod, NIL));
+               efcode(); /* struct return handled here */
+               if ((c = cftnsp->soname) == NULL)
+                       c = addname(exname(cftnsp->sname));
+               SETOFF(maxautooff, ALCHAR);
+               send_passt(IP_EPILOG, maxautooff/SZCHAR, c,
+                   cftnsp->stype, cftnsp->sclass == EXTDEF, retlab, tvaloff);
+       }
+
+       cftnod = NIL;
+       tcheck();
+       brklab = contlab = retlab = NOLAB;
+       flostat = 0;
+       if (nerrors == 0) {
+               if (savbc != NULL)
+                       cerror("bcsave error");
+               if (lparam != NULL)
+                       cerror("parameter reset error");
+               if (swpole != NULL)
+                       cerror("switch error");
+       }
+#ifdef GCC_COMPAT
+       if (cftnsp) {
+               gc = attr_find(cftnsp->sap, GCC_ATYP_CONSTRUCTOR);
+               gd = attr_find(cftnsp->sap, GCC_ATYP_DESTRUCTOR);
+               if (gc || gd) {
+                       struct symtab sts = *cftnsp;
+                       NODE *p;
+                       sts.stype = INCREF(sts.stype);
+                       p = nametree(&sts);
+                       p->n_op = ICON;
+                       if (gc) {
+                               locctr(CTORS, &sts);
+                               inval(0, SZPOINT(0), p);
+                       }
+                       if (gd) {
+                               locctr(DTORS, &sts);
+                               inval(0, SZPOINT(0), p);
+                       }
+                       tfree(p);
+               }
+       }
+#endif
+       savbc = NULL;
+       lparam = NULL;
+       cftnsp = NULL;
+       maxautooff = autooff = AUTOINIT;
+       reached = 1;
+
+       if (isinlining)
+               inline_end();
+       inline_prtout();
+
+       tmpfree(); /* Release memory resources */
+}
+
+static struct symtab nulsym = {
+       NULL, NULL, NULL, 0, 0, 0, 0, "null", "null", INT, 0, NULL, NULL
+};
+
+void
+dclargs(void)
+{
+       union dimfun *df;
+       union arglist *al, *al2, *alb;
+       struct params *a;
+       struct symtab *p, **parr = NULL; /* XXX gcc */
+       int i;
+
+       /*
+        * Deal with fun(void) properly.
+        */
+       if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID)
+               goto done;
+
+       if (cftnsp->sdown && cftnsp->sdown->sclass != NSPACE) {
+               /* first arg is a pointer to the "sprev" class */
+               p = cxxstrvar(cftnsp->sdown);
+               ssave(p);
+               nparams++;
+       }
+       /*
+        * Generate a list for bfcode().
+        * Parameters were pushed in reverse order.
+        */
+       if (nparams != 0)
+               parr = tmpalloc(sizeof(struct symtab *) * nparams);
+
+       if (nparams)
+           for (a = lparam, i = 0; a != NULL; a = a->prev) {
+               p = a->sym;
+               parr[i++] = p;
+               if (p == NULL) {
+                       uerror("parameter %d name missing", i);
+                       p = &nulsym; /* empty symtab */
+               }
+               if (p->stype == FARG)
+                       p->stype = INT;
+               if (ISARY(p->stype)) {
+                       p->stype += (PTR-ARY);
+                       p->sdf++;
+               } else if (ISFTN(p->stype)) {
+                       werror("function declared as argument");
+                       p->stype = INCREF(p->stype);
+               }
+#ifdef STABS
+               if (gflag)
+                       stabs_newsym(p);
+#endif
+       }
+       if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) {
+               /*
+                * Check against prototype of oldstyle function.
+                */
+               alb = al2 = tmpalloc(sizeof(union arglist) * nparams * 3 + 1);
+               for (i = 0; i < nparams; i++) {
+                       TWORD type = parr[i]->stype;
+                       (al2++)->type = type;
+                       if (ISSOU(BTYPE(type)))
+                               (al2++)->sap = parr[i]->sap;
+                       while (!ISFTN(type) && !ISARY(type) && type > BTMASK)
+                               type = DECREF(type);
+                       if (type > BTMASK)
+                               (al2++)->df = parr[i]->sdf;
+               }
+               al2->type = TNULL;
+               intcompare = 1;
+               if (chkftn(al, alb))
+                       uerror("function doesn't match prototype");
+               intcompare = 0;
+
+       }
+
+       if (oldstyle && nparams) {
+               /* Must recalculate offset for oldstyle args here */
+               argoff = ARGINIT;
+               for (i = 0; i < nparams; i++) {
+                       parr[i]->soffset = NOOFFSET;
+                       oalloc(parr[i], &argoff);
+               }
+       }
+
+done:  autooff = AUTOINIT;
+
+       plabel(prolab); /* after prolog, used in optimization */
+       retlab = getlab();
+       bfcode(parr, nparams);
+       if (fun_inline && (xinline
+#ifdef GCC_COMPAT
+           || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL)
+#endif
+               ))
+               inline_args(parr, nparams);
+       plabel(getlab()); /* used when spilling */
+       if (parlink)
+               ecomp(parlink);
+       parlink = NIL;
+       lparam = NULL;
+       nparams = 0;
+       symclear(1);    /* In case of function pointer args */
+}
+
+/*
+ * basic attributes for structs and enums
+ */
+static struct attr *
+seattr(void)
+{
+       return attr_add(attr_new(ATTR_ALIGNED, 4), attr_new(ATTR_STRUCT, 2));
+}
+
+/*
+ * Struct/union/enum symtab construction.
+ */
+static void
+defstr(struct symtab *sp, int class)
+{
+       sp->sclass = (char)class;
+       if (class == STNAME || class == CLNAME)
+               sp->stype = STRTY;
+       else if (class == UNAME)
+               sp->stype = UNIONTY;
+       else if (class == ENAME)
+               sp->stype = ENUMTY;
+}
+
+/*
+ * Declare a struct/union/enum tag.
+ * If not found, create a new tag with UNDEF type.
+ */
+static struct symtab *
+deftag(char *name, int class)
+{
+       struct symtab *sp;
+
+       if ((sp = cxxdclstr(name))->sap == NULL) {
+               /* New tag */
+               defstr(sp, class);
+       } else if (sp->sclass != class)
+               uerror("tag %s redeclared", name);
+       return sp;
+}
+
+/*
+ * reference to a structure or union, with no definition
+ */
+NODE *
+rstruct(char *tag, int soru)
+{
+       struct symtab *sp;
+
+       sp = deftag(tag, soru);
+       if (sp->sap == NULL)
+               sp->sap = seattr();
+       return mkty(sp->stype, 0, sp->sap);
+}
+
+static int enumlow, enumhigh;
+int enummer;
+
+/*
+ * Declare a member of enum.
+ */
+void
+moedef(char *name)
+{
+       struct symtab *sp;
+
+       sp = lookup(name, SNORMAL);
+       if (sp->stype == UNDEF || (sp->slevel < blevel)) {
+               if (sp->stype != UNDEF)
+                       sp = hide(sp);
+               sp->stype = INT; /* always */
+               sp->sclass = MOE;
+               sp->soffset = enummer;
+       } else
+               uerror("%s redeclared", name);
+       if (enummer < enumlow)
+               enumlow = enummer;
+       if (enummer > enumhigh)
+               enumhigh = enummer;
+       enummer++;
+}
+
+/*
+ * Declare an enum tag.  Complain if already defined.
+ */
+struct symtab *
+enumhd(char *name)
+{
+       struct attr *ap;
+       struct symtab *sp;
+
+       enummer = enumlow = enumhigh = 0;
+       if (name == NULL)
+               return NULL;
+
+       sp = deftag(name, ENAME);
+       if (sp->stype != ENUMTY) {
+               if (sp->slevel == blevel)
+                       uerror("%s redeclared", name);
+               sp = hide(sp);
+               defstr(sp, ENAME);
+       }
+       if (sp->sap == NULL)
+               ap = sp->sap = attr_new(ATTR_STRUCT, 4);
+       else
+               ap = attr_find(sp->sap, ATTR_STRUCT);
+       ap->amlist = sp;
+       return sp;
+}
+
+/*
+ * finish declaration of an enum
+ */
+NODE *
+enumdcl(struct symtab *sp)
+{
+       NODE *p;
+       TWORD t;
+
+#ifdef ENUMSIZE
+       t = ENUMSIZE(enumhigh, enumlow);
+#else
+       t = ctype(enumlow < 0 ? INT : UNSIGNED);
+#ifdef notdef
+       if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR)
+               t = ctype(CHAR);
+       else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT)
+               t = ctype(SHORT);
+       else
+               t = ctype(INT);
+#endif
+#endif
+       
+       if (sp)
+               sp->stype = t;
+       p = mkty(t, 0, 0);
+       p->n_sp = sp;
+       return p;
+}
+
+/*
+ * Handle reference to an enum
+ */
+NODE *
+enumref(char *name)
+{
+       struct symtab *sp;
+       NODE *p;
+
+       sp = lookup(name, STAGNAME);
+
+#ifdef notdef
+       /*
+        * 6.7.2.3 Clause 2:
+        * "A type specifier of the form 'enum identifier' without an
+        *  enumerator list shall only appear after the type it specifies
+        *  is complete."
+        */
+       if (sp->sclass != ENAME)
+               uerror("enum %s undeclared", name);
+#endif
+       if (sp->sclass == SNULL) {
+               /* declare existence of enum */
+               sp = enumhd(name);
+               sp->stype = ENUMTY;
+       }
+
+       p = mkty(sp->stype, 0, sp->sap);
+       p->n_sp = sp;
+       return p;
+}
+
+/*
+ * begining of structure or union declaration
+ * It's an error if this routine is called twice with the same struct.
+ */
+struct rstack *
+bstruct(char *name, int soru, NODE *gp)
+{
+       struct rstack *r;
+       struct symtab *sp;
+       struct attr *ap, *gap;
+       char nbuf[20];
+
+#ifdef GCC_COMPAT
+       gap = gp ? gcc_attr_parse(gp) : NULL;
+#else
+       gap = NULL;
+#endif
+
+       if (name == NULL) {
+               static int ancnt;
+               snprintf(nbuf, sizeof(nbuf), "__%%ANON%d", ancnt++);
+               name = addname(nbuf);
+       }
+
+       if (name != NULL) {
+               sp = deftag(name, soru);
+               if (sp->sap == NULL)
+                       sp->sap = seattr();
+               ap = attr_find(sp->sap, ATTR_ALIGNED);
+               if (ap->iarg(0) != 0) {
+                       if (sp->slevel < blevel) {
+                               sp = hide(sp);
+                               defstr(sp, soru);
+                               sp->sap = seattr();
+                       } else
+                               uerror("%s redeclared", name);
+               }
+               INSSYM(sp);
+               nscur = sp;
+               gap = sp->sap = attr_add(sp->sap, gap);
+       } else {
+               gap = attr_add(seattr(), gap);
+               sp = getsymtab("__%", SNORMAL);
+       }
+
+       r = tmpcalloc(sizeof(struct rstack));
+       r->rsou = soru;
+       r->rsym = sp;
+//     r->rb = NULL;
+       r->ap = gap;
+       r->rnext = rpole;
+       rpole = r;
+
+       return r;
+}
+
+/*
+ * Called after a struct is declared to restore the environment.
+ * - If ALSTRUCT is defined, this will be the struct alignment and the
+ *   struct size will be a multiple of ALSTRUCT, otherwise it will use
+ *   the alignment of the largest struct member.
+ */
+NODE *
+dclstruct(struct rstack *r)
+{
+       NODE *n;
+       struct attr *aps, *apb;
+       struct symtab *sp;
+       int al, sa, sz;
+
+       apb = attr_find(r->ap, ATTR_ALIGNED);
+       aps = attr_find(r->ap, ATTR_STRUCT);
+//     aps->amlist = r->rb;
+       aps->amlist = nscur->sup;
+
+#ifdef ALSTRUCT
+       al = ALSTRUCT;
+#else
+       al = ALCHAR;
+#endif
+
+       /*
+        * extract size and alignment, calculate offsets
+        */
+       for (sp = /* r->rb */nscur->sup; sp; sp = sp->snext) {
+               sp->sdown = r->rsym;
+               if (ISFTN(sp->stype))
+                       continue;
+               sa = talign(sp->stype, sp->sap);
+               if (sp->sclass & FIELD)
+                       sz = sp->sclass&FLDSIZ;
+               else
+                       sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+               if (sz > rpole->rstr)
+                       rpole->rstr = sz;  /* for use with unions */
+               /*
+                * set al, the alignment, to the lcm of the alignments
+                * of the members.
+                */
+               SETOFF(al, sa);
+       }
+
+       SETOFF(rpole->rstr, al);
+
+       aps->amsize = rpole->rstr;
+       apb->iarg(0) = al;
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("dclstruct(%s): size=%d, align=%d\n",
+                   r->rsym ? r->rsym->sname : "??",
+                   aps->amsize, apb->iarg(0));
+       }
+       if (ddebug>1) {
+               printf("\tsize %d align %d link %p\n",
+                   aps->amsize, apb->iarg(0), aps->amlist);
+               for (sp = aps->amlist; sp != NULL; sp = sp->snext) {
+                       printf("\tmember %s(%p)\n", sp->sname, sp);
+               }
+       }
+#endif
+
+#ifdef STABS
+       if (gflag)
+               stabs_struct(r->rsym, r->ap);
+#endif
+
+       rpole = r->rnext;
+       n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap);
+       n->n_sp = r->rsym;
+
+       POPSYM();
+
+       n->n_qual |= 1; /* definition place XXX used by attributes */
+       return n;
+}
+
+/*
+ * Add a new member to the current struct or union being declared.
+ */
+void
+soumemb(NODE *n, char *name, int class)
+{
+       struct symtab *sp, *lsp;
+       int incomp, tsz, al;
+       TWORD t;
+       if (rpole == NULL)
+               cerror("soumemb");
+       /* check if tag name exists */
+       lsp = NULL;
+       for (sp = /* rpole->rb */ nscur->sup; sp != NULL; lsp = sp, sp = sp->snext)
+               if (*name != '*' && sp->sname == name && class == sp->sclass)
+                       uerror("redeclaration of %s", name);
+
+       sp = getsymtab(name, SMOSNAME);
+#if 0
+       if (rpole->rb == NULL)
+               rpole->rb = sp;
+       else
+               lsp->snext = sp;
+#endif
+       if (nscur->sup == NULL)
+               nscur->sup = sp;
+       else
+               lsp->snext = sp;
+
+       n->n_sp = sp;
+       sp->stype = n->n_type;
+       sp->squal = n->n_qual;
+       sp->slevel = blevel;
+       sp->sap = n->n_ap;
+       sp->sdf = n->n_df;
+       sp->sdown = rpole->rsym;
+
+       if (class & FIELD) {
+               sp->sclass = (char)class;
+               falloc(sp, class&FLDSIZ, NIL);
+       } else if (class == STATIC) {
+               sp->sclass = USTATIC;
+               cxxsetname(sp);
+       } else if (ISFTN(sp->stype)) {
+               sp->sclass = EXTERN;
+               cxxsetname(sp);
+       } else if (rpole->rsou == STNAME || rpole->rsou == UNAME) {
+               sp->sclass = rpole->rsou == STNAME ? MOS : MOU;
+               if (sp->sclass == MOU)
+                       rpole->rstr = 0;
+               al = talign(sp->stype, sp->sap);
+               tsz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+               sp->soffset = upoff(tsz, al, &rpole->rstr);
+       }
+
+       /*
+        * 6.7.2.1 clause 16:
+        * "...the last member of a structure with more than one
+        *  named member may have incomplete array type;"
+        */
+       if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+               incomp = 1;
+       else
+               incomp = 0;
+       if ((rpole->flags & LASTELM) || (/* rpole->rb */ nscur->sup == sp && incomp == 1))
+               uerror("incomplete array in struct");
+       if (incomp == 1)
+               rpole->flags |= LASTELM;
+
+       /*
+        * 6.7.2.1 clause 2:
+        * "...such a structure shall not be a member of a structure
+        *  or an element of an array."
+        */
+       t = sp->stype;
+       if (rpole->rsou != STNAME || BTYPE(t) != STRTY)
+               return; /* not for unions */
+       while (ISARY(t))
+               t = DECREF(t);
+       if (ISPTR(t))
+               return;
+
+       if ((lsp = strmemb(sp->sap)) != NULL) {
+               for (; lsp->snext; lsp = lsp->snext)
+                       ;
+               if (ISARY(lsp->stype) && lsp->snext &&
+                   lsp->sdf->ddim == NOOFFSET)
+                       uerror("incomplete struct in struct");
+       }
+}
+
+/*
+ * error printing routine in parser
+ */
+void
+yyerror(char *s)
+{
+       uerror(s);
+}
+
+void yyaccpt(void);
+void
+yyaccpt(void)
+{
+       ftnend();
+}
+
+/*
+ * p is top of type list given to tymerge later.
+ * Find correct CALL node and declare parameters from there.
+ */
+void
+ftnarg(NODE *p)
+{
+       NODE *q;
+
+#ifdef PCC_DEBUG
+       if (ddebug > 2)
+               printf("ftnarg(%p)\n", p);
+#endif
+       /*
+        * Push argument symtab entries onto param stack in reverse order,
+        * due to the nature of the stack it will be reclaimed correct.
+        */
+       for (; p->n_op != NAME; p = p->n_left) {
+               if (p->n_op == UCALL && p->n_left->n_op == NAME)
+                       return; /* Nothing to enter */
+               if (p->n_op == CALL &&
+                   (p->n_left->n_op == NAME || p->n_left->n_op == NMLIST))
+                       break;
+       }
+
+       p = p->n_right;
+       while (p->n_op == CM) {
+               q = p->n_right;
+               if (q->n_op != ELLIPSIS) {
+                       ssave(q->n_sp);
+                       nparams++;
+#ifdef PCC_DEBUG
+                       if (ddebug > 2)
+                               printf("        saving sym %s (%p) from (%p)\n",
+                                   q->n_sp->sname, q->n_sp, q);
+#endif
+               }
+               p = p->n_left;
+       }
+       ssave(p->n_sp);
+       if (p->n_type != VOID)
+               nparams++;
+
+#ifdef PCC_DEBUG
+       if (ddebug > 2)
+               printf("        saving sym %s (%p) from (%p)\n",
+                   nparams ? p->n_sp->sname : "<noname>", p->n_sp, p);
+#endif
+}
+
+/*
+ * compute the alignment of an object with type ty, sizeoff index s
+ */
+int
+talign(unsigned int ty, struct attr *apl)
+{
+       struct attr *al;
+       int a;
+
+       for (; ty > BTMASK; ty = DECREF(ty)) {
+               switch (ty & TMASK) {
+               case PTR:
+                       return(ALPOINT);
+               case ARY:
+                       continue;
+               case FTN:
+                       cerror("compiler takes alignment of function");
+               }
+       }
+
+       /* check for alignment attribute */
+       if ((al = attr_find(apl, ATTR_ALIGNED))) {
+               if ((a = al->iarg(0)) == 0) {
+                       uerror("no alignment");
+                       a = ALINT;
+               } 
+               return a;
+       }
+
+       ty = BTYPE(ty);
+       if (ty >= CHAR && ty <= ULONGLONG && ISUNSIGNED(ty))
+               ty = DEUNSIGN(ty);
+
+       switch (ty) {
+       case BOOL: a = ALBOOL; break;
+       case CHAR: a = ALCHAR; break;
+       case SHORT: a = ALSHORT; break;
+       case INT: a = ALINT; break;
+       case LONG: a = ALLONG; break;
+       case LONGLONG: a = ALLONGLONG; break;
+       case FLOAT: a = ALFLOAT; break;
+       case DOUBLE: a = ALDOUBLE; break;
+       case LDOUBLE: a = ALLDOUBLE; break;
+       default:
+               uerror("no alignment");
+               a = ALINT;
+       }
+       return a;
+}
+
+short sztable[] = { 0, SZBOOL, SZCHAR, SZCHAR, SZSHORT, SZSHORT, SZINT, SZINT,
+       SZLONG, SZLONG, SZLONGLONG, SZLONGLONG, SZFLOAT, SZDOUBLE, SZLDOUBLE };
+
+/* compute the size associated with type ty,
+ *  dimoff d, and sizoff s */
+/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */
+OFFSZ
+tsize(TWORD ty, union dimfun *d, struct attr *apl)
+{
+       struct attr *ap, *ap2;
+       OFFSZ mult, sz;
+
+       mult = 1;
+
+       for (; ty > BTMASK; ty = DECREF(ty)) {
+               switch (ty & TMASK) {
+
+               case FTN:
+                       uerror( "cannot take size of function");
+               case PTR:
+                       return( SZPOINT(ty) * mult );
+               case ARY:
+                       if (d->ddim == NOOFFSET)
+                               return 0;
+                       if (d->ddim < 0)
+                               cerror("tsize: dynarray");
+                       mult *= d->ddim;
+                       d++;
+               }
+       }
+
+       if (ty == VOID)
+               ty = CHAR;
+       if (ty <= LDOUBLE)
+               sz = sztable[ty];
+       else if (ISSOU(ty)) {
+               if ((ap = strattr(apl)) == NULL ||
+                   (ap2 = attr_find(apl, ATTR_ALIGNED)) == NULL ||
+                   (ap2->iarg(0) == 0)) {
+                       uerror("unknown structure/union/enum");
+                       sz = SZINT;
+               } else
+                       sz = ap->amsize;
+       } else {
+               uerror("unknown type");
+               sz = SZINT;
+       }
+
+       return((unsigned int)sz * mult);
+}
+
+/*
+ * Save string (and print it out).  If wide then wide string.
+ */
+NODE *
+strend(int wide, char *str)
+{
+       struct symtab *sp;
+       NODE *p;
+
+       /* If an identical string is already emitted, just forget this one */
+       if (wide) {
+               /* Do not save wide strings, at least not now */
+               sp = getsymtab(str, SSTRING|STEMP);
+       } else {
+               str = addstring(str);   /* enter string in string table */
+               sp = lookup(str, SSTRING);      /* check for existence */
+       }
+
+       if (sp->soffset == 0) { /* No string */
+               char *wr;
+               int i;
+
+               sp->sclass = STATIC;
+               sp->slevel = 1;
+               sp->soffset = getlab();
+               sp->squal = (CON >> TSHIFT);
+               sp->sdf = permalloc(sizeof(union dimfun));
+               if (wide) {
+                       sp->stype = WCHAR_TYPE+ARY;
+               } else {
+                       if (xuchar) {
+                               sp->stype = UCHAR+ARY;
+                       } else {
+                               sp->stype = CHAR+ARY;
+                       }
+               }
+               for (wr = sp->sname, i = 1; *wr; i++)
+                       if (*wr++ == '\\')
+                               (void)esccon(&wr);
+
+               sp->sdf->ddim = i;
+               if (wide)
+                       inwstring(sp);
+               else
+                       instring(sp);
+       }
+
+       p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+       p->n_sp = sp;
+       return(clocal(p));
+}
+
+/*
+ * Print out a wide string by calling ninval().
+ */
+void
+inwstring(struct symtab *sp)
+{
+       char *s = sp->sname;
+       NODE *p;
+
+       locctr(STRNG, sp);
+       defloc(sp);
+       p = xbcon(0, NULL, WCHAR_TYPE);
+       do {
+               if (*s++ == '\\')
+                       glval(p) = esccon(&s);
+               else
+                       glval(p) = (unsigned char)s[-1];
+               inval(0, tsize(WCHAR_TYPE, NULL, NULL), p);
+       } while (s[-1] != 0);
+       nfree(p);
+}
+
+#ifndef MYINSTRING
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+       char *s, *str;
+
+       locctr(STRNG, sp);
+       defloc(sp);
+       str = sp->sname;
+
+       /* be kind to assemblers and avoid long strings */
+       printf("\t.ascii \"");
+       for (s = str; *s != 0; ) {
+               if (*s++ == '\\') {
+                       (void)esccon(&s);
+               }
+               if (s - str > 60) {
+                       fwrite(str, 1, s - str, stdout);
+                       printf("\"\n\t.ascii \"");
+                       str = s;
+               }
+       }
+       fwrite(str, 1, s - str, stdout);
+       printf("\\0\"\n");
+}
+#endif
+
+/*
+ * update the offset pointed to by poff; return the
+ * offset of a value of size `size', alignment `alignment',
+ * given that off is increasing
+ */
+int
+upoff(int size, int alignment, int *poff)
+{
+       int off;
+
+       off = *poff;
+       SETOFF(off, alignment);
+       if (off < 0)
+               cerror("structure or stack overgrown"); /* wrapped */
+       *poff = off+size;
+       return (off);
+}
+
+/*
+ * allocate p with offset *poff, and update *poff
+ */
+int
+oalloc(struct symtab *p, int *poff )
+{
+       int al, off, tsz;
+       int noff;
+
+       /*
+        * Only generate tempnodes if we are optimizing,
+        * and only for integers, floats or pointers,
+        * and not if the type on this level is volatile.
+        */
+       if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) &&
+           (p->stype < STRTY || ISPTR(p->stype)) &&
+           !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) {
+               NODE *tn = tempnode(0, p->stype, p->sdf, p->sap);
+               p->soffset = regno(tn);
+               p->sflags |= STNODE;
+               nfree(tn);
+               return 0;
+       }
+
+       al = talign(p->stype, p->sap);
+       noff = off = *poff;
+       tsz = (int)tsize(p->stype, p->sdf, p->sap);
+#ifdef BACKAUTO
+       if (p->sclass == AUTO) {
+               noff = off + tsz;
+               if (noff < 0)
+                       cerror("stack overflow");
+               SETOFF(noff, al);
+               off = -noff;
+       } else
+#endif
+       if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR ||
+           p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) {
+               off = upoff(SZINT, ALINT, &noff);
+#if TARGET_ENDIAN == TARGET_BE
+               off = noff - tsz;
+#endif
+       } else {
+               off = upoff(tsz, al, &noff);
+       }
+
+       if (p->sclass != REGISTER) {
+       /* in case we are allocating stack space for register arguments */
+               if (p->soffset == NOOFFSET)
+                       p->soffset = off;
+               else if(off != p->soffset)
+                       return(1);
+       }
+
+       *poff = noff;
+       return(0);
+}
+
+/*
+ * Delay emission of code generated in argument headers.
+ */
+static void
+edelay(NODE *p)
+{
+       if (blevel == 1) {
+               /* Delay until after declarations */
+               if (parlink == NULL)
+                       parlink = p;
+               else
+                       parlink = block(COMOP, parlink, p, 0, 0, 0);
+       } else
+               ecomp(p);
+}
+
+/*
+ * Traverse through the array args, evaluate them and put the 
+ * resulting temp numbers in the dim fields.
+ */
+static void
+evalidx(struct symtab *sp)
+{
+       union dimfun *df;
+       NODE *p;
+       TWORD t;
+       int astkp = 0;
+
+       if (arrstk[0] == NIL)
+               astkp++; /* for parameter arrays */
+
+       if (isdyn(sp))
+               sp->sflags |= SDYNARRAY;
+
+       df = sp->sdf;
+       for (t = sp->stype; t > BTMASK; t = DECREF(t)) {
+               if (!ISARY(t))
+                       continue;
+               if (df->ddim == -1) {
+                       p = tempnode(0, INT, 0, 0);
+                       df->ddim = -regno(p);
+                       edelay(buildtree(ASSIGN, p, arrstk[astkp++]));
+               }
+               df++;
+       }
+       arrstkp = 0;
+}
+
+/*
+ * Return 1 if dynamic array, 0 otherwise.
+ */
+int
+isdyn(struct symtab *sp)
+{
+       union dimfun *df = sp->sdf;
+       TWORD t;
+
+       for (t = sp->stype; t > BTMASK; t = DECREF(t)) {
+               if (!ISARY(t))
+                       return 0;
+               if (df->ddim < 0 && df->ddim != NOOFFSET)
+                       return 1;
+               df++;
+       }
+       return 0;
+}
+
+/*
+ * Allocate space on the stack for dynamic arrays (or at least keep track
+ * of the index).
+ * Strategy is as follows:
+ * - first entry is a pointer to the dynamic datatype.
+ * - if it's a one-dimensional array this will be the only entry used.
+ * - if it's a multi-dimensional array the following (numdim-1) integers
+ *   will contain the sizes to multiply the indexes with.
+ * - code to write the dimension sizes this will be generated here.
+ * - code to allocate space on the stack will be generated here.
+ */
+static void
+dynalloc(struct symtab *p, int *poff)
+{
+       union dimfun *df;
+       NODE *n, *tn, *pol;
+       TWORD t;
+
+       /*
+        * The pointer to the array is not necessarily stored in a
+        * TEMP node, but if it is, its number is in the soffset field;
+        */
+       t = p->stype;
+       p->sflags |= STNODE;
+       p->stype = INCREF(p->stype); /* Make this an indirect pointer */
+       tn = tempnode(0, p->stype, p->sdf, p->sap);
+       p->soffset = regno(tn);
+
+       df = p->sdf;
+
+       pol = bcon(1);
+       for (; t > BTMASK; t = DECREF(t)) {
+               if (!ISARY(t))
+                       break;
+               if (df->ddim < 0)
+                       n = tempnode(-df->ddim, INT, 0, 0);
+               else
+                       n = bcon(df->ddim);
+
+               pol = buildtree(MUL, pol, n);
+               df++;
+       }
+       /* Create stack gap */
+       spalloc(tn, pol, tsize(t, 0, p->sap));
+}
+
+/*
+ * allocate a field of width w
+ * new is 0 if new entry, 1 if redefinition, -1 if alignment
+ */
+int
+falloc(struct symtab *p, int w, NODE *pty)
+{
+       TWORD otype, type;
+       int al,sz;
+
+       otype = type = p ? p->stype : pty->n_type;
+
+       if (type == BOOL)
+               type = BOOL_TYPE;
+       if (!ISINTEGER(type)) {
+               uerror("illegal field type");
+               type = INT;
+       }
+
+       al = talign(type, NULL);
+       sz = tsize(type, NULL, NULL);
+
+       if (w > sz) {
+               uerror("field too big");
+               w = sz;
+       }
+
+       if (w == 0) { /* align only */
+               SETOFF(rpole->rstr, al);
+               if (p != NULL)
+                       uerror("zero size field");
+               return(0);
+       }
+
+       if (rpole->rstr%al + w > sz)
+               SETOFF(rpole->rstr, al);
+       if (p == NULL) {
+               rpole->rstr += w;  /* we know it will fit */
+               return(0);
+       }
+
+       /* establish the field */
+
+       p->soffset = rpole->rstr;
+       rpole->rstr += w;
+       p->stype = otype;
+       fldty(p);
+       return(0);
+}
+
+/*
+ * Check if this symbol should be a common or must be handled in data seg.
+ */
+static void
+commchk(struct symtab *sp)
+{
+       if ((sp->sflags & STLS)
+#ifdef GCC_COMPAT
+           || attr_find(sp->sap, GCC_ATYP_SECTION)
+#endif
+           ) {
+               /* TLS handled in data segment */
+               if (sp->sclass == EXTERN)
+                       sp->sclass = EXTDEF;
+               beginit(sp);
+               endinit(1);
+       } else {
+               symdirec(sp);
+               defzero(sp);
+       }
+}
+
+/*
+ * handle unitialized declarations assumed to be not functions:
+ * int a;
+ * extern int a;
+ * static int a;
+ */
+void
+nidcl(NODE *p, int class)
+{
+       struct symtab *sp;
+       int commflag = 0;
+
+       /* compute class */
+       if (class == SNULL) {
+               if (blevel > 1)
+                       class = AUTO;
+               else if (blevel != 0 || rpole)
+                       cerror( "nidcl error" );
+               else /* blevel = 0 */
+                       commflag = 1, class = EXTERN;
+       }
+
+       defid(p, class);
+
+       sp = p->n_sp;
+       /* check if forward decl */
+       if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+               return;
+
+       if (sp->sflags & SASG)
+               return; /* already initialized */
+
+       switch (class) {
+       case EXTDEF:
+               /* simulate initialization by 0 */
+               simpleinit(p->n_sp, bcon(0));
+               break;
+       case EXTERN:
+               if (commflag)
+                       lcommadd(p->n_sp);
+               else
+                       extdec(p->n_sp);
+               break;
+       case STATIC:
+               if (blevel == 0)
+                       lcommadd(p->n_sp);
+               else
+                       commchk(p->n_sp);
+               break;
+       }
+}
+
+struct lcd {
+       SLIST_ENTRY(lcd) next;
+       struct symtab *sp;
+};
+
+static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw};
+
+/*
+ * Add a local common statement to the printout list.
+ */
+void
+lcommadd(struct symtab *sp)
+{
+       struct lcd *lc, *lcp;
+
+       lcp = NULL;
+       SLIST_FOREACH(lc, &lhead, next) {
+               if (lc->sp == sp)
+                       return; /* already exists */
+               if (lc->sp == NULL && lcp == NULL)
+                       lcp = lc;
+       }
+       if (lcp == NULL) {
+               lc = permalloc(sizeof(struct lcd));
+               lc->sp = sp;
+               SLIST_INSERT_LAST(&lhead, lc, next);
+       } else
+               lcp->sp = sp;
+}
+
+/*
+ * Delete a local common statement.
+ */
+void
+lcommdel(struct symtab *sp)
+{
+       struct lcd *lc;
+
+       SLIST_FOREACH(lc, &lhead, next) {
+               if (lc->sp == sp) {
+                       lc->sp = NULL;
+                       return;
+               }
+       }
+}
+
+/*
+ * Print out the remaining common statements.
+ */
+void
+lcommprint(void)
+{
+       struct lcd *lc;
+
+       SLIST_FOREACH(lc, &lhead, next) {
+               if (lc->sp != NULL)
+                       commchk(lc->sp);
+       }
+}
+
+/*
+ * Merge given types to a single node.
+ * Any type can end up here.
+ * p is the old node, q is the old (if any).
+ * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF.
+ * QUALIFIER is VOL or CON
+ * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT,
+ *     DOUBLE, STRTY, UNIONTY.
+ */
+struct typctx {
+       int class, qual, sig, uns, cmplx, imag, err;
+       TWORD type;
+       NODE *saved;
+       struct attr *pre, *post;
+};
+
+static void
+typwalk(NODE *p, void *arg)
+{
+       struct typctx *tc = arg;
+
+#define        cmop(x,y) block(CM, x, y, INT, 0, 0)
+       switch (p->n_op) {
+       case ATTRIB:
+#ifdef GCC_COMPAT
+               if (tc->saved && (tc->saved->n_qual & 1)) {
+                       tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left));
+               } else {
+                       tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left));
+               }
+               p->n_left = bcon(0); /* For tfree() */
+#endif
+               break;
+       case CLASS:
+               if (tc->class)
+                       tc->err = 1; /* max 1 class */
+               tc->class = p->n_type;
+               break;
+
+       case QUALIFIER:
+#if 0
+               if (p->n_qual == 0)
+                       uerror("invalid use of 'restrict'");
+#endif
+               tc->qual |= p->n_qual >> TSHIFT;
+               break;
+
+       case TYPE:
+               if (p->n_sp != NULL || ISSOU(p->n_type)) {
+                       /* typedef, enum or struct/union */
+                       if (tc->saved || tc->type)
+                               tc->err = 1;
+#ifdef GCC_COMPAT
+                       if (ISSOU(p->n_type) && p->n_left) {
+                               if (tc->post)
+                                       cerror("typwalk");
+                               tc->post = gcc_attr_parse(p->n_left);
+                       }
+#endif
+                       tc->saved = ccopy(p);
+                       break;
+               }
+
+               switch (p->n_type) {
+               case BOOL:
+               case CHAR:
+               case FLOAT:
+               case VOID:
+                       if (tc->type)
+                               tc->err = 1;
+                       tc->type = p->n_type;
+                       break;
+               case DOUBLE:
+                       if (tc->type == 0)
+                               tc->type = DOUBLE;
+                       else if (tc->type == LONG)
+                               tc->type = LDOUBLE;
+                       else
+                               tc->err = 1;
+                       break;
+               case SHORT:
+                       if (tc->type == 0 || tc->type == INT)
+                               tc->type = SHORT;
+                       else
+                               tc->err = 1;
+                       break;
+               case INT:
+                       if (tc->type == SHORT || tc->type == LONG ||
+                           tc->type == LONGLONG)
+                               break;
+                       else if (tc->type == 0)
+                               tc->type = INT;
+                       else
+                               tc->err = 1;
+                       break;
+               case LONG:
+                       if (tc->type == 0)
+                               tc->type = LONG;
+                       else if (tc->type == INT)
+                               break;
+                       else if (tc->type == LONG)
+                               tc->type = LONGLONG;
+                       else if (tc->type == DOUBLE)
+                               tc->type = LDOUBLE;
+                       else
+                               tc->err = 1;
+                       break;
+               case SIGNED:
+                       if (tc->sig || tc->uns)
+                               tc->err = 1;
+                       tc->sig = 1;
+                       break;
+               case UNSIGNED:
+                       if (tc->sig || tc->uns)
+                               tc->err = 1;
+                       tc->uns = 1;
+                       break;
+               case COMPLEX:
+                       tc->cmplx = 1;
+                       break;
+               case IMAG:
+                       tc->imag = 1;
+                       break;
+               default:
+                       cerror("typwalk");
+               }
+       }
+
+}
+
+NODE *
+typenode(NODE *p)
+{
+       struct symtab *sp;
+       struct typctx tc;
+       NODE *q;
+       char *c;
+
+       memset(&tc, 0, sizeof(struct typctx));
+
+       flist(p, typwalk, &tc);
+       tfree(p);
+
+       if (tc.err)
+               goto bad;
+
+       if (tc.cmplx || tc.imag) {
+               if (tc.type == 0)
+                       tc.type = DOUBLE;
+               if ((tc.cmplx && tc.imag) || tc.sig || tc.uns ||
+                   !ISFTY(tc.type))
+                       goto bad;
+               if (tc.cmplx) {
+                       c = tc.type == DOUBLE ? "0d" :
+                           tc.type == FLOAT ? "0f" : "0l";
+                       sp = lookup(addname(c), 0);
+                       tc.type = STRTY;
+                       tc.saved = mkty(tc.type, sp->sdf, sp->sap);
+                       tc.saved->n_sp = sp;
+                       tc.type = 0;
+               } else
+                       tc.type += (FIMAG-FLOAT);
+       }
+
+       if (tc.saved && tc.type)
+               goto bad;
+       if (tc.sig || tc.uns) {
+               if (tc.type == 0)
+                       tc.type = tc.sig ? INT : UNSIGNED;
+               if (tc.type > ULONGLONG)
+                       goto bad;
+               if (tc.uns)
+                       tc.type = ENUNSIGN(tc.type);
+       }
+
+       if (xuchar && tc.type == CHAR && tc.sig == 0)
+               tc.type = UCHAR;
+
+#ifdef GCC_COMPAT
+       if (pragma_packed) {
+               q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed));
+               tc.post = attr_add(tc.post, gcc_attr_parse(q));
+       }
+       if (pragma_aligned) {
+               /* Deal with relevant pragmas */
+               q = bdty(CALL, bdty(NAME, "aligned"), bcon(pragma_aligned));
+               tc.post = attr_add(tc.post, gcc_attr_parse(q));
+       }
+       pragma_aligned = pragma_packed = 0;
+#endif
+       if ((q = tc.saved) == NULL) {
+               TWORD t;
+               if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID &&
+                   t != BOOL && !(t >= FIMAG && t <= LIMAG))
+                       cerror("typenode2 t %x", tc.type);
+               if (t == UNDEF) {
+                       t = INT;
+                       MODTYPE(tc.type, INT);
+               }
+               q =  mkty(tc.type, 0, 0);
+       }
+       q->n_ap = attr_add(q->n_ap, tc.post);
+       q->n_qual = tc.qual;
+       glval(q) = tc.class;
+#ifdef GCC_COMPAT
+       if (tc.post) {
+               /* Can only occur for TYPEDEF, STRUCT or UNION */
+               if (tc.saved == NULL)
+                       cerror("typenode");
+               if (tc.saved->n_sp) /* trailer attributes for structs */
+                       tc.saved->n_sp->sap = q->n_ap;
+       }
+       if (tc.pre)
+               q->n_ap = attr_add(q->n_ap, tc.pre);
+       gcc_tcattrfix(q);
+#endif
+       return q;
+
+bad:   uerror("illegal type combination");
+       return mkty(INT, 0, 0);
+}
+
+struct tylnk {
+       struct tylnk *next;
+       union dimfun df;
+};
+
+/*
+ * Retrieve all CM-separated argument types, sizes and dimensions and
+ * put them in an array.
+ * XXX - can only check first type level, side effects?
+ */
+static union arglist *
+arglist(NODE *n)
+{
+       union arglist *al;
+       NODE *w = n, **ap;
+       int num, cnt, i, j, k;
+       TWORD ty;
+
+#ifdef PCC_DEBUG
+       if (pdebug) {
+               printf("arglist %p\n", n);
+               fwalk(n, eprint, 0);
+       }
+#endif
+       /* First: how much to allocate */
+       for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) {
+               cnt++;  /* Number of levels */
+               num++;  /* At least one per step */
+               if (w->n_right->n_op == ELLIPSIS)
+                       continue;
+               ty = w->n_right->n_type;
+               if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+                       num++;
+               while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK)
+                       ty = DECREF(ty);
+               if (ty > BTMASK)
+                       num++;
+       }
+       cnt++;
+       ty = w->n_type;
+       if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+               num++;
+       while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK)
+               ty = DECREF(ty);
+       if (ty > BTMASK)
+               num++;
+       num += 2; /* TEND + last arg type */
+
+       /* Second: Create list to work on */
+       ap = tmpalloc(sizeof(NODE *) * cnt);
+       al = permalloc(sizeof(union arglist) * num);
+       arglistcnt += num;
+
+       for (w = n, i = 0; w->n_op == CM; w = w->n_left)
+               ap[i++] = w->n_right;
+       ap[i] = w;
+
+       /* Third: Create actual arg list */
+       for (k = 0, j = i; j >= 0; j--) {
+               if (ap[j]->n_op == ELLIPSIS) {
+                       al[k++].type = TELLIPSIS;
+                       ap[j]->n_op = ICON; /* for tfree() */
+                       continue;
+               }
+               /* Convert arrays to pointers */
+               if (ISARY(ap[j]->n_type)) {
+                       ap[j]->n_type += (PTR-ARY);
+                       ap[j]->n_df++;
+               }
+               /* Convert (silently) functions to pointers */
+               if (ISFTN(ap[j]->n_type))
+                       ap[j]->n_type = INCREF(ap[j]->n_type);
+               ty = ap[j]->n_type;
+#ifdef GCC_COMPAT
+               if (ty == UNIONTY &&
+                   attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){
+                       /* transparent unions must have compatible types
+                        * shortcut here: if pointers, set void *, 
+                        * otherwise btype.
+                        */
+                       struct symtab *sp = strmemb(ap[j]->n_ap);
+                       ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype;
+               }
+#endif
+               al[k++].type = ty;
+               if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+                       al[k++].sap = ap[j]->n_ap;
+               while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK)
+                       ty = DECREF(ty);
+               if (ty > BTMASK)
+                       al[k++].df = ap[j]->n_df;
+       }
+       al[k++].type = TNULL;
+       if (k > num)
+               cerror("arglist: k%d > num%d", k, num);
+       tfree(n);
+#ifdef PCC_DEBUG
+       if (pdebug)
+               alprint(al, 0);
+#endif
+       return al;
+}
+
+static void
+tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim)
+{
+       (*tylkp)->next = tmpalloc(sizeof(struct tylnk));
+       *tylkp = (*tylkp)->next;
+       (*tylkp)->next = NULL;
+       (*tylkp)->df = dim;
+       (*ntdim)++;
+}
+
+/*
+ * build a type, and stash away dimensions,
+ * from a parse tree of the declaration
+ * the type is build top down, the dimensions bottom up
+ */
+static void
+tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim)
+{
+       union dimfun dim;
+       NODE *r = NULL;
+       int o;
+       TWORD t, q;
+
+       o = p->n_op;
+       if (o == NAME) {
+               p->n_qual = DECQAL(p->n_qual);
+               return;
+       }
+
+       t = INCREF(p->n_type);
+       q = p->n_qual;
+       switch (o) {
+       case CALL:
+               t += (FTN-PTR);
+               dim.dfun = arglist(p->n_right);
+               break;
+       case UCALL:
+               t += (FTN-PTR);
+               dim.dfun = NULL;
+               break;
+       case LB:
+               t += (ARY-PTR);
+               if (p->n_right->n_op != ICON) {
+                       r = p->n_right;
+                       o = RB;
+               } else {
+                       dim.ddim = (int)glval(p->n_right);
+                       nfree(p->n_right);
+#ifdef notdef
+       /* XXX - check dimensions at usage time */
+                       if (dim.ddim == NOOFFSET && p->n_left->n_op == LB)
+                               uerror("null dimension");
+#endif
+               }
+               break;
+       }
+
+       p->n_left->n_type = t;
+       p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual;
+       tyreduce(p->n_left, tylkp, ntdim);
+
+       if (o == LB || o == UCALL || o == CALL)
+               tylkadd(dim, tylkp, ntdim);
+       if (o == RB) {
+               dim.ddim = -1;
+               tylkadd(dim, tylkp, ntdim);
+               arrstk[arrstkp++] = r;
+       }
+
+       p->n_sp = p->n_left->n_sp;
+       p->n_type = p->n_left->n_type;
+       p->n_qual = p->n_left->n_qual;
+}
+
+/*
+ * merge type typ with identifier idp.
+ * idp is returned as a NAME node with correct types,
+ * typ is untouched since multiple declarations uses it.
+ * typ has type attributes, idp can never carry such attributes
+ * so on return just a pointer to the typ attributes is returned.
+ */
+NODE *
+tymerge(NODE *typ, NODE *idp)
+{
+       TWORD t;
+       NODE *p;
+       union dimfun *j;
+       struct tylnk *base, tylnk, *tylkp;
+       struct attr *bap;
+       int ntdim, i;
+
+#ifdef PCC_DEBUG
+       if (ddebug > 2) {
+               printf("tymerge(%p,%p)\n", typ, idp);
+               fwalk(typ, eprint, 0);
+               fwalk(idp, eprint, 0);
+       }
+#endif
+
+       if (typ->n_op != TYPE)
+               cerror("tymerge: arg 1");
+
+       bap = typ->n_ap;
+
+       idp->n_type = typ->n_type;
+       idp->n_qual |= typ->n_qual;
+
+       tylkp = &tylnk;
+       tylkp->next = NULL;
+       ntdim = 0;
+
+       tyreduce(idp, &tylkp, &ntdim);
+
+       for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t))
+               if (ISARY(t) || ISFTN(t))
+                       tylkadd(*j++, &tylkp, &ntdim);
+
+       if (ntdim) {
+               union dimfun *a = permalloc(sizeof(union dimfun) * ntdim);
+               dimfuncnt += ntdim;
+               for (i = 0, base = tylnk.next; base; base = base->next, i++)
+                       a[i] = base->df;
+               idp->n_df = a;
+       } else
+               idp->n_df = NULL;
+
+       /* now idp is a single node: fix up type */
+       if ((t = ctype(idp->n_type)) != idp->n_type)
+               idp->n_type = t;
+       
+       if (idp->n_op != NAME) {
+               for (p = idp->n_left; p->n_op != NAME; p = p->n_left)
+                       nfree(p);
+               nfree(p);
+               idp->n_op = NAME;
+       }
+       idp->n_ap = bap;
+
+       return(idp);
+}
+
+static NODE *
+argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap)
+{
+       NODE *u, *r = talloc();
+
+       r->n_op = NAME;
+       r->n_type = t;
+       r->n_qual = 0; /* XXX */
+       r->n_df = d;
+       r->n_ap = ap;
+
+       u = buildtree(CAST, r, p);
+       nfree(u->n_left);
+       r = u->n_right;
+       nfree(u);
+       return r;
+}
+
+#ifdef PCC_DEBUG
+/*
+ * Print a prototype.
+ */
+static void
+alprint(union arglist *al, int in)
+{
+       TWORD t;
+       int i = 0, j;
+
+       for (; al->type != TNULL; al++) {
+               for (j = in; j > 0; j--)
+                       printf("  ");
+               printf("arg %d: ", i++);
+               t = al->type;
+               tprint(t, 0);
+               while (t > BTMASK) {
+                       if (ISARY(t)) {
+                               al++;
+                               printf(" dim %d ", al->df->ddim);
+                       } else if (ISFTN(t)) {
+                               al++;
+                               alprint(al->df->dfun, in+1);
+                       }
+                       t = DECREF(t);
+               }
+               if (ISSOU(t)) {
+                       al++;
+                       printf(" (size %d align %d)", (int)tsize(t, 0, al->sap),
+                           (int)talign(t, al->sap));
+               }
+               printf("\n");
+       }
+       if (in == 0)
+               printf("end arglist\n");
+}
+#endif
+int
+suemeq(struct attr *s1, struct attr *s2)
+{
+
+       return (strmemb(s1) == strmemb(s2));
+}
+
+/*
+ * Sanity-check old-style args.
+ */
+static NODE *
+oldarg(NODE *p)
+{
+       if (p->n_op == TYPE)
+               uerror("type is not an argument");
+       if (p->n_type == FLOAT)
+               return cast(p, DOUBLE, p->n_qual);
+       return p;
+}
+
+/*
+ * Do prototype checking and add conversions before calling a function.
+ * Argument f is function and a is a CM-separated list of arguments.
+ * Returns a merged node (via buildtree() of function and arguments.
+ */
+NODE *
+doacall(struct symtab *sp, NODE *f, NODE *a, int hidden)
+{
+       NODE *w, *r;
+       union arglist *al;
+       struct ap {
+               struct ap *next;
+               NODE *node;
+       } *at, *apole = NULL;
+       int argidx/* , hasarray = 0*/;
+       TWORD type, arrt;
+
+#ifdef PCC_DEBUG
+       if (ddebug) {
+               printf("doacall.\n");
+               fwalk(f, eprint, 0);
+               if (a)
+                       fwalk(a, eprint, 0);
+       }
+#endif
+
+       /* First let MD code do something */
+       calldec(f, a);
+/* XXX XXX hack */
+       if ((f->n_op == CALL) &&
+           f->n_left->n_op == ADDROF &&
+           f->n_left->n_left->n_op == NAME &&
+           (f->n_left->n_left->n_type & 0x7e0) == 0x4c0)
+               goto build;
+/* XXX XXX hack */
+
+       /* Check for undefined or late defined enums */
+       if (BTYPE(f->n_type) == ENUMTY) {
+               /* not-yet check if declared enum */
+               struct symtab *sq = strmemb(f->n_ap);
+               if (sq->stype != ENUMTY)
+                       MODTYPE(f->n_type, sq->stype);
+               if (BTYPE(f->n_type) == ENUMTY)
+                       uerror("enum %s not declared", sq->sname);
+       }
+
+       /*
+        * Do some basic checks.
+        */
+       if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) {
+               /*
+                * Handle non-prototype declarations.
+                */
+               if (f->n_op == NAME && f->n_sp != NULL) {
+                       if (strncmp(f->n_sp->sname, "__builtin", 9) != 0)
+                               warner(Wmissing_prototypes, f->n_sp->sname);
+               } else
+                       warner(Wmissing_prototypes, "<pointer>");
+
+               /* floats must be cast to double */
+               if (a == NULL)
+                       goto build;
+               if (a->n_op != CM) {
+                       a = oldarg(a);
+               } else {
+                       for (w = a; w->n_left->n_op == CM; w = w->n_left)
+                               w->n_right = oldarg(w->n_right);
+                       w->n_left = oldarg(w->n_left);
+                       w->n_right = oldarg(w->n_right);
+               }
+               goto build;
+       }
+       if (al->type == VOID) {
+               if (a != NULL)
+                       uerror("function takes no arguments");
+               goto build; /* void function */
+       } else {
+               if (a == NULL) {
+                       uerror("function needs arguments");
+                       goto build;
+               }
+       }
+#ifdef PCC_DEBUG
+       if (pdebug) {
+               printf("arglist for %s\n",
+                   f->n_sp != NULL ? f->n_sp->sname : "function pointer");
+               alprint(al, 0);
+       }
+#endif
+
+       /*
+        * Create a list of pointers to the nodes given as arg.
+        */
+       for (w = a; w->n_op == CM; w = w->n_left) {
+               at = tmpalloc(sizeof(struct ap));
+               at->node = w->n_right;
+               at->next = apole;
+               apole = at;
+       }
+       if (hidden == 0) {
+               at = tmpalloc(sizeof(struct ap));
+               at->node = w;
+               at->next = apole;
+               apole = at;
+       }
+
+       /*
+        * Do the typechecking by walking up the list.
+        */
+       argidx = 1;
+       while (al->type != TNULL) {
+               if (al->type == TELLIPSIS) {
+                       /* convert the rest of float to double */
+                       for (; apole; apole = apole->next) {
+                               if (apole->node->n_type != FLOAT)
+                                       continue;
+                               MKTY(apole->node, DOUBLE, 0, 0);
+                       }
+                       goto build;
+               }
+               if (apole == NULL) {
+                       uerror("too few arguments to function");
+                       goto build;
+               }
+/* al = prototyp, apole = argument till ftn */
+/* type = argumentets typ, arrt = prototypens typ */
+               type = apole->node->n_type;
+               arrt = al->type;
+#if 0
+               if ((hasarray = ISARY(arrt)))
+                       arrt += (PTR-ARY);
+#endif
+               /* Taking addresses of arrays are meaningless in expressions */
+               /* but people tend to do that and also use in prototypes */
+               /* this is mostly a problem with typedefs */
+               if (ISARY(type)) {
+                       if (ISPTR(arrt) && ISARY(DECREF(arrt)))
+                               type = INCREF(type);
+                       else
+                               type += (PTR-ARY);
+               } else if (ISPTR(type) && !ISARY(DECREF(type)) &&
+                   ISPTR(arrt) && ISARY(DECREF(arrt))) {
+                       type += (ARY-PTR);
+                       type = INCREF(type);
+               }
+
+               /* Check structs */
+               if (type <= BTMASK && arrt <= BTMASK) {
+                       if (type != arrt) {
+                               if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) {
+incomp:                                        uerror("incompatible types for arg %d",
+                                           argidx);
+                               } else {
+                                       MKTY(apole->node, arrt, 0, 0)
+                               }
+#ifndef NO_COMPLEX
+                       } else if (type == STRTY &&
+                           attr_find(apole->node->n_ap, ATTR_COMPLEX) &&
+                           attr_find(al[1].sap, ATTR_COMPLEX)) {
+                               /* Both are complex */
+                               if (strmemb(apole->node->n_ap)->stype !=
+                                   strmemb(al[1].sap)->stype) {
+                                       /* must convert to correct type */
+                                       w = talloc();
+                                       *w = *apole->node;
+                                       w = mkcmplx(w,
+                                           strmemb(al[1].sap)->stype);
+                                       *apole->node = *w;
+                                       nfree(w);
+                               }
+                               goto out;
+#endif
+                       } else if (ISSOU(BTYPE(type))) {
+                               if (!suemeq(apole->node->n_ap, al[1].sap))
+                                       goto incomp;
+                       }
+                       goto out;
+               }
+
+               /* XXX should (recusively) check return type and arg list of
+                  func ptr arg XXX */
+               if (ISFTN(DECREF(arrt)) && ISFTN(type))
+                       type = INCREF(type);
+
+               /* Hereafter its only pointers (or arrays) left */
+               /* Check for struct/union intermixing with other types */
+               if (((type <= BTMASK) && ISSOU(BTYPE(type))) ||
+                   ((arrt <= BTMASK) && ISSOU(BTYPE(arrt))))
+                       goto incomp;
+
+               /* Check for struct/union compatibility */
+               if (type == arrt) {
+                       if (ISSOU(BTYPE(type))) {
+                               if (suemeq(apole->node->n_ap, al[1].sap))
+                                       goto out;
+                       } else
+                               goto out;
+               }
+               if (BTYPE(arrt) == VOID && type > BTMASK)
+                       goto skip; /* void *f = some pointer */
+               if (arrt > BTMASK && BTYPE(type) == VOID)
+                       goto skip; /* some *f = void pointer */
+               if (apole->node->n_op == ICON && glval(apole->node) == 0)
+                       goto skip; /* Anything assigned a zero */
+
+               if ((type & ~BTMASK) == (arrt & ~BTMASK)) {
+                       /* do not complain for pointers with signedness */
+                       if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) &&
+                           (BTYPE(type) != BTYPE(arrt))) {
+                               warner(Wpointer_sign);
+                               goto skip;
+                       }
+               }
+
+               werror("implicit conversion of argument %d due to prototype",
+                   argidx);
+
+skip:          if (ISSOU(BTYPE(arrt))) {
+                       MKTY(apole->node, arrt, 0, al[1].sap)
+               } else {
+                       MKTY(apole->node, arrt, 0, 0)
+               }
+
+out:           al++;
+               if (ISSOU(BTYPE(arrt)))
+                       al++;
+#if 0
+               while (arrt > BTMASK && !ISFTN(arrt))
+                       arrt = DECREF(arrt);
+               if (ISFTN(arrt) || hasarray)
+                       al++;
+#else
+               while (arrt > BTMASK) {
+                       if (ISARY(arrt) || ISFTN(arrt)) {
+                               al++;
+                               break;
+                       }
+                       arrt = DECREF(arrt);
+               }
+#endif
+               apole = apole->next;
+               argidx++;
+       }
+       if (apole != NULL)
+               uerror("too many arguments to function");
+
+build: if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a)))
+               return w;
+       return buildtree(a == NIL ? UCALL : CALL, f, a);
+}
+
+static int
+chk2(TWORD type, union dimfun *dsym, union dimfun *ddef)
+{
+       while (type > BTMASK) {
+               switch (type & TMASK) {
+               case ARY:
+                       /* may be declared without dimension */
+                       if (dsym->ddim == NOOFFSET)
+                               dsym->ddim = ddef->ddim;
+                       if (dsym->ddim < 0 && ddef->ddim < 0)
+                               ; /* dynamic arrays as arguments */
+                       else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim)
+                               return 1;
+                       dsym++, ddef++;
+                       break;
+               case FTN:
+                       /* old-style function headers with function pointers
+                        * will most likely not have a prototype.
+                        * This is not considered an error.  */
+                       if (ddef->dfun == NULL) {
+#ifdef notyet
+                               werror("declaration not a prototype");
+#endif
+                       } else if (chkftn(dsym->dfun, ddef->dfun))
+                               return 1;
+                       dsym++, ddef++;
+                       break;
+               }
+               type = DECREF(type);
+       }
+       return 0;
+}
+
+/*
+ * Compare two function argument lists to see if they match.
+ */
+int
+chkftn(union arglist *usym, union arglist *udef)
+{
+       TWORD t2;
+       int ty, tyn;
+
+       if (usym == NULL)
+               return 0;
+       if (cftnsp != NULL && udef == NULL && usym->type == VOID)
+               return 0; /* foo() { function with foo(void); prototype */
+       if (udef == NULL && usym->type != TNULL)
+               return 1;
+       while (usym->type != TNULL) {
+               if (usym->type == udef->type)
+                       goto done;
+               /*
+                * If an old-style declaration, then all types smaller than
+                * int are given as int parameters.
+                */
+               if (intcompare) {
+                       ty = BTYPE(usym->type);
+                       tyn = BTYPE(udef->type);
+                       if (ty == tyn || ty != INT)
+                               return 1;
+                       if (tyn == CHAR || tyn == UCHAR ||
+                           tyn == SHORT || tyn == USHORT)
+                               goto done;
+                       return 1;
+               } else
+                       return 1;
+
+done:          ty = BTYPE(usym->type);
+               t2 = usym->type;
+               if (ISSOU(ty)) {
+                       usym++, udef++;
+                       if (suemeq(usym->sap, udef->sap) == 0)
+                               return 1;
+               }
+
+               while (!ISFTN(t2) && !ISARY(t2) && t2 > BTMASK)
+                       t2 = DECREF(t2);
+               if (t2 > BTMASK) {
+                       usym++, udef++;
+                       if (chk2(t2, usym->df, udef->df))
+                               return 1;
+               }
+               usym++, udef++;
+       }
+       if (usym->type != udef->type)
+               return 1;
+       return 0;
+}
+
+void
+fixtype(NODE *p, int class)
+{
+       unsigned int t, type;
+       int mod1, mod2;
+       /* fix up the types, and check for legality */
+
+       /* forward declared enums */
+       if (BTYPE(p->n_sp->stype) == ENUMTY) {
+               MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype);
+       }
+
+       if( (type = p->n_type) == UNDEF ) return;
+       if ((mod2 = (type&TMASK))) {
+               t = DECREF(type);
+               while( mod1=mod2, mod2 = (t&TMASK) ){
+                       if( mod1 == ARY && mod2 == FTN ){
+                               uerror( "array of functions is illegal" );
+                               type = 0;
+                               }
+                       else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){
+                               uerror( "function returns illegal type" );
+                               type = 0;
+                               }
+                       t = DECREF(t);
+                       }
+               }
+
+       /* detect function arguments, watching out for structure declarations */
+       if (rpole && ISFTN(type)) {
+               uerror("function illegal in structure or union");
+               type = INCREF(type);
+       }
+       p->n_type = type;
+}
+
+/*
+ * give undefined version of class
+ */
+int
+uclass(int class)
+{
+       if (class == SNULL)
+               return(EXTERN);
+       else if (class == STATIC)
+               return(USTATIC);
+       else
+               return(class);
+}
+
+int
+fixclass(int class, TWORD type)
+{
+       extern int fun_inline;
+
+       /* first, fix null class */
+       if (class == SNULL) {
+               if (fun_inline && ISFTN(type))
+                       return SNULL;
+               if (rpole)
+                       cerror("field8");
+               else if (blevel == 0)
+                       class = EXTDEF;
+               else
+                       class = AUTO;
+       }
+
+       /* now, do general checking */
+
+       if( ISFTN( type ) ){
+               switch( class ) {
+               default:
+                       uerror( "function has illegal storage class" );
+               case AUTO:
+                       class = EXTERN;
+               case EXTERN:
+               case EXTDEF:
+               case TYPEDEF:
+               case STATIC:
+               case USTATIC:
+                       ;
+                       }
+               }
+
+       if (class & FIELD) {
+               cerror("field3");
+       }
+
+       switch (class) {
+
+       case MOS:
+       case MOU:
+               cerror("field4");
+
+       case REGISTER:
+               if (blevel == 0)
+                       uerror("illegal register declaration");
+               if (blevel == 1)
+                       return(PARAM);
+               else
+                       return(AUTO);
+
+       case AUTO:
+               if( blevel < 2 ) uerror( "illegal ULABEL class" );
+               return( class );
+
+       case EXTERN:
+       case STATIC:
+       case EXTDEF:
+       case TYPEDEF:
+       case USTATIC:
+       case PARAM:
+               return( class );
+
+       default:
+               cerror( "illegal class: %d", class );
+               /* NOTREACHED */
+
+       }
+       return 0; /* XXX */
+}
+
+/*
+ * Generates a goto statement; sets up label number etc.
+ */
+void
+gotolabel(char *name)
+{
+       struct symtab *s = lookup(name, SLBLNAME);
+
+       if (s->soffset == 0)
+               s->soffset = -getlab();
+       branch(s->soffset < 0 ? -s->soffset : s->soffset);
+}
+
+/*
+ * Sets a label for gotos.
+ */
+void
+deflabel(char *name, NODE *p)
+{
+       struct symtab *s = lookup(name, SLBLNAME);
+
+#ifdef GCC_COMPAT
+       s->sap = gcc_attr_parse(p);
+#endif
+       if (s->soffset > 0)
+               uerror("label '%s' redefined", name);
+       if (s->soffset == 0)
+               s->soffset = getlab();
+       if (s->soffset < 0)
+               s->soffset = -s->soffset;
+       plabel( s->soffset);
+}
+
+struct symtab *
+getsymtab(char *name, int flags)
+{
+       struct symtab *s;
+
+       if (flags & STEMP) {
+               s = tmpalloc(sizeof(struct symtab));
+       } else {
+               s = permalloc(sizeof(struct symtab));
+               symtabcnt++;
+       }
+       s->sname = name;
+       s->soname = NULL;
+       s->sup = s->sdown = s->snext = NULL;
+       s->stype = UNDEF;
+       s->squal = 0;
+       s->sclass = SNULL;
+       s->sflags = (short)(flags & SMASK);
+       s->soffset = 0;
+       s->slevel = (char)blevel;
+       s->sdf = NULL;
+       s->sap = NULL;
+       return s;
+}
+
+int
+fldchk(int sz)
+{
+       if (rpole->rsou != STNAME && rpole->rsou != UNAME)
+               uerror("field outside of structure");
+       if (sz < 0 || sz >= FIELD) {
+               uerror("illegal field size");
+               return 1;
+       }
+       return 0;
+}
+
+#ifdef PCC_DEBUG
+static char *
+ccnames[] = { /* names of storage classes */
+       "SNULL",
+       "AUTO",
+       "EXTERN",
+       "STATIC",
+       "REGISTER",
+       "EXTDEF",
+       "LABEL",
+       "ULABEL",
+       "MOS",
+       "PARAM",
+       "STNAME",
+       "MOU",
+       "UNAME",
+       "TYPEDEF",
+       "FORTRAN",
+       "ENAME",
+       "MOE",
+       "UFORTRAN",
+       "USTATIC",
+       "?????",
+       "?????",
+       "CLNAME",
+       "NSPACE",
+       };
+
+char *
+scnames(int c)
+{
+       /* return the name for storage class c */
+       static char buf[12];
+       if( c&FIELD ){
+               snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ );
+               return( buf );
+               }
+       return( ccnames[c] );
+       }
+#endif
+
+#ifdef os_openbsd
+static char *stack_chk_fail = "__stack_smash_handler";
+static char *stack_chk_guard = "__guard";
+#else
+static char *stack_chk_fail = "__stack_chk_fail";
+static char *stack_chk_guard = "__stack_chk_guard";
+#endif
+static char *stack_chk_canary = "__stack_chk_canary";
+
+void
+sspinit(void)
+{
+       NODE *p;
+
+       p = block(NAME, NIL, NIL, FTN+VOID, 0, 0);
+       p->n_sp = lookup(stack_chk_fail, SNORMAL);
+       defid(p, EXTERN);
+       nfree(p);
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_sp = lookup(stack_chk_guard, SNORMAL);
+       defid(p, EXTERN);
+       nfree(p);
+}
+
+void
+sspstart(void)
+{
+       NODE *p, *q;
+
+       q = block(NAME, NIL, NIL, INT, 0, 0);
+       q->n_sp = lookup(stack_chk_guard, SNORMAL);
+       q = clocal(q);
+
+       p = block(REG, NIL, NIL, INT, 0, 0);
+       glval(p) = 0;
+       p->n_rval = FPREG;
+       q = block(ER, p, q, INT, 0, 0);
+       q = clocal(q);
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_qual = VOL >> TSHIFT;
+       p->n_sp = lookup(stack_chk_canary, SNORMAL);
+       defid(p, AUTO);
+       p = clocal(p);
+       ecomp(buildtree(ASSIGN, p, q));
+}
+
+void
+sspend(void)
+{
+       NODE *p, *q;
+       TWORD t;
+       int lab;
+
+       if (retlab != NOLAB) {
+               plabel(retlab);
+               retlab = getlab();
+       }
+
+       t = DECREF(cftnsp->stype);
+       if (t == BOOL)
+               t = BOOL_TYPE;
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_sp = lookup(stack_chk_canary, SNORMAL);
+       p = clocal(p);
+
+       q = block(REG, NIL, NIL, INT, 0, 0);
+       glval(q) = 0;
+       q->n_rval = FPREG;
+       q = block(ER, p, q, INT, 0, 0);
+
+       p = block(NAME, NIL, NIL, INT, 0, 0);
+       p->n_sp = lookup(stack_chk_guard, SNORMAL);
+       p = clocal(p);
+
+       lab = getlab();
+       cbranch(buildtree(EQ, p, q), bcon(lab));
+
+       p = block(NAME, NIL, NIL, FTN+VOID, 0, 0);
+       p->n_sp = lookup(stack_chk_fail, SNORMAL);
+       p = clocal(p);
+
+       q = eve(bdty(STRING, cftnsp->sname, 0));
+       ecomp(buildtree(CALL, p, q));
+
+       plabel(lab);
+}
+
+/*
+ * Allocate on the permanent heap for inlines, otherwise temporary heap.
+ */
+void *
+blkalloc(int size)
+{
+       return isinlining || blevel < 2 ?  permalloc(size) : tmpalloc(size);
+}
+
+/*
+ * Allocate on the permanent heap for inlines, otherwise temporary heap.
+ */
+void *
+inlalloc(int size)
+{
+       return isinlining ?  permalloc(size) : tmpalloc(size);
+}
+
+/*
+ * Fetch pointer to first member in a struct list.
+ */
+struct symtab *
+strmemb(struct attr *ap)
+{
+
+       if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL)
+               cerror("strmemb");
+       return ap->amlist;
+}
+
+#ifndef NO_COMPLEX
+
+static char *real, *imag;
+static struct symtab *cxsp[3];
+/*
+ * As complex numbers internally are handled as structs, create
+ * these by hand-crafting them.
+ */
+void
+complinit(void)
+{
+       struct attr *ap;
+       struct rstack *rp;
+       NODE *p, *q;
+       char *n[] = { "0f", "0d", "0l" };
+       int i, d_debug;
+
+       d_debug = ddebug;
+       ddebug = 0;
+       real = addname("__real");
+       imag = addname("__imag");
+       p = block(NAME, NIL, NIL, FLOAT, 0, 0);
+       for (i = 0; i < 3; i++) {
+               p->n_type = FLOAT+i;
+               rpole = rp = bstruct(NULL, STNAME, NULL);
+               soumemb(p, real, 0);
+               soumemb(p, imag, 0);
+               q = dclstruct(rp);
+               cxsp[i] = q->n_sp = lookup(addname(n[i]), 0);
+               defid(q, TYPEDEF);
+               ap = attr_new(ATTR_COMPLEX, 0);
+               q->n_sp->sap = attr_add(q->n_sp->sap, ap);
+               nfree(q);
+       }
+       nfree(p);
+       ddebug = d_debug;
+}
+
+/*
+ * Return the highest real floating point type.
+ * Known that at least one type is complex or imaginary.
+ */
+static TWORD
+maxtyp(NODE *l, NODE *r)
+{
+       TWORD tl, tr, t;
+
+       tl = ANYCX(l) ? strmemb(l->n_ap)->stype : l->n_type;
+       tr = ANYCX(r) ? strmemb(r->n_ap)->stype : r->n_type;
+       if (ISITY(tl))
+               tl -= (FIMAG - FLOAT);
+       if (ISITY(tr))
+               tr -= (FIMAG - FLOAT);
+       t = tl > tr ? tl : tr;
+       if (!ISFTY(t))
+               cerror("maxtyp");
+       return t;
+}
+
+/*
+ * Fetch space on stack for complex struct.
+ */
+static NODE *
+cxstore(TWORD t)
+{
+       struct symtab s;
+
+       s = *cxsp[t - FLOAT];
+       s.sclass = AUTO;
+       s.soffset = NOOFFSET;
+       oalloc(&s, &autooff);
+       return nametree(&s);
+}
+
+#define        comop(x,y) buildtree(COMOP, x, y)
+
+static NODE *
+mkcmplx(NODE *p, TWORD dt)
+{
+       NODE *q, *r, *i, *t;
+
+       if (!ANYCX(p)) {
+               /* Not complex, convert to complex on stack */
+               q = cxstore(dt);
+               if (ISITY(p->n_type)) {
+                       p->n_type = p->n_type - FIMAG + FLOAT;
+                       r = bcon(0);
+                       i = p;
+               } else {
+                       r = p;
+                       i = bcon(0);
+               }
+               p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r);
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i));
+               p = comop(p, q);
+       } else {
+               if (strmemb(p->n_ap)->stype != dt) {
+                       q = cxstore(dt);
+                       p = buildtree(ADDROF, p, NIL);
+                       t = tempnode(0, p->n_type, p->n_df, p->n_ap);
+                       p = buildtree(ASSIGN, ccopy(t), p);
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, real),
+                           structref(ccopy(t), STREF, real)));
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag),
+                           structref(t, STREF, imag)));
+                       p = comop(p, q);
+               }
+       }
+       return p;
+}
+
+static NODE *
+cxasg(NODE *l, NODE *r)
+{
+       TWORD tl, tr;
+
+       tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0;
+       tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0;
+
+       if (ANYCX(l) && ANYCX(r) && tl != tr) {
+               /* different types in structs */
+               r = mkcmplx(r, tl);
+       } else if (!ANYCX(l))
+               r = structref(r, DOT, ISITY(l->n_type) ? imag : real);
+       else if (!ANYCX(r))
+               r = mkcmplx(r, tl);
+       return buildtree(ASSIGN, l, r);
+}
+
+/*
+ * Fixup complex operations.
+ * At least one operand is complex.
+ */
+NODE *
+cxop(int op, NODE *l, NODE *r)
+{
+       TWORD mxtyp;
+       NODE *p, *q;
+       NODE *ltemp, *rtemp;
+       NODE *real_l, *imag_l;
+       NODE *real_r, *imag_r;
+
+       if (op == ASSIGN)
+               return cxasg(l, r);
+
+       mxtyp = maxtyp(l, r);
+       l = mkcmplx(l, mxtyp);
+       r = mkcmplx(r, mxtyp);
+
+
+       /* put a pointer to left and right elements in a TEMP */
+       l = buildtree(ADDROF, l, NIL);
+       ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap);
+       l = buildtree(ASSIGN, ccopy(ltemp), l);
+
+       r = buildtree(ADDROF, r, NIL);
+       rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap);
+       r = buildtree(ASSIGN, ccopy(rtemp), r);
+
+       p = comop(l, r);
+
+       /* create the four trees needed for calculation */
+       real_l = structref(ccopy(ltemp), STREF, real);
+       real_r = structref(ccopy(rtemp), STREF, real);
+       imag_l = structref(ltemp, STREF, imag);
+       imag_r = structref(rtemp, STREF, imag);
+
+       /* get storage on stack for the result */
+       q = cxstore(mxtyp);
+
+       switch (op) {
+       case NE:
+       case EQ:
+               tfree(q);
+               p = buildtree(op, comop(p, real_l), real_r);
+               q = buildtree(op, imag_l, imag_r);
+               p = buildtree(op == EQ ? ANDAND : OROR, p, q);
+               return p;
+
+       case PLUS:
+       case MINUS:
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), 
+                   buildtree(op, real_l, real_r)));
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), 
+                   buildtree(op, imag_l, imag_r)));
+               break;
+
+       case MUL:
+               /* Complex mul is "complex" */
+               /* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+                   buildtree(MINUS,
+                   buildtree(MUL, ccopy(real_r), ccopy(real_l)),
+                   buildtree(MUL, ccopy(imag_r), ccopy(imag_l)))));
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag),
+                   buildtree(PLUS,
+                   buildtree(MUL, real_r, imag_l),
+                   buildtree(MUL, imag_r, real_l))));
+               break;
+
+       case DIV:
+               /* Complex div is even more "complex" */
+               /* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+                   buildtree(DIV,
+                     buildtree(PLUS,
+                       buildtree(MUL, ccopy(real_r), ccopy(real_l)),
+                       buildtree(MUL, ccopy(imag_r), ccopy(imag_l))),
+                     buildtree(PLUS,
+                       buildtree(MUL, ccopy(real_r), ccopy(real_r)),
+                       buildtree(MUL, ccopy(imag_r), ccopy(imag_r))))));
+               p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+                   buildtree(DIV,
+                     buildtree(MINUS,
+                       buildtree(MUL, ccopy(imag_l), ccopy(real_r)),
+                       buildtree(MUL, ccopy(real_l), ccopy(imag_r))),
+                     buildtree(PLUS,
+                       buildtree(MUL, ccopy(real_r), ccopy(real_r)),
+                       buildtree(MUL, ccopy(imag_r), ccopy(imag_r))))));
+               tfree(real_r);
+               tfree(real_l);
+               tfree(imag_r);
+               tfree(imag_l);
+               break;
+       default:
+               uerror("illegal operator %s", copst(op));
+       }
+       return comop(p, q);
+}
+
+/*
+ * Fixup imaginary operations.
+ * At least one operand is imaginary, none is complex.
+ */
+NODE *
+imop(int op, NODE *l, NODE *r)
+{
+       NODE *p, *q;
+       TWORD mxtyp;
+       int li, ri;
+
+       li = ri = 0;
+       if (ISITY(l->n_type))
+               li = 1, l->n_type = l->n_type - (FIMAG-FLOAT);
+       if (ISITY(r->n_type))
+               ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT);
+
+       mxtyp = maxtyp(l, r);
+       switch (op) {
+       case ASSIGN:
+               /* if both are imag, store value, otherwise store 0.0 */
+               if (!(li && ri)) {
+                       tfree(r);
+                       r = bcon(0);
+               }
+               p = buildtree(ASSIGN, l, r);
+               p->n_type += (FIMAG-FLOAT);
+               break;
+
+       case PLUS:
+               if (li && ri) {
+                       p = buildtree(PLUS, l, r);
+                       p->n_type += (FIMAG-FLOAT);
+               } else {
+                       /* If one is imaginary and one is real, make complex */
+                       if (li)
+                               q = l, l = r, r = q; /* switch */
+                       q = cxstore(mxtyp);
+                       p = buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, real), l);
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag), r));
+                       p = comop(p, q);
+               }
+               break;
+
+       case MINUS:
+               if (li && ri) {
+                       p = buildtree(MINUS, l, r);
+                       p->n_type += (FIMAG-FLOAT);
+               } else if (li) {
+                       q = cxstore(mxtyp);
+                       p = buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+                           buildtree(UMINUS, r, NIL));
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag), l));
+                       p = comop(p, q);
+               } else /* if (ri) */ {
+                       q = cxstore(mxtyp);
+                       p = buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, real), l);
+                       p = comop(p, buildtree(ASSIGN,
+                           structref(ccopy(q), DOT, imag),
+                           buildtree(UMINUS, r, NIL)));
+                       p = comop(p, q);
+               }
+               break;
+
+       case MUL:
+               p = buildtree(MUL, l, r);
+               if (li && ri)
+                       p = buildtree(UMINUS, p, NIL);
+               if (li ^ ri)
+                       p->n_type += (FIMAG-FLOAT);
+               break;
+
+       case DIV:
+               p = buildtree(DIV, l, r);
+               if (ri && !li)
+                       p = buildtree(UMINUS, p, NIL);
+               if (li ^ ri)
+                       p->n_type += (FIMAG-FLOAT);
+               break;
+       default:
+               cerror("imop");
+               p = NULL;
+       }
+       return p;
+}
+
+NODE *
+cxelem(int op, NODE *p)
+{
+
+       if (ANYCX(p)) {
+               p = structref(p, DOT, op == XREAL ? real : imag);
+       } else if (op == XIMAG) {
+               /* XXX  sanitycheck? */
+               tfree(p);
+               p = bcon(0);
+       }
+       return p;
+}
+
+NODE *
+cxconj(NODE *p)
+{
+       NODE *q, *r;
+
+       /* XXX side effects? */
+       q = cxstore(strmemb(p->n_ap)->stype);
+       r = buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+           structref(ccopy(p), DOT, real));
+       r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag),
+           buildtree(UMINUS, structref(p, DOT, imag), NIL)));
+       return comop(r, q);
+}
+
+/*
+ * Prepare for return.
+ * There may be implicit casts to other types.
+ */
+NODE *
+cxret(NODE *p, NODE *q)
+{
+//printf("cxret\n");
+//fwalk(p, eprint, 0);
+       if (ANYCX(q)) { /* Return complex type */
+               p = mkcmplx(p, strmemb(q->n_ap)->stype);
+       } else if (ISFTY(q->n_type) || ISITY(q->n_type)) { /* real or imag */
+               p = structref(p, DOT, ISFTY(q->n_type) ? real : imag);
+               if (p->n_type != q->n_type)
+                       p = cast(p, q->n_type, 0);
+       } else 
+               cerror("cxred failing type");
+       return p;
+}
+#endif
diff --git a/lang/pcc/pcc/cc/cxxcom/scan.l b/lang/pcc/pcc/cc/cxxcom/scan.l
new file mode 100644 (file)
index 0000000..f6ddd47
--- /dev/null
@@ -0,0 +1,839 @@
+%{
+/*     $Id: scan.l,v 1.7 2016/03/05 15:31:25 ragge Exp $       */
+
+/*
+ * Copyright (c) 2002 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+%}
+
+
+D                      [0-9]
+L                      [a-zA-Z_]
+H                      [a-fA-F0-9]
+E                      [Ee][+-]?{D}+
+P                      [Pp][+-]?{D}+
+FS                     (f|F|l|L)?i?
+IS                     (u|U|l|L)*
+UL                     ({L}|\\u{H}{H}{H}{H}|\\U{H}{H}{H}{H}{H}{H}{H}{H})
+
+%{
+#include <stdlib.h>
+#include <errno.h>  
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "pass1.h"
+#include "cgram.h"
+
+static NODE *cvtdig(int radix);
+static NODE *charcon(void);
+static NODE *wcharcon(void);
+static void control(int);
+static void pragma(void);
+int notype, parbal, inattr, parlvl, nodinit, inoso;
+static int resw(TWORD, int);
+static int namechk(void);
+
+#define        CPP_IDENT       2
+#define        CPP_LINE        3
+#define        CPP_HASH        4
+
+#ifdef STABS
+#define        STABS_LINE(x) if (gflag && cftnsp) stabs_line(x)
+#else
+#define STABS_LINE(x)
+#endif
+#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31
+/* Hack to avoid unnecessary warnings */
+FILE *yyget_in  (void);
+FILE *yyget_out  (void);
+int yyget_leng  (void);
+char *yyget_text  (void);
+void yyset_in (FILE *);
+void yyset_out (FILE *);
+int yyget_debug  (void);
+void yyset_debug (int);
+int yylex_destroy  (void);
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+#endif
+
+%}
+
+%%
+
+"__func__"             {
+                               if (cftnsp == NULL)
+                                       uerror("__func__ outside function");
+                               yylval.strp = cftnsp->sname; /* XXX - not C99 */
+                               return(C_STRING);
+                       }
+"asm"                  { return(C_ASM); }
+"auto"                 {       return resw(AUTO, C_CLASS); }
+"_Bool"                        {       return resw(BOOL, C_TYPE); }
+"break"                        { return(C_BREAK); }
+"case"                 { return(C_CASE); }
+"char"                 {       return resw(CHAR, C_TYPE); }
+"class"                        { yylval.intval = CLNAME; notype=1; return(C_STRUCT); }
+"_Complex"             {       return resw(COMPLEX, C_TYPE); }
+"const"                        {       return resw(CON, C_QUALIFIER); }
+"const_cast"           { yylval.intval = CONST_CAST; return(CXX_CASTS); }
+"continue"             { return(C_CONTINUE); }
+"default"              { return(C_DEFAULT); }
+"delete"               { return(CXX_DELETE); }
+"do"                   { return(C_DO); }
+"double"               {       return resw(DOUBLE, C_TYPE); }
+"dynamic_cast"         { yylval.intval = DYN_CAST; return(CXX_CASTS); }
+"else"                 { return(C_ELSE); }
+"enum"                 { notype=1; return(C_ENUM); }
+"extern"               {       return resw(EXTERN, C_CLASS); }
+"float"                        {       return resw(FLOAT, C_TYPE); }
+"for"                  { return(C_FOR); }
+"goto"                 { notype=1; return(C_GOTO); }
+"if"                   { return(C_IF); }
+"_Imaginary"           {       return resw(IMAG, C_TYPE); }
+"inline"               { return(C_FUNSPEC); }
+"int"                  {       return resw(INT, C_TYPE); }
+"long"                 {       return resw(LONG, C_TYPE); }
+"namespace"            {       return(CXX_NAMESPACE); }
+"new"                  {       notype = 0; return(CXX_NEW); }
+"register"             {       return resw(REGISTER, C_CLASS); }
+"reinterpret_cast"     { yylval.intval = REINT_CAST; return(CXX_CASTS); }
+"restrict"             { ; /* just ignore */ }
+"return"               { return(C_RETURN); }
+"short"                        {       return resw(SHORT, C_TYPE); }
+"signed"               {       return resw(SIGNED, C_TYPE); }
+"sizeof"               { return(C_SIZEOF); }
+"static"               {       return resw(STATIC, C_CLASS); }
+"static_cast"          { yylval.intval = STATIC_CAST; return(CXX_CASTS); }
+"struct"               { yylval.intval = STNAME; notype=1; return(C_STRUCT); }
+"switch"               { return(C_SWITCH); }
+"template"             { return(CXX_TEMPLATE); }
+"typedef"              {       return resw(TYPEDEF, C_CLASS); }
+"typename"             { return(CXX_TYPENAME); }
+"union"                        { yylval.intval = UNAME; notype=1; return(C_STRUCT); }
+"unsigned"             {       return resw(UNSIGNED, C_TYPE); }
+"using"                        { return(CXX_USING); }
+"void"                 {       return resw(VOID, C_TYPE); }
+"volatile"             {       return resw(VOL, C_QUALIFIER); }
+"while"                        { return(C_WHILE); }
+
+{UL}({UL}|{D})*                { return namechk(); }
+0[xX]{H}+{IS}?         { yylval.nodep = cvtdig(16); return(C_ICON); }
+0{D}+{IS}?             { yylval.nodep = cvtdig(8); return(C_ICON); }
+{D}+{IS}?              { yylval.nodep = cvtdig(10); return(C_ICON); }
+L'(\\.|[^\\'])*'       { yylval.nodep = wcharcon(); return(C_ICON); }
+'(\\.|[^\\'])*'                { yylval.nodep = charcon(); return(C_ICON); }
+
+{D}+{E}{FS}?           { yylval.nodep = floatcon(yytext); return(C_FCON); }
+{D}*"."{D}+({E})?{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); }
+{D}+"."{D}*({E})?{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); }
+0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+"."{P}{FS}?   { yylval.nodep = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+{P}{FS}?      { yylval.nodep = fhexcon(yytext); return(C_FCON); }
+
+L?\"(\\.|[^\\"])*\"    { yylval.strp = yytext; return C_STRING; }
+
+"..."                  { return(C_ELLIPSIS); }
+">>="                  { yylval.intval = RSEQ; return(C_ASOP); }
+"<<="                  { yylval.intval = LSEQ; return(C_ASOP); }
+"+="                   { yylval.intval = PLUSEQ; return(C_ASOP); }
+"-="                   { yylval.intval = MINUSEQ; return(C_ASOP); }
+"*="                   { yylval.intval = MULEQ; return(C_ASOP); }
+"/="                   { yylval.intval = DIVEQ; return(C_ASOP); }
+"%="                   { yylval.intval = MODEQ; return(C_ASOP); }
+"&="                   { yylval.intval = ANDEQ; return(C_ASOP); }
+"^="                   { yylval.intval = EREQ; return(C_ASOP); }
+"|="                   { yylval.intval = OREQ; return(C_ASOP); }
+">>"                   { yylval.intval = RS; return(C_SHIFTOP); }
+"<<"                   { yylval.intval = LS; return(C_SHIFTOP); }
+"++"                   { yylval.intval = INCR; return(C_INCOP); }
+"--"                   { yylval.intval = DECR; return(C_INCOP); }
+"->"                   { yylval.intval = STREF; return(C_STROP); }
+"&&"                   { yylval.intval = ANDAND; return(C_ANDAND); }
+"||"                   { yylval.intval = OROR; return(C_OROR); }
+"<="                   { yylval.intval = LE; return(C_RELOP); }
+">="                   { yylval.intval = GE; return(C_RELOP); }
+"=="                   { yylval.intval = EQ; return(C_EQUOP); }
+"!="                   { yylval.intval = NE; return(C_EQUOP); }
+"::"                   { return(CXX_DUALCC); }
+";"                    { notype = 0; return(';'); }
+("{"|"<%")             { notype = 0; return('{'); }
+("}"|"%>")             { if (rpole) notype = 1; return('}'); }
+","                    { if (parbal && !inoso) notype = 0; return(','); }
+":"                    { if (doing_init) nodinit--; return(':'); }
+"="                    { return('='); }
+"("                    { parbal++; notype = 0; return('('); }
+")"                    {       parbal--;
+                               inoso = 0;
+                               if (parbal==0) { notype = 0; }
+                               if (inattr && parlvl == parbal)
+                                       inattr = 0;
+                               return(')'); }
+("["|"<:")             { return('['); }
+("]"|":>")             { return(']'); }
+"."                    { yylval.intval = DOT; return(C_STROP); }
+"&"                    { return('&'); }
+"!"                    { yylval.intval = NOT; return(C_UNOP); }
+"~"                    { yylval.intval = COMPL; return(C_UNOP); }
+"-"                    { return('-'); }
+"+"                    { return('+'); }
+"*"                    { if (parbal && notype == 0) notype = 1; return('*'); }
+"/"                    { yylval.intval = DIV; return(C_DIVOP); }
+"%"                    { yylval.intval = MOD; return(C_DIVOP); }
+"<"                    { yylval.intval = LT; return(C_RELOP); }
+">"                    { yylval.intval = GT; return(C_RELOP); }
+"^"                    { return('^'); }
+"|"                    { return('|'); }
+"?"                    { if (doing_init) nodinit++; return('?'); }
+^#pragma[ \t].*                { pragma(); }
+^#ident[ \t].*         { control(CPP_IDENT); }
+^#line[ \t].*          { control(CPP_LINE); }
+^#.*                   { control(CPP_HASH); }
+
+[ \t\v\f]              { }
+"\n"                   { ++lineno; STABS_LINE(lineno); }
+.                      { /* ignore bad characters */ }
+
+%%
+
+int lineno, issyshdr;
+char *ftitle = "<stdin>";
+
+static int
+namechk(void)
+{      
+       struct symtab *s;
+       int i;
+
+       yylval.strp = addname(yytext);
+
+       while ((i = input()) == ' ' || i == '\t')
+               ;
+       if (i == ':') {
+               if ((i = input()) == ':')
+                       return CXX_MORENM;
+               unput(i);
+               if (doing_init && nodinit == 0)
+                       return(GCC_DESIG);
+               i = ':';
+       }
+       unput(i);
+
+#ifdef GCC_COMPAT
+       if ((i = gcc_keyword(yylval.strp, &yylval.nodep)) > 0)
+               return i;
+#endif
+
+       if (notype)
+               return(C_NAME);
+       s = lookup(yylval.strp, SNOCREAT);
+       return s && s->sclass == TYPEDEF ?  notype=1, C_TYPENAME : C_NAME;
+}
+
+int
+yywrap(void)
+{
+       if (0) unput(0); /* quiet gcc */
+       return(1);
+}
+
+int
+resw(TWORD t, int rv)
+{
+       if (inattr) {
+               yylval.strp = addname(yytext);
+               return C_NAME;
+       }
+
+       switch (rv) {
+       case C_CLASS:
+               yylval.nodep = block(CLASS, NIL, NIL, t, 0, 0);
+               return rv;
+
+       case C_QUALIFIER:
+               yylval.nodep = block(QUALIFIER, NIL, NIL, 0, 0, 0);
+               yylval.nodep->n_qual = t;
+               return rv;
+
+       case C_TYPE:
+               yylval.nodep = mkty(t, 0, 0);
+               notype=1;
+               return(rv);
+
+       default:
+               cerror("resw");
+       }
+       return 0;
+}
+
+#ifndef SOFTFLOAT
+
+static long double
+typround(long double dc, char *e, TWORD *tw)
+{
+       int im = 0;
+
+       *tw = DOUBLE;
+       for (; *e; e++) {
+               switch (*e) {
+               case 'f':
+               case 'F':
+                       *tw = FLOAT;
+                       dc = (float)dc;
+                       break;
+               case 'l':
+               case 'L':
+                       *tw = LDOUBLE;
+                       break;
+               case 'i':
+               case 'I':
+                       im = 1;
+                       break;
+               }
+       }
+       if (*tw == DOUBLE)
+               dc = (double)dc;
+#ifndef NO_COMPLEX
+       if (im)
+               *tw += (FIMAG-FLOAT);
+#endif
+       return dc;
+}
+
+/*
+ * XXX floatcon() and fhexcon() should be in support libraries for
+ * the target floating point.
+ */
+static NODE *
+f2(char *str)
+{
+       TWORD tw;
+       NODE *p;
+       long double dc;
+       char *eptr;
+
+#ifdef HAVE_STRTOLD
+       dc = strtold(str, &eptr); /* XXX - avoid strtod() */
+#else
+       dc = strtod(str, &eptr); /* XXX - avoid strtod() */
+#endif
+       dc = typround(dc, eptr, &tw);
+       p = block(FCON, NIL, NIL, tw, 0, 0);
+       p->n_dcon = fltallo();
+       FCAST(p->n_dcon)->fp = dc;
+       return p;
+}
+
+NODE *
+floatcon(char *s)
+{
+       return f2(s);
+}
+
+static int
+h2n(int ch)
+{
+       if (ch >= '0' && ch <= '9')
+               return ch - '0';
+       if (ch >= 'a' && ch <= 'f')
+               return ch - 'a' + 10;
+       return ch - 'A' + 10;
+       
+}
+
+NODE *
+fhexcon(char *c)
+{
+       TWORD tw;
+       char *ep;
+       long double d;
+       int i, ed;
+       NODE *p;
+
+       d = 0.0;
+       ed = 0;
+       c+= 2; /* skip 0x */
+#define FSET(n) { d *= 2; if (i & n) d += 1.0; }
+       for (; *c != '.' && *c != 'p' && *c != 'P'; c++) {
+               i = h2n(*c);
+               FSET(8); FSET(4); FSET(2); FSET(1);
+       }
+       if (*c != '.' && *c != 'p' && *c != 'P')
+               cerror("fhexcon");
+       if (*c == '.') {
+               c++;
+               for (; *c != 'p' && *c != 'P'; c++) {
+                       i = h2n(*c);
+                       FSET(8); FSET(4); FSET(2); FSET(1);
+                       ed -= 4;
+               }
+       }
+       if (*c != 'P' && *c != 'p')
+               cerror("fhexcon2");
+       c++;
+       ed += strtol(c, &ep, 10);
+
+       /* avoid looping in vain. Idea from Fred J. Tydeman */
+       if (ed > 32769) ed = 32769;
+       if (ed < -32769) ed = -32769;
+
+       while (ed > 0)
+               d *= 2, ed--;
+       while (ed < 0)
+               d /= 2, ed++;
+       d = typround(d, ep, &tw);
+       p = block(FCON, NIL, NIL, tw, 0, 0);
+       p->n_dcon = fltallo();
+       FCAST(p->n_dcon)->fp = d;
+       return p;
+}
+#endif
+
+unsigned int
+esccon(char **sptr)
+{
+       char *wr = *sptr;
+       char *owr;
+       char c;
+       unsigned int val;
+       int wsz = 4, esccon_warn = 1;
+
+       switch (*wr++) {
+       case 'a': val = '\a'; break;
+       case 'b': val = '\b'; break;
+       case 'f': val = '\f'; break;
+       case 'n': val = '\n'; break;
+       case 'r': val = '\r'; break;
+       case 't': val = '\t'; break;
+       case 'v': val = '\v'; break;
+       case '\"': val = '\"'; break;
+       case 'x': val = strtoul(wr, &wr, 16); break;
+       /* ISO/IEC 9099:1999 (E) 6.4.3 */
+       case 'U'|(char)0x80:
+               esccon_warn = 0;
+               /* FALLTHROUGH */
+       case 'U':
+               wsz = 8;
+               /* FALLTHROUGH */
+       case 'u':
+               owr = wr;
+               while (wr < (owr + wsz))
+                       if (*wr == '\0')
+                               break;
+                       else
+                               ++wr;
+               if (wr != (owr + wsz)) {
+                       /* incomplete */
+                       val = strtoul(owr, &wr, 16);
+               } else {
+                       c = owr[wsz];
+                       owr[wsz] = '\0'; /* prevent it from reading too much */
+                       val = strtoul(owr, &wr, 16);
+                       owr[wsz] = c;
+               }
+               if (wr != (owr + wsz))
+                       werror("incomplete universal character name");
+               if (wsz == 4)
+                       val &= 0xFFFF;
+               if (esccon_warn && ((val >= 0xD800 && val <= 0xDFFF) ||
+                   (val < 0xA0 && val != 0x24 && val != 0x40 && val != 0x60)))
+                       werror("invalid universal character name %04X", val);
+               break;
+       case '0': case '1': case '2': case '3': case '4': 
+       case '5': case '6': case '7':
+               val = wr[-1] - '0';
+               if (*wr >= '0' && *wr <= '7') {
+                       val = (val << 3) + (*wr++ - '0');
+                       if (*wr >= '0' && *wr <= '7')
+                               val = (val << 3) + (*wr++ - '0');
+               }
+               break;
+       default: val = wr[-1];
+       }
+       *sptr = wr;
+       return val;
+}
+
+NODE *
+cvtdig(int radix)
+{
+       NODE *p;
+       TWORD otype, ntype;
+       unsigned long long v;
+       char *ch = yytext;
+       int n, numl, numu;
+
+       if (radix == 16)
+               ch += 2; /* Skip 0x */
+       
+       v = 0;
+       while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') ||
+           (*ch >= 'A' && *ch <= 'F')) {
+               v *= radix;
+               n = *ch;
+               n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10);
+               ch++;
+               v += n;
+       }
+       /* Parse trailing chars */
+       ntype = INT;
+       numl = numu = 0;
+       for (n = 0; n < 3; n++) {
+               if (*ch == 0)
+                       break;
+               if ((*ch == 'l' || *ch == 'L') && numl < 2)
+                       ntype+=2, numl++;
+               else if ((*ch == 'u' || *ch == 'U') && numu < 1)
+                       ntype = ENUNSIGN(ntype), numu++;
+               else
+                       break;
+               ch++;
+       }
+       if (*ch)
+               uerror("constant has too many '%c'", *ch);
+
+       otype = ntype;
+       switch (ntype) {
+       case INT:
+       case LONG:
+       case LONGLONG:
+               if (radix == 10) {
+                       if (otype == LONGLONG)
+                               break;
+                       if (v > MAX_LONG) { 
+                               ntype = LONGLONG;
+                               if (otype == LONG)
+                                       break;
+                       } else if (v > MAX_INT)
+                               ntype = LONG;
+               } else {
+                       if (v > MAX_LONGLONG) {
+                               ntype = ULONGLONG;
+                               if (otype == LONGLONG)
+                                       break;
+                       } else if (v > MAX_ULONG) {
+                               ntype = LONGLONG;
+                       } else if (v > MAX_LONG) {
+                               ntype = ULONG;
+                               if (otype == LONG)
+                                       break;
+                       } else if (v > MAX_UNSIGNED) {
+                               ntype = LONG;
+                       } else if (v > MAX_INT)
+                               ntype = UNSIGNED;
+               }
+               break;
+       case UNSIGNED:
+       case ULONG:
+               if (v > MAX_ULONG) {
+                       ntype = ULONGLONG;
+                       if (otype == ULONG)
+                               break;
+               } else if (v > MAX_UNSIGNED)
+                       ntype = ULONG;
+               break;  
+       }       
+
+       ntype = ctype(ntype);
+       p = xbcon(v, NULL, ntype);
+       ASGLVAL(p->n_slval, v);
+
+       return p;
+}
+
+/*
+ * Convert a character constant to an integer.
+ */
+NODE *
+charcon(void)
+{
+       int lastcon = 0;
+       int val, i = 0;
+       char *pp = yytext;
+
+       pp++;   /* skip ' */
+       while (*pp != '\'') {
+               if (*pp++ == '\\') {
+                       val = esccon(&pp);
+               } else
+                       val = pp[-1];
+               makecc(val, i);
+               i++;
+       }
+
+       if (i == 0)
+               uerror("empty character constant");
+       else if (i > (SZINT/SZCHAR) || (i>1))
+               werror("too many characters in character constant");
+       return bcon(lastcon);
+}
+
+NODE *
+wcharcon(void)
+{
+       unsigned int lastcon = 0;
+       unsigned int val, i = 0;
+       char *pp = yytext;
+
+       pp++;   /* skip L */
+       pp++;   /* skip ' */
+       while (*pp != '\'') {
+               if (*pp++ == '\\') {
+                       val = esccon(&pp);
+               } else
+                       val = pp[-1];
+#if WCHAR_SIZE == 2
+               lastcon = (lastcon << 16) | (val & 0xFFFF);
+#else
+               lastcon = val;
+#endif
+               i++;
+       }
+
+       if (i == 0)
+               uerror("empty wide-character constant");
+       else if (i > 1)
+               werror("too many characters in wide-character constant");
+       return xbcon(lastcon, NULL, ctype(UNSIGNED));
+}
+
+void
+control(int t)
+{
+       char *wr = yytext;
+       char *eptr;
+       int val;
+
+       wr++;   /* Skip initial '#' */
+       switch (t) {
+       case CPP_IDENT:
+               return; /* Just skip these for now. */
+
+       case CPP_LINE:
+               wr += 4;
+               /* FALLTHROUGH */
+       case CPP_HASH:
+               val = strtol(wr, &eptr, 10);
+               if (wr == eptr) /* Illegal string */
+                       goto bad;
+               wr = eptr;
+               lineno = val - 1;
+               while (*wr && *wr != '\"')
+                       wr++;
+               if (*wr == 0)
+                       return;
+               if (*wr++ != '\"')
+                       goto bad;
+               eptr = wr;
+               while (*wr && *wr != '\"')
+                       wr++;
+               if (*wr != '\"')
+                       goto bad;
+               *wr = 0;
+               ftitle = addstring(eptr);
+#ifdef STABS
+               if (gflag)
+                       stabs_file(ftitle);
+#endif
+       }
+       return;
+bad:
+       werror("%s: illegal control", yytext);
+}
+
+int pragma_allpacked;
+int pragma_packed, pragma_aligned;
+char *pragma_renamed;
+
+static int
+pragmas_weak(char *str)
+{
+       struct symtab *sp;
+       char *s1, *s2;
+
+       if ((s1 = pragtok(NULL)) == NULL)
+               return 1;
+       if ((s2 = pragtok(NULL)) == NULL) {
+               sp = lookup(addname(s1), SNORMAL);
+#ifdef GCC_COMPAT
+               sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak")));
+#else
+               sp->sap = 0;
+#endif
+       } else if (*s2 == '=') {
+               if ((s2 = pragtok(NULL)) == NULL)
+                       return 1;
+               sp = lookup(addname(s2), SNORMAL);
+#ifdef GCC_COMPAT
+               sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL,
+                   bdty(NAME, "aliasweak"), bdty(STRING, s1, 0))));
+#else
+               sp->sap = NULL;
+#endif
+       } else
+               return 1;
+       return 0;
+}
+
+char *pragstore;
+
+/* trivial tokenizer for pragmas */
+#define ps pragstore
+char *
+pragtok(char *sin)
+{
+       static char ss[2];
+       char *rv;
+
+       if (sin)
+               ps = sin;
+
+       for (; isspace((int)*ps); ps++)
+               ;
+       if (*ps == 0)
+               return NULL;
+       for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++)
+               ;
+       ss[0] = *ps;
+       if (rv == ps) {
+               rv = ss, ps++;
+       } else {
+               *ps = 0;
+               rv = tmpstrdup(rv);
+               *ps = ss[0];
+       }
+       return rv;
+}
+
+/* return 1 on error */
+int
+eat(int ch)
+{
+       char *s = pragtok(0);
+       return (s == 0 || *s != ch);
+}
+
+static int
+pragmas_alpack(char *t)
+{
+       char *s;
+       int ap;
+
+       ap = (s = pragtok(0)) ? atoi(s) : 1;
+       if (strcmp(t, "packed") == 0)
+               pragma_packed = ap;
+       else
+               pragma_aligned = ap;
+       return 0;
+}
+
+
+/*
+ * Packing control.
+ * still missing push/pop.
+ */
+static int
+pragmas_pack(char *t)
+{
+       char *s;
+
+       if (eat('('))
+               return 1;
+       s = pragtok(0);
+       if (*s == ')')
+               return pragma_allpacked = 0;
+
+       if (*s < '0' || *s > '9') /* no number */
+               return 1;
+       pragma_allpacked = atoi(s);
+       return eat(')');
+}
+
+static int
+pragmas_renamed(char *t)
+{
+       char *f = pragtok(0);
+
+       if (f == 0)
+               return 1;
+       pragma_renamed = newstring(f, strlen(f));
+       return 0;
+}
+
+static int
+pragmas_stdc(char *t)
+{
+       return 0; /* Just ignore */
+}
+
+struct pragmas {
+       char *name;
+       int (*fun)(char *);
+} pragmas[] = {
+       { "pack", pragmas_pack },
+       { "packed", pragmas_alpack },
+       { "aligned", pragmas_alpack },
+       { "rename", pragmas_renamed },
+#ifdef GCC_COMPAT
+       { "GCC", pragmas_gcc },
+#endif
+       { "STDC", pragmas_stdc },
+       { "weak", pragmas_weak },
+       { "ident", NULL },
+       { 0 },
+};
+
+/*
+ * got a full pragma line.  Split it up here.
+ */
+static void
+pragma(void)
+{
+       struct pragmas *p;
+       char *t, *pt;
+
+       if ((t = pragtok(&yytext[7])) != NULL) {
+               pt = ps;
+               for (p = pragmas; p->name; p++) {
+                       if (strcmp(t, p->name) == 0) {
+                               if (p->fun && (*p->fun)(t))
+                                       uerror("bad argument to #pragma");
+                               return;
+                       }
+               }
+               ps = pt;
+               if (mypragma(t))
+                       return;
+       }
+       warner(Wunknown_pragmas, t, ps);
+}
+
+void
+cunput(char c)
+{
+       unput(c);
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/softfloat.c b/lang/pcc/pcc/cc/cxxcom/softfloat.c
new file mode 100644 (file)
index 0000000..22ad6da
--- /dev/null
@@ -0,0 +1,359 @@
+/*     $Id: softfloat.c,v 1.1 2012/01/01 16:20:55 ragge Exp $  */
+
+/*
+ * Copyright (c) 2008 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef SOFTFLOAT
+
+#include "pass1.h"
+
+
+/*
+ * Floating point emulation to be used when cross-compiling.
+ * Currently only supports F- and D-float, used in DEC machines.
+ * Should be trivial to add other emulations.
+ *
+ * XXX - assumes that:
+ *     - long long is (at least) 64 bits
+ *     - int is at least 32 bits.
+ *     - short is 16 bits.
+ */
+
+#ifdef FDFLOAT
+
+/*
+ * Useful macros to manipulate the float.
+ */
+#define DSIGN(w)       (((w).fd1 >> 15) & 1)
+#define DSIGNSET(w,s)  ((w).fd1 = (s << 15) | ((w).fd1 & 077777))
+#define DEXP(w)                (((w).fd1 >> 7) & 0377)
+#define DEXPSET(w,e)   ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177))
+#define DMANTH(w)      ((w).fd1 & 0177)
+#define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600))
+
+typedef unsigned int lword;
+typedef unsigned long long dword;
+
+#define MAXMANT 0x100000000000000LL
+
+/*
+ * Returns a zero dfloat.
+ */
+static SF
+nulldf(void)
+{
+       SF rv;
+
+       rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0;
+       return rv;
+}
+
+/*
+ * Convert a (u)longlong to dfloat.
+ * XXX - fails on too large (> 55 bits) numbers.
+ */
+SF
+soft_cast(CONSZ ll, TWORD t)
+{
+       int i;
+       SF rv;
+
+       rv = nulldf();
+       if (ll == 0)
+               return rv;  /* fp is zero */
+       if (ll < 0)
+               DSIGNSET(rv,1), ll = -ll;
+       for (i = 0; ll > 0; i++, ll <<= 1)
+               ;
+       DEXPSET(rv, 192-i);
+       DMANTHSET(rv, ll >> 56);
+       rv.fd2 = ll >> 40;
+       rv.fd3 = ll >> 24;
+       rv.fd4 = ll >> 8;
+       return rv;
+}
+
+/*
+ * multiply two dfloat. Use chop, not round.
+ */
+SF
+soft_mul(SF p1, SF p2)
+{
+       SF rv;
+       lword a1[2], a2[2], res[4];
+       dword sum;
+
+       res[0] = res[1] = res[2] = res[3] = 0;
+
+       /* move mantissa into lwords */
+       a1[0] = p1.fd4 | (p1.fd3 << 16);
+       a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000;
+
+       a2[0] = p2.fd4 | (p2.fd3 << 16);
+       a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000;
+
+#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \
+       res[r] = sum; sum >>= 32;
+
+       sum = 0;
+       MULONE(0, 0, 0);
+       MULONE(1, 0, 1);
+       res[2] = sum;
+       sum = 0;
+       MULONE(0, 1, 1);
+       MULONE(1, 1, 2);
+       res[3] = sum;
+
+       rv.fd1 = 0;
+       DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2));
+       DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128);
+       if (res[3] & 0x8000) {
+               res[3] = (res[3] << 8) | (res[2] >> 24);
+               res[2] = (res[2] << 8) | (res[1] >> 24);
+       } else {
+               DEXPSET(rv, DEXP(rv) - 1);
+               res[3] = (res[3] << 9) | (res[2] >> 23);
+               res[2] = (res[2] << 9) | (res[1] >> 23);
+       }
+       DMANTHSET(rv, res[3] >> 16);
+       rv.fd2 = res[3];
+       rv.fd3 = res[2] >> 16;
+       rv.fd4 = res[2];
+       return rv;
+}
+
+SF
+soft_div(SF t, SF n)
+{
+       SF rv;
+       dword T, N, K;
+       int c;
+
+#define SHL(x,b) ((dword)(x) << b)
+       T = SHL(1,55) | SHL(DMANTH(t), 48) |
+           SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4;
+       N = SHL(1,55) | SHL(DMANTH(n), 48) |
+           SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4;
+
+       c = T > N;
+       for (K = 0; (K & 0x80000000000000ULL) == 0; ) {
+               if (T >= N) {
+                       T -= N;
+                       K |= 1;
+               }
+               T <<= 1;
+               K <<= 1;
+       }
+       rv.fd1 = 0;
+       DSIGNSET(rv, DSIGN(t) ^ DSIGN(n));
+       DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c);
+       DMANTHSET(rv, K >> 48);
+       rv.fd2 = K >> 32;
+       rv.fd3 = K >> 16;
+       rv.fd4 = K;
+       return rv;
+}
+
+/*
+ * Negate a float number. Easy.
+ */
+SF
+soft_neg(SF sf)
+{
+       int sign = DSIGN(sf) == 0;
+       DSIGNSET(sf, sign);
+       return sf;
+}
+
+/*
+ * Return true if fp number is zero.
+ */
+int
+soft_isz(SF sf)
+{
+       return (DEXP(sf) == 0);
+}
+
+int
+soft_cmp_eq(SF x1, SF x2)
+{
+       cerror("soft_cmp_eq");
+       return 0;
+}
+
+int
+soft_cmp_ne(SF x1, SF x2)
+{
+       cerror("soft_cmp_ne");
+       return 0;
+}
+
+int
+soft_cmp_le(SF x1, SF x2)
+{
+       cerror("soft_cmp_le");
+       return 0;
+}
+
+int
+soft_cmp_lt(SF x1, SF x2)
+{
+       cerror("soft_cmp_lt");
+       return 0;
+}
+
+int
+soft_cmp_ge(SF x1, SF x2)
+{
+       cerror("soft_cmp_ge");
+       return 0;
+}
+
+int
+soft_cmp_gt(SF x1, SF x2)
+{
+       cerror("soft_cmp_gt");
+       return 0;
+}
+
+/*
+ * Convert a fp number to a CONSZ.
+ */
+CONSZ
+soft_val(SF sf)
+{
+       CONSZ mant;
+       int exp = DEXP(sf) - 128;
+
+       mant = SHL(1,55) | SHL(DMANTH(sf), 48) |
+            SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4;
+
+       while (exp < 0)
+               mant >>= 1, exp++;
+       while (exp > 0)
+               mant <<= 1, exp--;
+       return mant;
+}
+
+SF
+soft_plus(SF x1, SF x2)
+{
+       cerror("soft_plus");
+       return x1;
+}
+
+SF
+soft_minus(SF x1, SF x2)
+{
+       cerror("soft_minus");
+       return x1;
+}
+
+/*
+ * Convert a hex constant to floating point number.
+ */
+NODE *
+fhexcon(char *s)
+{
+       cerror("fhexcon");
+       return NULL;
+}
+
+/*
+ * Convert a floating-point constant to D-float and store it in a NODE.
+ */
+NODE *
+floatcon(char *s)
+{
+       NODE *p;
+       dword mant;
+       SF fl, flexp, exp5;
+       int exp, negexp, bexp;
+
+       exp = 0;
+       mant = 0;
+#define ADDTO(sum, val) sum = sum * 10 + val - '0'
+       for (; *s >= '0' && *s <= '9'; s++) {
+               if (mant<MAXMANT)
+                       ADDTO(mant, *s);
+               else
+                       exp++;
+       }
+       if (*s == '.') {
+               for (s++; *s >= '0' && *s <= '9'; s++) {
+                       if (mant<MAXMANT) {
+                               ADDTO(mant, *s);
+                               exp--;
+                       }
+               }
+       }
+
+       if ((*s == 'E') || (*s == 'e')) {
+               int eexp = 0, sign = 0;
+               s++;
+               if (*s == '+')
+                       s++;
+               else if (*s=='-')
+                       sign = 1, s++;
+
+               for (; *s >= '0' && *s <= '9'; s++)
+                       ADDTO(eexp, *s);
+               if (sign)
+                       eexp = -eexp;
+               exp = exp + eexp;
+       }
+
+       negexp = 1;
+       if (exp<0) {
+               negexp = -1;
+               exp = -exp;
+       }
+
+
+       flexp = soft_cast(1, INT);
+       exp5 = soft_cast(5, INT);
+       bexp = exp;
+       fl = soft_cast(mant, INT);
+
+       for (; exp; exp >>= 1) {
+               if (exp&01)
+                       flexp = soft_mul(flexp, exp5);
+               exp5 = soft_mul(exp5, exp5);
+       }
+       if (negexp<0)
+               fl = soft_div(fl, flexp);
+       else
+               fl = soft_mul(fl, flexp);
+
+       DEXPSET(fl, DEXP(fl) + negexp*bexp);
+       p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */
+       p->n_dcon = fl;
+       return p;
+}
+#else
+#error missing softfloat definition
+#endif
+#endif
diff --git a/lang/pcc/pcc/cc/cxxcom/stabs.c b/lang/pcc/pcc/cc/cxxcom/stabs.c
new file mode 100644 (file)
index 0000000..fdd63bf
--- /dev/null
@@ -0,0 +1,460 @@
+/*     $Id: stabs.c,v 1.3 2012/04/22 21:07:41 plunky Exp $     */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Simple implementation of the "stabs" debugging format.
+ * Not complete but at least makes it possible to set breakpoints,
+ * examine simple variables and do stack traces.
+ * Based on the stabs documentation that follows gdb.
+ */
+
+#include "pass1.h"
+
+#ifdef STABS
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define        STABHASH        256
+#define        INTNUM          1       /* internal number of type "int" */
+#undef BIT2BYTE /* from external.h */
+#define        BIT2BYTE(x)     ((x)/SZCHAR)
+
+#ifndef STABLBL
+#error macdefs.h must define STABLBL
+#endif
+
+/* defines taken from BSD <stab.h> */
+#define N_GSYM          0x20    /* global symbol */
+#define N_FUN           0x24    /* procedure name */
+#define N_LCSYM         0x28    /* bss segment variable */
+#define N_RSYM          0x40    /* register variable */
+#define N_SLINE         0x44    /* text segment line number */
+#define N_SO            0x64    /* main source file name */
+#define N_LSYM          0x80    /* stack variable */
+#define N_SOL           0x84    /* included source file name */
+#define N_PSYM          0xa0    /* parameter variable */
+#define N_LBRAC         0xc0    /* left bracket */
+#define N_RBRAC         0xe0    /* right bracket */
+
+/*
+ * Local type mapping
+ * Types are defined as a typeword, a dimension pointer (in the case
+ * of arrays) and struct/union/enum declarations.
+ * Function prototypes are ignored.
+ */
+static struct stabtype {
+       struct stabtype *next;  /* linked list */
+       TWORD type;             /* pcc type number */
+       union dimfun *df;       /* dimension of arrays */
+       struct attr *ap;        /* struct/union/enum declarations */
+       int num;                /* local type number */
+} *stabhash[STABHASH];
+static int ntypes;
+static char *curfun;
+static int stablbl = 10;
+extern int inftn;
+
+void ptype(char *name, int num, int inhnum, long long min, long long max);
+struct stabtype *addtype(TWORD, union dimfun *, struct attr *);
+struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue);
+void printtype(struct symtab *s, char *str, int len);
+void cprint(int p2, char *fmt, ...);
+
+#define        MAXPSTR 100
+
+extern int isinlining;
+
+/*
+ * Output type definitions for the stab debugging format.
+ * Note that "int" is always internal number 1.
+ */
+void
+stabs_init(void)
+{
+       struct stabtype *st;
+
+#define        ADDTYPE(y) addtype(y, NULL, 0)
+
+       ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT);
+
+       st = ADDTYPE(CHAR);
+       ptype("char", st->num, st->num, 0, MAX_CHAR);
+       ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT);
+       ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG);
+       ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM,
+            MIN_LONGLONG, MAX_LONGLONG);
+       ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR);
+       ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT);
+       ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED);
+       ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG);
+       ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM,
+           0, MAX_ULONGLONG);
+
+       ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0);
+       ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0);
+       ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0);
+       st = ADDTYPE(VOID);
+       cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n",
+           st->num, st->num, N_LSYM);
+
+}
+
+/*
+ * Print a type in stabs format
+ */
+void
+ptype(char *name, int num, int inhnum, long long min, long long max)
+{
+       cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n",
+           name, num, inhnum, min, max, N_LSYM);
+}
+
+/*
+ * Add a new local type to the hash table.
+ * The search key is the (type, df, sue) triple.
+ */
+struct stabtype *
+addtype(TWORD t, union dimfun *df, struct attr *ap)
+{
+       struct stabtype *st;
+
+       st = permalloc(sizeof(struct stabtype));
+       st->type = t;
+       st->df = df;
+       st->ap = ap;
+       st->num = ++ntypes;
+       st->next = stabhash[t & (STABHASH-1)];
+       stabhash[t & (STABHASH-1)] = st;
+       return st;
+}
+
+/*
+ * Search for a given type and return a type pointer (or NULL).
+ */
+struct stabtype *
+findtype(TWORD t, union dimfun *df, struct attr *ap)
+{
+       struct stabtype *st;
+       union dimfun *dw, *dx;
+       TWORD tw;
+
+       st = stabhash[t & (STABHASH-1)];
+       for (; st; st = st->next) {
+               if (t != st->type || ap != st->ap)
+                       continue;
+               /* Ok, type and sue matches, check dimensions */
+               if (st->df == NULL)
+                       return st; /* no arrays, got match */
+               dw = st->df;
+               dx = df;
+               tw = t;
+               for (; tw > BTMASK; tw = DECREF(tw)) {
+                       if (ISARY(tw)) {
+                               if (dw->ddim == dx->ddim)
+                                       dw++, dx++;
+                               else
+                                       break;
+                       }
+               }
+               if (tw <= BTMASK)
+                       return st;
+       }
+       return NULL;
+}
+
+/*
+ * Print current line number.
+ */
+void
+stabs_line(int line)
+{
+       if (inftn == 0)
+               return; /* ignore */
+#ifdef STAB_LINE_ABSOLUTE
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+           N_SLINE, line, stablbl, stablbl);
+#else
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+           N_SLINE, line, stablbl, curfun, stablbl);
+#endif
+       stablbl++;
+}
+
+/*
+ * Start of block.
+ */
+void
+stabs_lbrac(int blklvl)
+{
+#ifdef STAB_LINE_ABSOLUTE
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+           N_LBRAC, blklvl, stablbl, stablbl);
+#else
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+           N_LBRAC, blklvl, stablbl, curfun, stablbl);
+#endif
+       stablbl++;
+}
+
+/*
+ * End of block.
+ */
+void
+stabs_rbrac(int blklvl)
+{
+#ifdef STAB_LINE_ABSOLUTE
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+           N_RBRAC, blklvl, stablbl, stablbl);
+#else
+       cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+           N_RBRAC, blklvl, stablbl, curfun, stablbl);
+#endif
+       stablbl++;
+}
+
+static char *mainfile;
+
+/*
+ * Print current file and set mark.
+ */
+void
+stabs_file(char *fname)
+{
+       if (mainfile == NULL)
+               mainfile = fname; /* first call */
+       cprint(inftn, "\t.stabs \"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+           fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+       stablbl++;
+}
+
+/*
+ * Print end mark
+ */
+void
+stabs_efile(char *fname)
+{
+       cprint(inftn, "\t.stabs \"\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+           fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+       stablbl++;
+}
+
+/*
+ * Print beginning of function.
+ */
+void
+stabs_func(struct symtab *s)
+{
+       char str[MAXPSTR];
+
+       if ((curfun = s->soname) == NULL)
+               curfun = addname(exname(s->sname));
+       printtype(s, str, sizeof(str));
+       cprint(1, "\t.stabs     \"%s:%c%s\",%d,0,%d,%s\n",
+           curfun, s->sclass == STATIC ? 'f' : 'F', str,
+           N_FUN, 0, curfun);
+}
+
+/*
+ * Print a (complex) type.
+ * Will also create subtypes.
+ * Printed string is like "20=*21=*1".
+ */
+void
+printtype(struct symtab *s, char *ostr, int len)
+{
+       struct stabtype *st;
+       union dimfun *df = s->sdf;
+       struct attr *ap = s->sap;
+       TWORD t = s->stype;
+       int op = 0;
+
+       /* Print out not-yet-found types */
+       if (ISFTN(t))
+               t = DECREF(t);
+       st = findtype(t, df, ap);
+       while (st == NULL && t > BTMASK) {
+               st = addtype(t, df, ap);
+               op+=snprintf(ostr+op, len - op, "%d=", st->num);
+               if (ISFTN(t))
+                       ostr[op++] = 'f';
+               else if (ISPTR(t))
+                       ostr[op++] = '*';
+               else if (ISARY(t)) {
+                       op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1);
+               } else
+                       cerror("printtype: notype");
+               if (ISARY(t))
+                       df++;
+               t = DECREF(t);
+               st = findtype(t, df, ap);
+               if (op > MAXPSTR-10)
+                       cerror("printtype: too difficult expression");
+       }
+       /* print out basic type. may have to be entered in case of sue */
+       snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num);
+       /* snprintf here null-terminated the string */
+}
+
+void
+stabs_newsym(struct symtab *s)
+{
+       extern int fun_inline;
+       char *sname;
+       char ostr[MAXPSTR];
+       OFFSZ suesize, sz;
+
+       if (ISFTN(s->stype))
+               return; /* functions are handled separate */
+
+       if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS ||
+           s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE ||
+           s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype))
+               return; /* XXX - fix structs */
+
+       if ((sname = s->soname) == NULL)
+               sname = exname(s->sname);
+       sz = tsize(s->stype, s->sdf, s->sap);
+       suesize = BIT2BYTE(sz);
+       if (suesize > 32767)
+               suesize = 32767;
+       else if (suesize < -32768)
+               suesize = -32768;
+
+       printtype(s, ostr, sizeof(ostr));
+       switch (s->sclass) {
+       case PARAM:
+               cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n",
+                   sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
+               break;
+
+       case AUTO:
+               cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n",
+                   sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
+               break;
+
+       case STATIC:
+               if (blevel)
+                       cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n",
+                           sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset);
+               else
+                       cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n",
+                           sname, ostr, N_LCSYM, (CONSZ)suesize, sname);
+               break;
+
+       case EXTERN:
+       case EXTDEF:
+               cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n",
+                   sname, ostr, N_GSYM, (CONSZ)suesize);
+               break;
+
+       case REGISTER:
+               cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n",
+                   sname, ostr, N_RSYM, 1, s->soffset);
+               break;
+
+       case SNULL:
+               if (fun_inline)
+                       break;
+               /* FALLTHROUGH */
+       default:
+               cerror("fix stab_newsym; class %d", s->sclass);
+       }
+}
+
+void
+stabs_chgsym(struct symtab *s)
+{
+}
+
+/*
+ * define a struct.
+ */
+void
+stabs_struct(struct symtab *p, struct attr *ap)
+{
+}
+
+struct stabsv {
+       SLIST_ENTRY(stabsv) next;
+       char *str;
+} ;
+static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw };
+
+/*
+ * Global variable debug info is printed out directly.
+ * For functions and their declarations, both the labels and 
+ * the debug info is put into ASM nodes and follows their statements
+ * into pass2.  
+ * Due to the possible unsync between pass1 and 2 and where the 
+ * stabs info for text is sent over the following syncing is used:
+ * curfun == 0
+ *     print out everything; only data will be.
+ * curfun != 0 && inftn == 0
+ *     save in linked list
+ * curfun != 0 && inftn != 0
+ *     print linked list first, empty it, then arg.
+ */
+void
+cprint(int p2, char *fmt, ...)
+{
+#define        CPBSZ   200
+       char buf[CPBSZ];
+       struct stabsv *w;
+       va_list ap;
+       char *str;
+
+       if (isinlining)
+               return; /* XXX do not save any inline functions currently */
+
+       va_start(ap, fmt);
+       if (p2) {
+               if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ)
+                       werror("stab symbol line too long, truncating");
+               str = tmpstrdup(buf);
+               if (inftn == 0) {
+                       w = tmpalloc(sizeof(struct stabsv));
+                       w->str = str;
+                       SLIST_INSERT_LAST(&stpole, w, next);
+               } else {
+                       if (stpole.q_last != &stpole.q_forw) {
+                               SLIST_FOREACH(w, &stpole, next) {
+                                       send_passt(IP_ASM, w->str);
+                               }
+                               SLIST_INIT(&stpole);
+                       }
+                       send_passt(IP_ASM, str);
+               }
+       } else
+               vprintf(fmt, ap);
+       va_end(ap);
+}
+
+#endif
diff --git a/lang/pcc/pcc/cc/cxxcom/symtabs.c b/lang/pcc/pcc/cc/cxxcom/symtabs.c
new file mode 100644 (file)
index 0000000..4f4adce
--- /dev/null
@@ -0,0 +1,469 @@
+/*     $Id: symtabs.c,v 1.4 2015/09/15 20:01:10 ragge Exp $    */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+/*
+ * These definitions are used in the patricia tree that stores
+ * the strings.
+ */
+#define        LEFT_IS_LEAF            0x80000000
+#define        RIGHT_IS_LEAF           0x40000000
+#define        IS_LEFT_LEAF(x)         (((x) & LEFT_IS_LEAF) != 0)
+#define        IS_RIGHT_LEAF(x)        (((x) & RIGHT_IS_LEAF) != 0)
+#define        BITNO(x)                ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
+#define        CHECKBITS               8
+
+struct tree {
+       int bitno;
+       struct tree *lr[2];
+};
+
+static struct tree *firstname;
+int nametabs, namestrlen;
+static struct tree *firststr;
+int strtabs, strstrlen;
+static char *symtab_add(char *key, struct tree **, int *, int *);
+int lastloc = NOSEG;
+
+#define        P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
+#define        getree() permalloc(sizeof(struct tree))
+
+char *
+addname(char *key)      
+{
+       return symtab_add(key, &firstname, &nametabs, &namestrlen);
+}
+
+char *
+addstring(char *key)
+{
+       return symtab_add(key, &firststr, &strtabs, &strstrlen);
+}
+
+/*
+ * Add a name to the name stack (if its non-existing),
+ * return its address.
+ * This is a simple patricia implementation.
+ */
+static char *
+symtab_add(char *key, struct tree **first, int *tabs, int *stlen)
+{
+       struct tree *w, *new, *last;
+       int cix, bit, fbit, svbit, ix, bitno, len;
+       char *m, *k, *sm;
+
+       /* Count full string length */
+       for (k = key, len = 0; *k; k++, len++)
+               ;
+       
+       switch (*tabs) {
+       case 0:
+               *first = (struct tree *)newstring(key, len);
+               *stlen += (len + 1);
+               (*tabs)++;
+               return (char *)*first;
+
+       case 1:
+               m = (char *)*first;
+               svbit = 0; /* XXX why? */
+               break;
+
+       default:
+               w = *first;
+               bitno = len * CHECKBITS;
+               for (;;) {
+                       bit = BITNO(w->bitno);
+                       fbit = bit > bitno ? 0 : P_BIT(key, bit);
+                       svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+                           IS_LEFT_LEAF(w->bitno);
+                       w = w->lr[fbit];
+                       if (svbit) {
+                               m = (char *)w;
+                               break;
+                       }
+               }
+       }
+
+       sm = m;
+       k = key;
+
+       /* Check for correct string and return */
+       for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
+               ;
+       if (*m == 0 && *k == 0)
+               return sm;
+
+       ix = *m ^ *k;
+       while ((ix & 1) == 0)
+               ix >>= 1, cix++;
+
+       /* Create new node */
+       new = getree();
+       bit = P_BIT(key, cix);
+       new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       new->lr[bit] = (struct tree *)newstring(key, len);
+       *stlen += (len + 1);
+
+       if ((*tabs)++ == 1) {
+               new->lr[!bit] = *first;
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+               *first = new;
+               return (char *)new->lr[bit];
+       }
+
+
+       w = *first;
+       last = NULL;
+       for (;;) {
+               fbit = w->bitno;
+               bitno = BITNO(w->bitno);
+               if (bitno == cix)
+                       cerror("bitno == cix");
+               if (bitno > cix)
+                       break;
+               svbit = P_BIT(key, bitno);
+               last = w;
+               w = w->lr[svbit];
+               if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+                       break;
+       }
+
+       new->lr[!bit] = w;
+       if (last == NULL) {
+               *first = new;
+       } else {
+               last->lr[svbit] = new;
+               last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       }
+       if (bitno < cix)
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+       return (char *)new->lr[bit];
+}
+
+static struct tree *sympole[NSTYPES];
+static struct symtab *tmpsyms[NSTYPES];
+int numsyms[NSTYPES];
+
+/*
+ * Inserts a symbol into the symbol tree.
+ * Returns a struct symtab.
+ */
+struct symtab *
+lookup(char *key, int stype)
+{
+       struct symtab *sym;
+       struct tree *w, *new, *last;
+       int cix, bit, fbit, svbit, bitno;
+       int type, uselvl;
+       intptr_t ix, match, code = (intptr_t)key;
+
+       type = stype & SMASK;
+       uselvl = (blevel > 0 && type != SSTRING);
+
+       /*
+        * The local symbols are kept in a simple linked list.
+        * Check this list first.
+        */
+       if (blevel > 0)
+               for (sym = tmpsyms[type]; sym; sym = sym->snext)
+                       if (sym->sname == key)
+                               return sym;
+
+       switch (numsyms[type]) {
+       case 0:
+               if (stype & SNOCREAT)
+                       return NULL;
+               if (uselvl) {
+                       sym = getsymtab(key, stype|STEMP);
+                       sym->snext = tmpsyms[type];
+                       tmpsyms[type] = sym;
+                       return sym;
+               }
+               sympole[type] = (struct tree *)getsymtab(key, stype);
+               numsyms[type]++;
+               return (struct symtab *)sympole[type];
+
+       case 1:
+               w = (struct tree *)sympole[type];
+               svbit = 0; /* XXX why? */
+               break;
+
+       default:
+               w = sympole[type];
+               for (;;) {
+                       bit = BITNO(w->bitno);
+                       fbit = (code >> bit) & 1;
+                       svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+                           IS_LEFT_LEAF(w->bitno);
+                       w = w->lr[fbit];
+                       if (svbit)
+                               break;
+               }
+       }
+
+       sym = (struct symtab *)w;
+       match = (intptr_t)sym->sname;
+
+       ix = code ^ match;
+       if (ix == 0)
+               return sym;
+       else if (stype & SNOCREAT)
+               return NULL;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("        adding %s as %s at level %d\n",
+                   key, uselvl ? "temp" : "perm", blevel);
+#endif
+
+       /*
+        * Insert into the linked list, if feasible.
+        */
+       if (uselvl) {
+               sym = getsymtab(key, stype|STEMP);
+               sym->snext = tmpsyms[type];
+               tmpsyms[type] = sym;
+               return sym;
+       }
+
+       /*
+        * Need a new node. If type is SNORMAL and inside a function
+        * the node must be allocated as permanent anyway.
+        * This could be optimized by adding a remove routine, but it
+        * may be more trouble than it is worth.
+        */
+       if (stype == (STEMP|SNORMAL))
+               stype = SNORMAL;
+
+       for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++)
+               ;
+
+       new = stype & STEMP ? tmpalloc(sizeof(struct tree)) :
+           permalloc(sizeof(struct tree));
+       bit = (code >> cix) & 1;
+       new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       new->lr[bit] = (struct tree *)getsymtab(key, stype);
+       if (numsyms[type]++ == 1) {
+               new->lr[!bit] = sympole[type];
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+               sympole[type] = new;
+               return (struct symtab *)new->lr[bit];
+       }
+
+
+       w = sympole[type];
+       last = NULL;
+       for (;;) {
+               fbit = w->bitno;
+               bitno = BITNO(w->bitno);
+               if (bitno == cix)
+                       cerror("bitno == cix");
+               if (bitno > cix)
+                       break;
+               svbit = (code >> bitno) & 1;
+               last = w;
+               w = w->lr[svbit];
+               if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+                       break;
+       }
+
+       new->lr[!bit] = w;
+       if (last == NULL) {
+               sympole[type] = new;
+       } else {
+               last->lr[svbit] = new;
+               last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+       }
+       if (bitno < cix)
+               new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+       return (struct symtab *)new->lr[bit];
+}
+
+void
+symclear(int level)
+{
+       struct symtab *s;
+       int i;
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("symclear(%d)\n", level);
+#endif
+       if (level < 1) {
+               for (i = 0; i < NSTYPES; i++) {
+                       s = tmpsyms[i];
+                       tmpsyms[i] = 0;
+                       if (i != SLBLNAME)
+                               continue;
+                       while (s != NULL) {
+                               if (s->soffset < 0)
+                                       uerror("label '%s' undefined",s->sname);
+                               s = s->snext;
+                       }
+               }
+       } else {
+               for (i = 0; i < NSTYPES; i++) {
+                       if (i == SLBLNAME)
+                               continue; /* function scope */
+                       while (tmpsyms[i] != NULL &&
+                           tmpsyms[i]->slevel > level) {
+                               tmpsyms[i] = tmpsyms[i]->snext;
+                       }
+               }
+       }
+}
+
+struct symtab *
+hide(struct symtab *sym)
+{
+       struct symtab *new;
+       int typ = sym->sflags & SMASK;
+
+       new = getsymtab(sym->sname, typ|STEMP);
+       new->snext = tmpsyms[typ];
+       tmpsyms[typ] = new;
+
+       warner(Wshadow, sym->sname, sym->slevel ? "local" : "global");
+
+#ifdef PCC_DEBUG
+       if (ddebug)
+               printf("\t%s hidden at level %d (%p -> %p)\n",
+                   sym->sname, blevel, sym, new);
+#endif
+       return new;
+}
+
+/*
+ * Extract correct segment for the specified symbol and call
+ * target routines to print it out.
+ * If symtab entry is specified, output alignment as well.
+ */
+void
+locctr(int seg, struct symtab *sp)
+{
+#ifdef GCC_COMPAT
+       struct attr *ga;
+#endif
+
+       if (seg == NOSEG) {
+               ;
+       } else if (sp == NULL) {
+               if (lastloc != seg)
+                       setseg(seg, NULL);
+#ifdef GCC_COMPAT
+       } else if ((ga = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL) {
+               setseg(NMSEG, ga->sarg(0));
+               seg = NOSEG;
+#endif
+       } else {
+               if (seg == DATA) {
+                       if (ISCON(cqual(sp->stype, sp->squal)))
+                               seg = RDATA;
+                       else if (sp->sclass == STATIC)
+                               seg = LDATA;
+               }
+               if (sp->sflags & STLS) {
+                       if (seg == DATA || seg == LDATA)
+                               seg = TLSDATA;
+                       if (seg == UDATA) seg = TLSUDATA;
+               } else if (kflag) {
+                       if (seg == DATA) seg = PICDATA;
+                       if (seg == RDATA) seg = PICRDATA;
+                       if (seg == LDATA) seg = PICLDATA;
+               }
+               if (lastloc != seg)
+                       setseg(seg, NULL);
+       }
+       lastloc = seg;
+
+       /* setup alignment */
+#ifndef ALFTN
+#define        ALFTN   ALINT
+#endif
+       if (sp) {
+               int al;
+
+               if (ISFTN(sp->stype)) {
+                       al = ALFTN;
+               } else
+                       al = talign(sp->stype, sp->sap);
+               defalign(al);
+               symdirec(sp);
+       }
+}
+
+#ifndef MYALIGN
+void
+defalign(int al)
+{
+#ifdef HASP2ALIGN
+#define        P2ALIGN(x)      ispow2(x)
+#else
+#define        P2ALIGN(x)      (x)
+#endif
+       if (al != ALCHAR)
+               printf("\t.align %d\n", P2ALIGN(al/ALCHAR));
+}
+#endif
+
+#ifndef MYDIREC
+/*
+ * Directives given as attributes to symbols.
+ */
+void
+symdirec(struct symtab *sp)
+{
+#ifdef GCC_COMPAT
+       struct attr *ga;
+       char *name;
+
+       if ((name = sp->soname) == NULL)
+               name = exname(sp->sname);
+       if ((ga = attr_find(sp->sap, GCC_ATYP_WEAK)) != NULL)
+               printf("\t.weak %s\n", name);
+       if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
+           strcmp(ga->sarg(0), "default"))
+               printf("\t.%s %s\n", ga->sarg(0), name);
+       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIASWEAK))) {
+               printf("\t.weak %s\n", ga->sarg(0));
+               printf("\t.set %s,%s\n", ga->sarg(0), name);
+       }
+#endif
+}
+#endif
+
+char *
+getexname(struct symtab *sp)
+{  
+       char *s;
+       if ((s = sp->soname) == NULL)
+               s = addname(exname(sp->sname));
+       return s;
+}
diff --git a/lang/pcc/pcc/cc/cxxcom/trees.c b/lang/pcc/pcc/cc/cxxcom/trees.c
new file mode 100644 (file)
index 0000000..886c2c0
--- /dev/null
@@ -0,0 +1,3322 @@
+/*     $Id: trees.c,v 1.21 2016/03/05 15:31:25 ragge Exp $     */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Some of the changes from 32V include:
+ * - Understand "void" as type.
+ * - Handle enums as ints everywhere.
+ * - Convert some C-specific ops into branches.
+ */
+
+# include "pass1.h"
+# include "pass2.h"
+
+# include <stdarg.h>
+# include <string.h>
+
+static void chkpun(NODE *p);
+static int opact(NODE *p);
+static int moditype(TWORD);
+static NODE *strargs(NODE *);
+static void rmcops(NODE *p);
+static NODE *tymatch(NODE *p);
+void putjops(NODE *, void *);
+static void p2tree(NODE *);
+static struct symtab *findmember(struct symtab *, char *);
+int inftn; /* currently between epilog/prolog */
+
+static char *tnames[] = {
+       "undef",
+       "farg",
+       "char",
+       "unsigned char",
+       "short",
+       "unsigned short",
+       "int",
+       "unsigned int",
+       "long",
+       "unsigned long",
+       "long long",
+       "unsigned long long",
+       "float",
+       "double",
+       "long double",
+       "strty",
+       "unionty",
+       "enumty",
+       "moety",
+       "void",
+       "signed", /* pass1 */
+       "bool", /* pass1 */
+       "fimag", /* pass1 */
+       "dimag", /* pass1 */
+       "limag", /* pass1 */
+       "fcomplex", /* pass1 */
+       "dcomplex", /* pass1 */
+       "lcomplex", /* pass1 */
+       "enumty", /* pass1 */
+       "?", "?"
+};
+
+/*     some special actions, used in finding the type of nodes */
+# define NCVT 01
+# define PUN 02
+# define TYPL 04
+# define TYPR 010
+# define TYMATCH 040
+# define LVAL 0100
+# define CVTO 0200
+# define CVTL 0400
+# define CVTR 01000
+# define PTMATCH 02000
+# define OTHER 04000
+# define NCVTR 010000
+# define PROML 020000  /* promote left operand */
+
+/* node conventions:
+
+       NAME:   rval>0 is stab index for external
+               rval<0 is -inlabel number
+               lval is offset in bits
+       ICON:   lval has the value
+               rval has the STAB index, or - label number,
+                       if a name whose address is in the constant
+               rval = NONAME means no name
+       REG:    rval is reg. identification cookie
+
+       */
+
+extern int negrel[];
+
+/* Have some defaults for most common targets */
+#ifndef WORD_ADDRESSED
+#define        offcon(o,t,d,ap) xbcon((o/SZCHAR), NULL, INTPTR)
+#define        VBLOCK(p,b,t,d,a) buildtree(DIV, p, b)
+#define        MBLOCK(p,b,t,d,a) buildtree(MUL, p, b)
+#else
+#define        VBLOCK(p,b,t,d,a) block(PVCONV, p, b, t, d, a)
+#define        MBLOCK(p,b,t,d,a) block(PMCONV, p, b, t, d, a)
+#endif
+
+NODE *
+buildtree(int o, NODE *l, NODE *r)
+{
+       NODE *p, *q;
+       int actions;
+       int opty, n;
+       struct symtab *sp = NULL; /* XXX gcc */
+       NODE *lr, *ll;
+
+#ifdef PCC_DEBUG
+       if (bdebug) {
+               printf("buildtree(%s, %p, %p)\n", copst(o), l, r);
+               if (l) fwalk(l, eprint, 0);
+               if (r) fwalk(r, eprint, 0);
+       }
+#endif
+       opty = coptype(o);
+
+       /* check for constants */
+
+       if (o == ANDAND || o == OROR || o == NOT) {
+               if (l->n_op == FCON) {
+                       p = bcon(!FLOAT_ISZERO(FCAST(l->n_dcon)));
+                       nfree(l);
+                       l = p;
+               }
+               if (o != NOT && r->n_op == FCON) {
+                       p = bcon(!FLOAT_ISZERO(FCAST(r->n_dcon)));
+                       nfree(r);
+                       r = p;
+               }
+       }
+
+       if( opty == UTYPE && l->n_op == ICON ){
+
+               switch( o ){
+
+               case NOT:
+               case UMINUS:
+               case COMPL:
+                       if( conval( l, o, l ) ) return(l);
+                       break;
+               }
+       } else if (o == NOT && l->n_op == FCON) {
+               l = clocal(block(SCONV, l, NIL, INT, 0, 0));
+       } else if( o == UMINUS && l->n_op == FCON ){
+                       FLOAT_NEG(FCAST(l->n_dcon));
+                       return(l);
+
+       } else if( o==QUEST &&
+           (l->n_op==ICON || (l->n_op==NAME && ISARY(l->n_type)))) {
+               CONSZ c = glval(l);
+               if (l->n_op==NAME)
+                       c = 1; /* will become constant later */
+               nfree(l);
+               if (c) {
+                       walkf(r->n_right, putjops, 0);
+                       tfree(r->n_right);
+                       l = r->n_left;
+               } else {
+                       walkf(r->n_left, putjops, 0);
+                       tfree(r->n_left);
+                       l = r->n_right;
+               }
+               nfree(r);
+               return(l);
+       } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){
+
+               switch( o ){
+
+               case PLUS:
+               case MINUS:
+               case MUL:
+               case DIV:
+               case MOD:
+                       /*
+                        * Do type propagation for simple types here.
+                        * The constant value is correct anyway.
+                        * Maybe this op shortcut should be removed?
+                        */
+                       if (l->n_sp == NULL && r->n_sp == NULL &&
+                           l->n_type < BTMASK && r->n_type < BTMASK) {
+                               if (l->n_type > r->n_type)
+                                       r->n_type = l->n_type;
+                               else
+                                       l->n_type = r->n_type;
+                       }
+                       /* FALLTHROUGH */
+               case ULT:
+               case UGT:
+               case ULE:
+               case UGE:
+               case LT:
+               case GT:
+               case LE:
+               case GE:
+               case EQ:
+               case NE:
+               case ANDAND:
+               case OROR:
+               case AND:
+               case OR:
+               case ER:
+               case LS:
+               case RS:
+                       if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) {
+                               if( conval( l, o, r ) ) {
+                                       nfree(r);
+                                       return(l);
+                               }
+                       }
+                       break;
+               }
+       } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) &&
+           (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS ||
+           o == MUL || o == DIV || (o >= EQ && o <= GT) )) {
+#define D(x)   ((FLT *)x)
+#ifndef CC_DIV_0
+               if (o == DIV &&
+                   ((r->n_op == ICON && glval(r) == 0) ||
+                    (r->n_op == FCON && FLOAT_EQ(D(r->n_dcon), FLOAT_ZERO))))
+                               goto runtime; /* HW dependent */
+#endif
+               if (l->n_op == ICON) {
+                       if (!concast(l, r->n_type))
+                               cerror("fail cast const");
+               } else if (r->n_op == ICON) {
+                       if (!concast(r, l->n_type))
+                               cerror("fail cast const");
+               }
+
+               switch(o){
+               case PLUS:
+               case MINUS:
+               case MUL:
+               case DIV:
+                       switch (o) {
+                       case PLUS:
+                               FLOAT_PLUS(l, r);
+                               break;
+                       case MINUS:
+                               FLOAT_MINUS(l, r);
+                               break;
+                       case MUL:
+                               FLOAT_MUL(l, r);
+                               break;
+                       case DIV:
+                               FLOAT_DIV(l, r);
+                               break;
+                       }
+                       nfree(r);
+                       return(l);
+               case EQ:
+               case NE:
+               case LE:
+               case LT:
+               case GE:
+               case GT:
+                       switch (o) {
+                       case EQ:
+                               n = FLOAT_EQ(D(l->n_dcon), D(r->n_dcon));
+                               break;
+                       case NE:
+                               n = FLOAT_NE(D(l->n_dcon), D(r->n_dcon));
+                               break;
+                       case LE:
+                               n = FLOAT_LE(D(l->n_dcon), D(r->n_dcon));
+                               break;
+                       case LT:
+                               n = FLOAT_LT(D(l->n_dcon), D(r->n_dcon));
+                               break;
+                       case GE:
+                               n = FLOAT_GE(D(l->n_dcon), D(r->n_dcon));
+                               break;
+                       case GT:
+                               n = FLOAT_GT(D(l->n_dcon), D(r->n_dcon));
+                               break;
+                       default:
+                               n = 0; /* XXX flow analysis */
+                       }
+                       nfree(r);
+                       nfree(l);
+                       return bcon(n);
+               }
+       }
+#ifndef CC_DIV_0
+runtime:
+#endif
+       /* its real; we must make a new node */
+
+       p = block(o, l, r, INT, 0, 0);
+
+       actions = opact(p);
+
+       if (actions & PROML)
+               p->n_left = intprom(p->n_left);
+
+       if (actions & LVAL) { /* check left descendent */
+               if (notlval(p->n_left)) {
+                       uerror("lvalue required");
+                       nfree(p);
+                       return l;
+#ifdef notyet
+               } else {
+                       if ((l->n_type > BTMASK && ISCON(l->n_qual)) ||
+                           (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT)))
+                               if (blevel > 0)
+                                       uerror("lvalue is declared const");
+#endif
+               }
+       }
+
+       if( actions & NCVTR ){
+               p->n_left = pconvert( p->n_left );
+               }
+       else if( !(actions & NCVT ) ){
+               switch( opty ){
+
+               case BITYPE:
+                       p->n_right = pconvert( p->n_right );
+                       /* FALLTHROUGH */
+               case UTYPE:
+                       p->n_left = pconvert( p->n_left );
+
+                       }
+               }
+
+       if ((actions&PUN) && (o!=CAST))
+               chkpun(p);
+
+       if( actions & (TYPL|TYPR) ){
+
+               q = (actions&TYPL) ? p->n_left : p->n_right;
+
+               p->n_type = q->n_type;
+               p->n_qual = q->n_qual;
+               p->n_df = q->n_df;
+               p->n_ap = q->n_ap;
+               }
+
+       if( actions & CVTL ) p = convert( p, CVTL );
+       if( actions & CVTR ) p = convert( p, CVTR );
+       if( actions & TYMATCH ) p = tymatch(p);
+       if( actions & PTMATCH ) p = ptmatch(p);
+
+       if( actions & OTHER ){
+               struct symtab *sp1;
+
+               l = p->n_left;
+               r = p->n_right;
+
+               switch(o){
+
+               case NAME:
+                       cerror("buildtree NAME");
+
+               case STREF:
+                       /* p->x turned into *(p+offset) */
+                       /* rhs must be a name; check correctness */
+
+                       /* Find member symbol struct */
+                       if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){
+                               uerror("struct or union required");
+                               break;
+                       }
+
+                       if ((sp1 = strmemb(l->n_ap)) == NULL) {
+                               uerror("undefined struct or union");
+                               break;
+                       }
+
+                       if ((sp = findmember(sp1, r->n_name)) == NULL) {
+                               uerror("member '%s' not declared", r->n_name);
+                               break;
+                       }
+
+                       r->n_sp = sp;
+                       p = stref(p);
+                       break;
+
+               case UMUL:
+                       if (l->n_op == ADDROF) {
+                               nfree(p);
+                               p = nfree(l);
+                       }
+                       if( !ISPTR(l->n_type))uerror("illegal indirection");
+                       p->n_type = DECREF(l->n_type);
+                       p->n_qual = DECREF(l->n_qual);
+                       p->n_df = l->n_df;
+                       p->n_ap = l->n_ap;
+                       break;
+
+               case ADDROF:
+                       switch( l->n_op ){
+
+                       case UMUL:
+                               nfree(p);
+                               p = nfree(l);
+                               /* FALLTHROUGH */
+                       case TEMP:
+                       case NAME:
+                               p->n_type = INCREF(l->n_type);
+                               p->n_qual = INCQAL(l->n_qual);
+                               p->n_df = l->n_df;
+                               p->n_ap = l->n_ap;
+                               break;
+
+                       case COMOP:
+                               nfree(p);
+                               lr = buildtree(ADDROF, l->n_right, NIL);
+                               p = buildtree( COMOP, l->n_left, lr );
+                               nfree(l);
+                               break;
+
+                       case QUEST:
+                               lr = buildtree( ADDROF, l->n_right->n_right, NIL );
+                               ll = buildtree( ADDROF, l->n_right->n_left, NIL );
+                               nfree(p); nfree(l->n_right);
+                               p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) );
+                               nfree(l);
+                               break;
+
+                       default:
+                               uerror("unacceptable operand of &: %d", l->n_op );
+                               break;
+                               }
+                       break;
+
+               case LS:
+               case RS: /* must make type size at least int... */
+                       if (p->n_type == CHAR || p->n_type == SHORT) {
+                               p->n_left = makety(l, INT, 0, 0, 0);
+                       } else if (p->n_type == UCHAR || p->n_type == USHORT) {
+                               p->n_left = makety(l, UNSIGNED, 0, 0, 0);
+                       }
+                       l = p->n_left;
+                       p->n_type = l->n_type;
+                       p->n_qual = l->n_qual;
+                       p->n_df = l->n_df;
+                       p->n_ap = l->n_ap;
+
+                       /* FALLTHROUGH */
+               case LSEQ:
+               case RSEQ: /* ...but not for assigned types */
+                       if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT)
+                               p->n_right = makety(r, INT, 0, 0, 0);
+                       break;
+
+               case RETURN:
+               case ASSIGN:
+               case CAST:
+                       /* structure assignment */
+                       /* take the addresses of the two sides; then make an
+                        * operator using STASG and
+                        * the addresses of left and right */
+
+                       if (strmemb(l->n_ap) != strmemb(r->n_ap))
+                               uerror("assignment of different structures");
+
+                       r = buildtree(ADDROF, r, NIL);
+
+                       l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap);
+                       l = clocal(l);
+
+                       if( o == RETURN ){
+                               nfree(p);
+                               p = l;
+                               break;
+                       }
+
+                       p->n_op = UMUL;
+                       p->n_left = l;
+                       p->n_right = NIL;
+                       break;
+
+               case QUEST: /* fixup types of : */
+                       if (r->n_left->n_type != p->n_type)
+                               r->n_left = makety(r->n_left, p->n_type,
+                                   p->n_qual, p->n_df, p->n_ap);
+                       if (r->n_right->n_type != p->n_type)
+                               r->n_right = makety(r->n_right, p->n_type,
+                                   p->n_qual, p->n_df, p->n_ap);
+                       break;
+
+               case COLON:
+                       /* structure colon */
+
+                       if (strmemb(l->n_ap) != strmemb(r->n_ap))
+                               uerror( "type clash in conditional" );
+                       break;
+
+               case CALL:
+                       p->n_right = r = strargs(p->n_right);
+                       p = funcode(p);
+                       /* FALLTHROUGH */
+               case UCALL:
+                       if (!ISPTR(l->n_type))
+                               uerror("illegal function");
+                       p->n_type = DECREF(l->n_type);
+                       if (!ISFTN(p->n_type))
+                               uerror("illegal function");
+                       p->n_type = DECREF(p->n_type);
+                       p->n_df = l->n_df+1; /* add one for prototypes */
+                       p->n_ap = l->n_ap;
+                       if (p->n_type == STRTY || p->n_type == UNIONTY) {
+                               /* function returning structure */
+                               /*  make function really return ptr to str., with * */
+
+                               p->n_op += STCALL-CALL;
+                               p->n_type = INCREF(p->n_type);
+                               p = clocal(p); /* before recursing */
+                               p = buildtree(UMUL, p, NIL);
+
+                               }
+                       break;
+
+               default:
+                       cerror( "other code %d", o );
+                       }
+
+               }
+
+       /*
+        * Allow (void)0 casts.
+        * XXX - anything on the right side must be possible to cast.
+        * XXX - remove void types further on.
+        */
+       if (p->n_op == CAST && p->n_type == VOID &&
+           p->n_right->n_op == ICON)
+               p->n_right->n_type = VOID;
+
+       if (actions & CVTO)
+               p = oconvert(p);
+       p = clocal(p);
+
+#ifdef PCC_DEBUG
+       if (bdebug) {
+               printf("End of buildtree:\n");
+               fwalk(p, eprint, 0);
+       }
+#endif
+
+       return(p);
+
+       }
+
+/* Find a member in a struct or union.  May be an unnamed member */
+static struct symtab *
+findmember(struct symtab *sp, char *s)
+{
+       struct symtab *sp2, *sp3;
+
+       for (; sp != NULL; sp = sp->snext) {
+               if (sp->sname[0] == '*') {
+                       /* unnamed member, recurse down */
+                       if ((sp2 = findmember(strmemb(sp->sap), s))) {
+                               sp3 = tmpalloc(sizeof (struct symtab));
+                               *sp3 = *sp2;
+                               sp3->soffset += sp->soffset;
+                               return sp3;
+                       }
+               } else if (sp->sname == s)
+                       return sp;
+       }
+       return NULL;
+}
+
+
+/*
+ * Check if there will be a lost label destination inside of a ?:
+ * It cannot be reached so just print it out.
+ */
+void
+putjops(NODE *p, void *arg)
+{
+       if (p->n_op == COMOP && p->n_left->n_op == GOTO)
+               plabel((int)glval(p->n_left->n_left)+1);
+}
+
+/*
+ * Build a name node based on a symtab entry.
+ * broken out from buildtree().
+ */
+NODE *
+nametree(struct symtab *sp)
+{
+       NODE *p;
+
+       p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+       p->n_qual = sp->squal;
+       p->n_sp = sp;
+
+#ifndef NO_C_BUILTINS
+       if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0)
+               return p;  /* do not touch builtins here */
+       
+#endif
+
+       if (sp->sflags & STNODE) {
+               /* Generated for optimizer */
+               p->n_op = TEMP;
+               p->n_rval = sp->soffset;
+       }
+
+#ifdef GCC_COMPAT
+       /* Get a label name */
+       if (sp->sflags == SLBLNAME) {
+               p->n_type = VOID;
+       }
+#endif
+       if (sp->stype == UNDEF) {
+               uerror("%s undefined", sp->sname);
+               /* make p look reasonable */
+               p->n_type = INT;
+               p->n_df = NULL;
+               defid(p, SNULL);
+       }
+       if (sp->sclass == MOE) {
+               p->n_op = ICON;
+               glval(p) = sp->soffset;
+               p->n_df = NULL;
+               p->n_sp = NULL;
+       }
+       return clocal(p);
+}
+
+/*
+ * Cast a node to another type by inserting a cast.
+ * Just a nicer interface to buildtree.
+ * Returns the new tree.
+ */
+NODE *
+cast(NODE *p, TWORD t, TWORD u)
+{
+       NODE *q;
+
+       q = block(NAME, NIL, NIL, t, 0, 0);
+       q->n_qual = u;
+       q = buildtree(CAST, q, p);
+       p = q->n_right;
+       nfree(q->n_left);
+       nfree(q);
+       return p;
+}
+
+/*
+ * Cast and complain if necessary by not inserining a cast.
+ */
+NODE *
+ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap)
+{
+       NODE *q;
+
+       /* let buildtree do typechecking (and casting) */ 
+       q = block(NAME, NIL, NIL, t, df, ap);
+       p = buildtree(ASSIGN, q, p);
+       nfree(p->n_left);
+       q = optim(p->n_right);
+       nfree(p);
+       return q;
+}
+
+/*
+ * Do an actual cast of a constant (if possible).
+ * Routine assumes 2-complement (is there anything else today?)
+ * Returns 1 if handled, 0 otherwise.
+ */
+int
+concast(NODE *p, TWORD t)
+{
+       extern short sztable[];
+       CONSZ val;
+
+       if (p->n_op != ICON && p->n_op != FCON) /* only constants */
+               return 0;
+       if (p->n_op == ICON && p->n_sp != NULL) { /* no addresses */
+               if (t == BOOL) {
+                       glval(p) = 1, p->n_type = BOOL, p->n_sp = NULL;
+                       return 1;
+               }
+               return 0;
+       }
+       if ((p->n_type & TMASK) || (t & TMASK)) /* no cast of pointers */
+               return 0;
+
+//printf("concast till %d\n", t);
+//fwalk(p, eprint, 0);
+
+#define        TYPMSK(y) ((((1LL << (y-1))-1) << 1) | 1)
+       if (p->n_op == ICON) {
+               val = glval(p);
+
+               if (t == BOOL) {
+                       if (val)
+                               glval(p) = 1;
+               } else if (t <= ULONGLONG) {
+                       glval(p) = val & TYPMSK(sztable[t]);
+                       if (!ISUNSIGNED(t)) {
+                               if (val & (1LL << (sztable[t]-1)))
+                                       glval(p) |= ~TYPMSK(sztable[t]);
+                       }
+               } else if (t <= LDOUBLE) {
+                       p->n_op = FCON;
+                       FLOAT_INT2FP(D(p->n_dcon), val, p->n_type);
+               }
+       } else { /* p->n_op == FCON */
+               if (t == BOOL) {
+                       p->n_op = ICON;
+                       glval(p) = FLOAT_NE(D(p->n_dcon),FLOAT_ZERO);
+                       p->n_sp = NULL;
+               } else if (t <= ULONGLONG) {
+                       p->n_op = ICON;
+                       glval(p) = ISUNSIGNED(t) ? /* XXX FIXME */
+                           ((U_CONSZ)D(p->n_dcon)->fp) : D(p->n_dcon)->fp;
+                       p->n_sp = NULL;
+               } else {
+                       D(p->n_dcon)->fp = t == FLOAT ? (float)D(p->n_dcon)->fp :
+                           t == DOUBLE ? (double)D(p->n_dcon)->fp : D(p->n_dcon)->fp;
+               }
+       }
+       p->n_type = t;
+//fwalk(p, eprint, 0);
+       return 1;
+}
+
+/*
+ * Do a conditional branch.
+ */
+void
+cbranch(NODE *p, NODE *q)
+{
+       p = buildtree(CBRANCH, p, q);
+       if (p->n_left->n_op == ICON) {
+               if (glval(p->n_left) != 0) {
+                       branch((int)glval(q)); /* branch always */
+                       reached = 0;
+               }
+               tfree(p);
+               tfree(q);
+               return;
+       }
+       ecomp(p);
+}
+
+NODE *
+strargs(register NODE *p)
+{
+       /* rewrite structure flavored arguments */
+
+       if( p->n_op == CM ){
+               p->n_left = strargs( p->n_left );
+               p->n_right = strargs( p->n_right );
+               return( p );
+               }
+
+       if( p->n_type == STRTY || p->n_type == UNIONTY ){
+               p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_ap);
+               p->n_left = buildtree( ADDROF, p->n_left, NIL );
+               p = clocal(p);
+               }
+       return( p );
+}
+
+/*
+ * apply the op o to the lval part of p; if binary, rhs is val
+ */
+int
+conval(NODE *p, int o, NODE *q)
+{
+       TWORD tl = p->n_type, tr = q->n_type, td;
+       int i, u;
+       CONSZ val;
+       U_CONSZ v1, v2;
+
+       val = glval(q);
+
+       /* make both sides same type */
+       if (tl < BTMASK && tr < BTMASK) {
+               td = tl > tr ? tl : tr;
+               if (td < INT)
+                       td = INT;
+               u = ISUNSIGNED(td);
+               if (tl != td)
+                       p = makety(p, td, 0, 0, 0);
+               if (tr != td)
+                       q = makety(q, td, 0, 0, 0);
+       } else
+               u = ISUNSIGNED(tl) || ISUNSIGNED(tr);
+       if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE);
+
+       if (p->n_sp != NULL && q->n_sp != NULL)
+               return(0);
+       if (q->n_sp != NULL && o != PLUS)
+               return(0);
+       if (p->n_sp != NULL && o != PLUS && o != MINUS)
+               return(0);
+
+       v1 = glval(p);
+       v2 = glval(q);
+       if (v2 == 0 && (cdope(o) & DIVFLG))
+               return 0; /* leave division by zero to runtime */
+       switch( o ){
+
+       case PLUS:
+               glval(p) += val;
+               if (p->n_sp == NULL) {
+                       p->n_right = q->n_right;
+                       p->n_type = q->n_type;
+               }
+               break;
+       case MINUS:
+               glval(p) -= val;
+               break;
+       case MUL:
+               glval(p) *= val;
+               break;
+       case DIV:
+               if (u) {
+                       v1 /= v2;
+                       glval(p) = v1;
+               } else
+                       glval(p) /= val;
+               break;
+       case MOD:
+               if (u) {
+                       v1 %= v2;
+                       glval(p) = v1;
+               } else
+                       glval(p) %= val;
+               break;
+       case AND:
+               glval(p) &= val;
+               break;
+       case OR:
+               glval(p) |= val;
+               break;
+       case ER:
+               glval(p) ^= val;
+               break;
+       case LS:
+               i = (int)val;
+               glval(p) = glval(p) << i;
+               break;
+       case RS:
+               i = (int)val;
+               if (u) {
+                       v1 = v1 >> i;
+                       glval(p) = v1;
+               } else
+                       glval(p) = glval(p) >> i;
+               break;
+
+       case UMINUS:
+               glval(p) = - glval(p);
+               break;
+       case COMPL:
+               glval(p) = ~glval(p);
+               break;
+       case NOT:
+               glval(p) = !glval(p);
+               break;
+       case LT:
+               glval(p) = glval(p) < val;
+               break;
+       case LE:
+               glval(p) = glval(p) <= val;
+               break;
+       case GT:
+               glval(p) = glval(p) > val;
+               break;
+       case GE:
+               glval(p) = glval(p) >= val;
+               break;
+       case ULT:
+               glval(p) = v1 < v2;
+               break;
+       case ULE:
+               glval(p) = v1 <= v2;
+               break;
+       case UGT:
+               glval(p) = v1 > v2;
+               break;
+       case UGE:
+               glval(p) = v1 >= v2;
+               break;
+       case EQ:
+               glval(p) = glval(p) == val;
+               break;
+       case NE:
+               glval(p) = glval(p) != val;
+               break;
+       case ANDAND:
+               glval(p) = glval(p) && val;
+               break;
+       case OROR:
+               glval(p) = glval(p) || val;
+               break;
+       default:
+               return(0);
+               }
+       /* Do the best in making everything type correct after calc */
+       if (p->n_sp == NULL && q->n_sp == NULL)
+               glval(p) = valcast(glval(p), p->n_type);
+       return(1);
+       }
+
+/*
+ * Ensure that v matches the type t; sign- or zero-extended
+ * as suitable to CONSZ.
+ * Only to be used for integer types.
+ */
+CONSZ
+valcast(CONSZ v, TWORD t)
+{
+       CONSZ r;
+       int sz;
+
+       if (t < CHAR || t > ULONGLONG)
+               return v; /* cannot cast */
+
+       if (t >= LONGLONG)
+               return v; /* already largest */
+
+#define M(x)   ((((1ULL << ((x)-1)) - 1) << 1) + 1)
+#define        NOTM(x) (~M(x))
+#define        SBIT(x) (1ULL << ((x)-1))
+
+       sz = (int)tsize(t, NULL, NULL);
+       r = v & M(sz);
+       if (!ISUNSIGNED(t) && (SBIT(sz) & r))
+               r = r | NOTM(sz);
+       return r;
+}
+
+/*
+ * Checks p for the existence of a pun.  This is called when the op of p
+ * is ASSIGN, RETURN, CAST, COLON, or relational.
+ * One case is when enumerations are used: this applies only to lint.
+ * In the other case, one operand is a pointer, the other integer type
+ * we check that this integer is in fact a constant zero...
+ * in the case of ASSIGN, any assignment of pointer to integer is illegal
+ * this falls out, because the LHS is never 0.
+ * XXX - check for COMOPs in assignment RHS?
+ */
+void
+chkpun(NODE *p)
+{
+       union dimfun *d1, *d2;
+       NODE *q;
+       int t1, t2;
+
+       t1 = p->n_left->n_type;
+       t2 = p->n_right->n_type;
+
+       switch (p->n_op) {
+       case RETURN:
+               /* return of void allowed but nothing else */
+               if (t1 == VOID && t2 == VOID)
+                       return;
+               if (t1 == VOID) {
+                       werror("returning value from void function");
+                       return;
+               }
+               if (t2 == VOID) {
+                       uerror("using void value");
+                       return;
+               }
+               break;
+       case COLON:
+               if (t1 == VOID && t2 == VOID)
+                       return;
+               break;
+       default:
+               if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) {
+                       uerror("value of void expression used");
+                       return;
+               }
+               break;
+       }
+
+       /* allow void pointer assignments in any direction */
+       if (BTYPE(t1) == VOID && (t2 & TMASK))
+               return;
+       if (BTYPE(t2) == VOID && (t1 & TMASK))
+               return;
+
+       /* boolean have special syntax */
+       if (t1 == BOOL) {
+               if (!ISARY(t2)) /* Anything scalar */
+                       return;
+       }
+
+       if (ISPTR(t1) || ISARY(t1))
+               q = p->n_right;
+       else
+               q = p->n_left;
+
+       if (!ISPTR(q->n_type) && !ISARY(q->n_type)) {
+               if (q->n_op != ICON || glval(q) != 0)
+                       werror("illegal combination of pointer and integer");
+       } else {
+               if (t1 == t2) {
+                       if (ISSOU(BTYPE(t1)) &&
+                           !suemeq(p->n_left->n_ap, p->n_right->n_ap))
+                               werror("illegal structure pointer combination");
+                       return;
+               }
+               d1 = p->n_left->n_df;
+               d2 = p->n_right->n_df;
+               for (;;) {
+                       if (ISARY(t1) || ISPTR(t1)) {
+                               if (!ISARY(t2) && !ISPTR(t2))
+                                       break;
+                               if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) {
+                                       werror("illegal array size combination");
+                                       return;
+                               }
+                               if (ISARY(t1))
+                                       ++d1;
+                               if (ISARY(t2))
+                                       ++d2;
+                       } else if (ISFTN(t1)) {
+                               if (chkftn(d1->dfun, d2->dfun)) {
+                                       werror("illegal function "
+                                           "pointer combination");
+                                       return;
+                               }
+                               ++d1;
+                               ++d2;
+                       } else
+                               break;
+                       t1 = DECREF(t1);
+                       t2 = DECREF(t2);
+               }
+               if (DEUNSIGN(t1) != DEUNSIGN(t2))
+                       warner(Wpointer_sign);
+       }
+}
+
+static NODE *
+offplus(NODE *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) {
+       if (off != 0) {
+               p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap);
+               p->n_qual = q;
+               p = optim(p);
+       }
+
+       return buildtree(UMUL, p, NIL);
+}
+
+NODE *
+stref(NODE *p)
+{
+       NODE *r;
+       struct attr *ap, *xap, *yap;
+       union dimfun *d;
+       TWORD t, q;
+       int dsc;
+       OFFSZ off;
+       struct symtab *s;
+
+       /* make p->x */
+       /* this is also used to reference automatic variables */
+
+       s = p->n_right->n_sp;
+       nfree(p->n_right);
+       r = nfree(p);
+#ifdef GCC_COMPAT
+       xap = attr_find(r->n_ap, GCC_ATYP_PACKED);
+#endif
+
+       p = pconvert(r);
+
+       /* make p look like ptr to x */
+
+       if (!ISPTR(p->n_type))
+               p->n_type = PTR+UNIONTY;
+
+       t = INCREF(s->stype);
+       q = INCQAL(s->squal);
+       d = s->sdf;
+       ap = s->sap;
+#ifdef GCC_COMPAT
+       if ((yap = attr_find(ap, GCC_ATYP_PACKED)) != NULL)
+               xap = yap;
+       else if (xap != NULL)
+               ap = attr_add(ap, attr_dup(xap));
+#else
+       xap = yap = NULL;
+#endif
+       /* xap set if packed struct */
+
+       p = makety(p, t, q, d, ap);
+       if (ISFTN(s->stype)) {
+               /* direct class call */
+               p = block(NMLIST, p, nametree(s), INT, 0, 0);
+               return p;
+       }
+
+       /* compute the offset to be added */
+
+       off = s->soffset;
+       dsc = s->sclass;
+
+       if (dsc & FIELD) {
+               TWORD ftyp = s->stype;
+               int fal = talign(ftyp, ap);
+               off = (off/fal)*fal;
+               p = offplus(p, off, t, q, d, ap);
+               p = block(FLD, p, NIL, ftyp, 0, ap);
+               p->n_qual = q;
+               p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%fal);
+       } else {
+               p = offplus(p, off, t, q, d, ap);
+#ifndef CAN_UNALIGN
+               /* if target cannot handle unaligned addresses, fix here */
+#endif
+       }
+
+       p = clocal(p);
+       return p;
+}
+
+int
+notlval(register NODE *p)
+{
+       /* return 0 if p an lvalue, 1 otherwise */
+
+       again:
+
+       switch( p->n_op ){
+
+       case FLD:
+               p = p->n_left;
+               goto again;
+
+       case NAME:
+       case OREG:
+       case UMUL:
+               if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1);
+       case TEMP:
+       case REG:
+               return(0);
+
+       default:
+               return(1);
+       }
+}
+
+/* make a constant node with value i */
+NODE *
+bcon(int i)
+{
+       return xbcon(i, NULL, INT);
+}
+
+NODE *
+xbcon(CONSZ val, struct symtab *sp, TWORD type)
+{
+       NODE *p;
+
+       p = block(ICON, NIL, NIL, type, 0, 0);
+       glval(p) = val;
+       p->n_sp = sp;
+       return clocal(p);
+}
+
+NODE *
+bpsize(NODE *p)
+{
+       int isdyn(struct symtab *sp);
+       struct symtab s;
+       NODE *q, *r;
+       TWORD t;
+       int sz;
+
+       s.stype = DECREF(p->n_type);
+       s.sdf = p->n_df;
+       if (isdyn(&s)) {
+               q = bcon(1);
+               for (t = s.stype; t > BTMASK; t = DECREF(t)) {
+                       if (ISPTR(t))
+                               return buildtree(MUL, q, bcon(SZPOINT(t)));
+                       if (ISARY(t)) {
+                               if (s.sdf->ddim < 0)
+                                       r = tempnode(-s.sdf->ddim, INT, 0, 0);
+                               else
+                                       r = bcon(s.sdf->ddim/SZCHAR);
+                               q = buildtree(MUL, q, r);
+                               s.sdf++;
+                       }
+               }
+               sz = (int)tsize(p->n_type, p->n_df, p->n_ap);
+               p = buildtree(MUL, q, bcon(sz/SZCHAR));
+       } else
+               p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap));
+       return p;
+}
+
+/*
+ * p is a node of type pointer; psize returns the
+ * size of the thing pointed to
+ */
+OFFSZ
+psize(NODE *p)
+{
+
+       if (!ISPTR(p->n_type)) {
+               uerror("pointer required");
+               return(SZINT);
+       }
+       /* note: no pointers to fields */
+       return(tsize(DECREF(p->n_type), p->n_df, p->n_ap));
+}
+
+/*
+ * convert an operand of p
+ * f is either CVTL or CVTR
+ * operand has type int, and is converted by the size of the other side
+ * convert is called when an integer is to be added to a pointer, for
+ * example in arrays or structures.
+ */
+NODE *
+convert(NODE *p, int f)
+{
+       union dimfun *df;
+       TWORD ty, ty2;
+       NODE *q, *r, *s, *rv;
+
+       if (f == CVTL) {
+               q = p->n_left;
+               s = p->n_right;
+       } else {
+               q = p->n_right;
+               s = p->n_left;
+       }
+       ty2 = ty = DECREF(s->n_type);
+       while (ISARY(ty))
+               ty = DECREF(ty);
+
+       r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap);
+       ty = ty2;
+       rv = bcon(1);
+       df = s->n_df;
+       while (ISARY(ty)) {
+               rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) :
+                   tempnode(-df->ddim, INT, 0, 0));
+               df++;
+               ty = DECREF(ty);
+       }
+       rv = clocal(MBLOCK(rv, r, INT, 0, 0));
+       rv = optim(rv);
+
+       r = MBLOCK(q, rv, INT, 0, 0);
+       r = clocal(r);
+       /*
+        * Indexing is only allowed with integer arguments, so insert
+        * SCONV here if arg is not an integer.
+        * XXX - complain?
+        */
+       if (r->n_type != INTPTR)
+               r = clocal(makety(r, INTPTR, 0, 0, 0));
+       if (f == CVTL)
+               p->n_left = r;
+       else
+               p->n_right = r;
+       return(p);
+}
+
+NODE *
+pconvert(register NODE *p)
+{
+       /* if p should be changed into a pointer, do so */
+
+       if( ISARY( p->n_type) ){
+               p->n_type = DECREF( p->n_type );
+               ++p->n_df;
+               return( buildtree( ADDROF, p, NIL ) );
+       }
+       if( ISFTN( p->n_type) )
+               return( buildtree( ADDROF, p, NIL ) );
+
+       return( p );
+}
+
+NODE *
+oconvert(register NODE *p)
+{
+       /* convert the result itself: used for pointer and unsigned */
+
+       switch(p->n_op) {
+
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+               if(ISUNSIGNED(p->n_left->n_type) ||
+                   ISUNSIGNED(p->n_right->n_type) ||
+                   ISPTR(p->n_left->n_type) ||
+                   ISPTR(p->n_right->n_type))
+                        p->n_op += (ULE-LE);
+               /* FALLTHROUGH */
+       case EQ:
+       case NE:
+               return( p );
+
+       case MINUS:
+               p->n_type = INTPTR;
+               p->n_ap = NULL;
+               return(clocal(VBLOCK(p, bpsize(p->n_left), INT, 0, 0)));
+               }
+
+       cerror( "illegal oconvert: %d", p->n_op );
+
+       return(p);
+}
+
+/*
+ * makes the operands of p agree; they are
+ * either pointers or integers, by this time
+ * with MINUS, the sizes must be the same
+ * with COLON, the types must be the same
+ */
+NODE *
+ptmatch(NODE *p)
+{
+       struct attr *ap, *ap2;
+       union dimfun *d, *d2;
+       TWORD t1, t2, t, q1, q2, q;
+       int o;
+
+       o = p->n_op;
+       t = t1 = p->n_left->n_type;
+       q = q1 = p->n_left->n_qual;
+       t2 = p->n_right->n_type;
+       q2 = p->n_right->n_qual;
+       d = p->n_left->n_df;
+       d2 = p->n_right->n_df;
+       ap = p->n_left->n_ap;
+       ap2 = p->n_right->n_ap;
+
+       switch( o ){
+
+       case ASSIGN:
+       case RETURN:
+               {  break; }
+
+       case CAST:
+               if (t == VOID) {
+                       /* just paint over */
+                       p->n_right = block(SCONV, p->n_right, NIL, VOID, 0, 0);
+                       return p;
+               }
+               break;
+
+       case MINUS: {
+               int isdyn(struct symtab *sp);
+               struct symtab s1, s2;
+
+               s1.stype = DECREF(t);
+               s1.sdf = d;
+               s2.stype = DECREF(t2);
+               s2.sdf = d2;
+               if (isdyn(&s1) || isdyn(&s2))
+                       ; /* We don't know */
+               else if (psize(p->n_left) != psize(p->n_right))
+                       uerror("illegal pointer subtraction");
+               break;
+               }
+
+       case COLON:
+               if (t1 != t2) {
+                       /*
+                        * Check for void pointer types. They are allowed
+                        * to cast to/from any pointers.
+                        */
+                       if (ISPTR(t1) && ISPTR(t2) &&
+                           (BTYPE(t1) == VOID || BTYPE(t2) == VOID))
+                               break;
+                       uerror("illegal types in :");
+               }
+               break;
+
+       default:  /* must work harder: relationals or comparisons */
+
+               if( !ISPTR(t1) ){
+                       t = t2;
+                       q = q2;
+                       d = d2;
+                       ap = ap2;
+                       break;
+                       }
+               if( !ISPTR(t2) ){
+                       break;
+                       }
+
+               /* both are pointers */
+               if( talign(t2,ap2) < talign(t,ap) ){
+                       t = t2;
+                       q = q2;
+                       ap = ap2;
+                       }
+               break;
+               }
+
+       p->n_left = makety( p->n_left, t, q, d, ap );
+       p->n_right = makety( p->n_right, t, q, d, ap );
+       if( o!=MINUS && !clogop(o) ){
+
+               p->n_type = t;
+               p->n_qual = q;
+               p->n_df = d;
+               p->n_ap = ap;
+               }
+
+       return(clocal(p));
+}
+
+/*
+ * Satisfy the types of various arithmetic binary ops.
+ *
+ * rules are:
+ *  if assignment, type of LHS
+ *  if any doubles, make double
+ *  else if any float make float
+ *  else if any longlongs, make long long
+ *  else if any longs, make long
+ *  else etcetc.
+ *
+ *  If the op with the highest rank is unsigned, this is the resulting type.
+ *  See:  6.3.1.1 rank order equal of signed and unsigned types
+ *        6.3.1.8 Usual arithmetic conversions
+ */
+static NODE *
+tymatch(NODE *p)
+{
+       TWORD tl, tr, t;
+       NODE *l, *r;
+       int o;
+
+       o = p->n_op;
+       r = p->n_right;
+       l = p->n_left;
+
+       tl = l->n_type;
+       tr = r->n_type;
+
+       if (tl == BOOL) tl = BOOL_TYPE;
+       if (tr == BOOL) tr = BOOL_TYPE;
+
+       if (casgop(o)) {
+               if (r->n_op != ICON && tl < FLOAT && tr < FLOAT &&
+                   DEUNSIGN(tl) < DEUNSIGN(tr) && o != CAST)
+                       warner(Wtruncate, tnames[tr], tnames[tl]);
+               p->n_right = makety(p->n_right, l->n_type, 0, 0, 0);
+               t = p->n_type = l->n_type;
+               p->n_ap = l->n_ap;
+       } else {
+               t = tl > tr ? tl : tr; /* MAX */
+               /* This depends on ctype() called early */
+               if (o != COLON && t < INT)
+                       t = INT;
+               if (tl != t) p->n_left = makety(p->n_left, t, 0, 0, 0);
+               if (tr != t) p->n_right = makety(p->n_right, t, 0, 0, 0);
+               if (o == COLON && l->n_type == BOOL && r->n_type == BOOL)
+                       t = p->n_type = BOOL;
+               else if (!clogop(o))
+                       p->n_type = t;
+       }
+#ifdef PCC_DEBUG
+       if (tdebug) {
+               printf("tymatch(%p): ", p);
+               tprint(tl, 0);
+               printf(" %s ", copst(o));
+               tprint(tr, 0);
+               printf(" => ");
+               tprint(t, 0);
+               printf("\n");
+               fwalk(p, eprint, 0);
+       }
+#endif
+       return p;
+}
+
+/*
+ * make p into type t by inserting a conversion
+ */
+NODE *
+makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap)
+{
+
+       if (t == p->n_type) {
+               p->n_df = d;
+               p->n_ap = ap;
+               p->n_qual = q;
+               return(p);
+       }
+
+       if (ISITY(t) || ISCTY(t) || ISITY(p->n_type) || ISCTY(p->n_type))
+               cerror("makety");
+
+       if (concast(p, t))
+               return clocal(p);
+
+       p = block(t & TMASK ? PCONV : SCONV, p, NIL, t, d, ap);
+       p->n_qual = q;
+       return clocal(p);
+}
+
+NODE *
+block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct attr *ap)
+{
+       register NODE *p;
+
+       p = talloc();
+       p->n_rval = 0;
+       p->n_op = o;
+       glval(p) = 0; /* Protect against large lval */
+       p->n_left = l;
+       p->n_right = r;
+       p->n_type = t;
+       p->n_qual = 0;
+       p->n_df = d;
+       p->n_ap = ap;
+#if !defined(MULTIPASS)
+       /* p->n_reg = */p->n_su = 0;
+       p->n_regw = 0;
+#endif
+       return(p);
+}
+
+/*
+ * Return the constant value from an ICON.
+ */
+CONSZ
+icons(NODE *p)
+{
+       /* if p is an integer constant, return its value */
+       CONSZ val;
+
+       if (p->n_op != ICON || p->n_sp != NULL) {
+               uerror( "constant expected");
+               val = 1;
+       } else
+               val = glval(p);
+       tfree(p);
+       return(val);
+}
+
+/* 
+ * the intent of this table is to examine the
+ * operators, and to check them for
+ * correctness.
+ * 
+ * The table is searched for the op and the
+ * modified type (where this is one of the
+ * types INT (includes char and short), LONG,
+ * DOUBLE (includes FLOAT), and POINTER
+ * 
+ * The default action is to make the node type integer
+ * 
+ * The actions taken include:
+ *     PUN       check for puns
+ *     CVTL      convert the left operand
+ *     CVTR      convert the right operand
+ *     TYPL      the type is determined by the left operand
+ *     TYPR      the type is determined by the right operand
+ *     TYMATCH   force type of left and right to match,by inserting conversions
+ *     PTMATCH   like TYMATCH, but for pointers
+ *     LVAL      left operand must be lval
+ *     CVTO      convert the op
+ *     NCVT      do not convert the operands
+ *     OTHER     handled by code
+ *     NCVTR     convert the left operand, not the right...
+ * 
+ */
+
+# define MINT 01       /* integer */
+# define MDBI 02       /* integer or double */
+# define MSTR 04       /* structure */
+# define MPTR 010      /* pointer */
+# define MPTI 020      /* pointer or integer */
+
+int
+opact(NODE *p)
+{
+       int mt12, mt1, mt2, o;
+
+       mt1 = mt2 = mt12 = 0;
+
+       switch (coptype(o = p->n_op)) {
+       case BITYPE:
+               mt12=mt2 = moditype(p->n_right->n_type);
+               /* FALLTHROUGH */
+       case UTYPE:
+               mt12 &= (mt1 = moditype(p->n_left->n_type));
+               break;
+       }
+
+       switch( o ){
+
+       case NAME :
+       case ICON :
+       case FCON :
+       case CALL :
+       case UCALL:
+       case UMUL:
+               {  return( OTHER ); }
+       case UMINUS:
+               if( mt1 & MDBI ) return( TYPL+PROML );
+               break;
+
+       case COMPL:
+               if( mt1 & MINT ) return( TYPL+PROML );
+               break;
+
+       case ADDROF:
+               return( NCVT+OTHER );
+       case NOT:
+               return( PROML );
+
+/*     case INIT: */
+       case CM:
+       case CBRANCH:
+       case ANDAND:
+       case OROR:
+               return( 0 );
+
+       case MUL:
+       case DIV:
+               if( mt12 & MDBI ) return( TYMATCH );
+               break;
+
+       case MOD:
+       case AND:
+       case OR:
+       case ER:
+               if( mt12 & MINT ) return( TYMATCH );
+               break;
+
+       case LS:
+       case RS:
+               if( mt12 & MINT ) return( TYPL+OTHER );
+               break;
+
+       case EQ:
+       case NE:
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+               if( mt12 & MDBI ) return( TYMATCH+CVTO );
+               else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO );
+               else if( mt12 & MPTI ) return( PTMATCH+PUN );
+               else break;
+
+       case QUEST:
+               return( TYPR+OTHER );
+       case COMOP:
+               return( TYPR );
+
+       case STREF:
+               return( NCVTR+OTHER );
+
+       case FORCE:
+               return( TYPL );
+
+       case COLON:
+               if( mt12 & MDBI ) return( TYMATCH );
+               else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN );
+               else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN );
+               else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN );
+               else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER );
+               break;
+
+       case ASSIGN:
+       case RETURN:
+               if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER );
+       case CAST:
+               if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH );
+               else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN );
+               else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN );
+               break;
+
+       case LSEQ:
+       case RSEQ:
+               if( mt12 & MINT ) return( TYPL+LVAL+OTHER );
+               break;
+
+       case MULEQ:
+       case DIVEQ:
+               if( mt12 & MDBI ) return( LVAL+TYMATCH );
+               break;
+
+       case MODEQ:
+       case ANDEQ:
+       case OREQ:
+       case EREQ:
+               if (mt12 & MINT)
+                       return(LVAL+TYMATCH);
+               break;
+
+       case PLUSEQ:
+       case MINUSEQ:
+       case INCR:
+       case DECR:
+               if (mt12 & MDBI)
+                       return(TYMATCH+LVAL);
+               else if ((mt1&MPTR) && (mt2&MINT))
+                       return(TYPL+LVAL+CVTR);
+               break;
+
+       case MINUS:
+               if (mt12 & MPTR)
+                       return(CVTO+PTMATCH+PUN);
+               if (mt2 & MPTR)
+                       break;
+               /* FALLTHROUGH */
+       case PLUS:
+               if (mt12 & MDBI)
+                       return(TYMATCH);
+               else if ((mt1&MPTR) && (mt2&MINT))
+                       return(TYPL+CVTR);
+               else if ((mt1&MINT) && (mt2&MPTR))
+                       return(TYPR+CVTL);
+
+       }
+       uerror("operands of %s have incompatible types", copst(o));
+       return(NCVT);
+}
+
+int
+moditype(TWORD ty)
+{
+       switch (ty) {
+
+       case STRTY:
+       case UNIONTY:
+               return( MSTR );
+
+       case BOOL:
+       case CHAR:
+       case SHORT:
+       case UCHAR:
+       case USHORT:
+       case UNSIGNED:
+       case ULONG:
+       case ULONGLONG:
+       case INT:
+       case LONG:
+       case LONGLONG:
+               return( MINT|MDBI|MPTI );
+       case FLOAT:
+       case DOUBLE:
+       case LDOUBLE:
+#ifndef NO_COMPLEX
+       case FCOMPLEX:
+       case COMPLEX:
+       case LCOMPLEX:
+       case FIMAG:
+       case IMAG:
+       case LIMAG:
+#endif
+               return( MDBI );
+       default:
+               return( MPTR|MPTI );
+
+       }
+}
+
+int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100;
+
+/*
+ * Returns a TEMP node with temp number nr.
+ * If nr == 0, return a node with a new number.
+ */
+NODE *
+tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap)
+{
+       NODE *r;
+
+       if (tvaloff == -NOOFFSET)
+               tvaloff++; /* Skip this for array indexing */
+       r = block(TEMP, NIL, NIL, type, df, ap);
+       regno(r) = nr ? nr : tvaloff;
+       tvaloff += szty(type);
+       return r;
+}
+
+/*
+ * Do sizeof on p.
+ */
+NODE *
+doszof(NODE *p)
+{
+       extern NODE *arrstk[10];
+       extern int arrstkp;
+       union dimfun *df;
+       TWORD ty;
+       NODE *rv, *q;
+       int astkp;
+
+       if (p->n_op == FLD)
+               uerror("can't apply sizeof to bit-field");
+
+       /*
+        * Arrays may be dynamic, may need to make computations.
+        */
+
+       rv = bcon(1);
+       df = p->n_df;
+       ty = p->n_type;
+       astkp = 0;
+       while (ISARY(ty)) {
+               if (df->ddim == NOOFFSET)
+                       uerror("sizeof of incomplete type");
+               if (df->ddim < 0) {
+                       if (arrstkp)
+                               q = arrstk[astkp++];
+                       else
+                               q = tempnode(-df->ddim, INT, 0, 0);
+               } else
+                       q = bcon(df->ddim);
+               rv = buildtree(MUL, rv, q);
+               df++;
+               ty = DECREF(ty);
+       }
+       rv = buildtree(MUL, rv, 
+           xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR));
+       tfree(p);
+       arrstkp = 0; /* XXX - may this fail? */
+       return rv;
+}
+
+#ifdef PCC_DEBUG
+void
+eprint(NODE *p, int down, int *a, int *b)
+{
+       int ty;
+
+       *a = *b = down+1;
+       while( down > 1 ){
+               printf( "\t" );
+               down -= 2;
+               }
+       if( down ) printf( "    " );
+
+       ty = coptype( p->n_op );
+
+       printf("%p) %s, ", p, copst(p->n_op));
+       if (p->n_op == XARG || p->n_op == XASM)
+               printf("id '%s', ", p->n_name);
+       if (ty == LTYPE) {
+               printf(CONFMT, glval(p));
+               if (p->n_op == NAME || p->n_op == ICON)
+                       printf(", %p, ", p->n_sp);
+               else
+                       printf(", %d, ", p->n_rval);
+       }
+       tprint(p->n_type, p->n_qual);
+       printf( ", %p, ", p->n_df);
+#ifdef GCC_COMPAT
+       dump_attr(p->n_ap);
+#endif
+}
+# endif
+
+/*
+ * Emit everything that should be emitted on the left side 
+ * of a comma operator, and remove the operator.
+ * Do not traverse through QUEST, ANDAND and OROR.
+ * Enable this for all targets when stable enough.
+ */
+static void
+comops(NODE *p)
+{
+       int o;
+       NODE *q;
+
+       while (p->n_op == COMOP) {
+               /* XXX hack for GCC ({ }) ops */
+               if (p->n_left->n_op == GOTO) {
+                       int v = (int)glval(p->n_left->n_left);
+                       ecomp(p->n_left);
+                       plabel(v+1);
+               } else
+                       ecomp(p->n_left); /* will recurse if more COMOPs */
+               q = p->n_right;
+               *p = *q;
+               nfree(q);
+       }
+       o = coptype(p->n_op);
+       if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR)
+               o = UTYPE;
+       if (o != LTYPE)
+               comops(p->n_left);
+       if (o == BITYPE)
+               comops(p->n_right);
+}
+
+/*
+ * Walk up through the tree from the leaves,
+ * removing constant operators.
+ */
+static void
+logwalk(NODE *p)
+{
+       int o = coptype(p->n_op);
+       NODE *l, *r;
+
+       l = p->n_left;
+       r = p->n_right;
+       switch (o) {
+       case LTYPE:
+               return;
+       case BITYPE:
+               logwalk(r);
+               /* FALLTHROUGH */
+       case UTYPE:
+               logwalk(l);
+       }
+       if (!clogop(p->n_op))
+               return;
+       if (p->n_op == NOT && l->n_op == ICON) {
+               glval(p) = glval(l) == 0;
+               nfree(l);
+               p->n_op = ICON;
+       }
+       if (l->n_op == ICON && r->n_op == ICON) {
+               if (conval(l, p->n_op, r) == 0) {
+                       /*
+                        * people sometimes tend to do really odd compares,
+                        * like "if ("abc" == "def")" etc.
+                        * do it runtime instead.
+                        */
+               } else {
+                       glval(p) = glval(l);
+                       p->n_op = ICON;
+                       nfree(l);
+                       nfree(r);
+               }
+       }
+}
+
+/*
+ * Removes redundant logical operators for branch conditions.
+ */
+static void
+fixbranch(NODE *p, int label)
+{
+
+       logwalk(p);
+
+       if (p->n_op == ICON) {
+               if (glval(p) != 0)
+                       branch(label);
+               nfree(p);
+       } else {
+               if (!clogop(p->n_op)) /* Always conditional */
+                       p = buildtree(NE, p, bcon(0));
+               ecode(buildtree(CBRANCH, p, bcon(label)));
+       }
+}
+
+/*
+ * Write out logical expressions as branches.
+ */
+static void
+andorbr(NODE *p, int true, int false)
+{
+       NODE *q;
+       int o, lab;
+
+       lab = -1;
+       switch (o = p->n_op) { 
+       case EQ:
+       case NE:
+               /*
+                * Remove redundant EQ/NE nodes.
+                */
+               while (((o = p->n_left->n_op) == EQ || o == NE) && 
+                   p->n_right->n_op == ICON) {
+                       o = p->n_op;
+                       q = p->n_left;
+                       if (glval(p->n_right) == 0) {
+                               nfree(p->n_right);
+                               *p = *q;
+                               nfree(q);
+                               if (o == EQ)
+                                       p->n_op = negrel[p->n_op - EQ];
+#if 0
+                                       p->n_op = NE; /* toggla */
+#endif
+                       } else if (glval(p->n_right) == 1) {
+                               nfree(p->n_right);
+                               *p = *q;
+                               nfree(q);
+                               if (o == NE)
+                                       p->n_op = negrel[p->n_op - EQ];
+#if 0
+                                       p->n_op = EQ; /* toggla */
+#endif
+                       } else
+                               break; /* XXX - should always be false */
+                       
+               }
+               /* FALLTHROUGH */
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+calc:          if (true < 0) {
+                       p->n_op = negrel[p->n_op - EQ];
+                       true = false;
+                       false = -1;
+               }
+
+               rmcops(p->n_left);
+               rmcops(p->n_right);
+               fixbranch(p, true);
+               if (false >= 0)
+                       branch(false);
+               break;
+
+       case ULE:
+       case UGT:
+               /* Convert to friendlier ops */
+               if (nncon(p->n_right) && glval(p->n_right) == 0)
+                       p->n_op = o == ULE ? EQ : NE;
+               goto calc;
+
+       case UGE:
+       case ULT:
+               /* Already true/false by definition */
+               if (nncon(p->n_right) && glval(p->n_right) == 0) {
+                       if (true < 0) {
+                               o = o == ULT ? UGE : ULT;
+                               true = false;
+                       }
+                       rmcops(p->n_left);
+                       ecode(p->n_left);
+                       rmcops(p->n_right);
+                       ecode(p->n_right);
+                       nfree(p);
+                       if (o == UGE) /* true */
+                               branch(true);
+                       break;
+               }
+               goto calc;
+
+       case ANDAND:
+               lab = false<0 ? getlab() : false ;
+               andorbr(p->n_left, -1, lab);
+               comops(p->n_right);
+               andorbr(p->n_right, true, false);
+               if (false < 0)
+                       plabel( lab);
+               nfree(p);
+               break;
+
+       case OROR:
+               lab = true<0 ? getlab() : true;
+               andorbr(p->n_left, lab, -1);
+               comops(p->n_right);
+               andorbr(p->n_right, true, false);
+               if (true < 0)
+                       plabel( lab);
+               nfree(p);
+               break;
+
+       case NOT:
+               andorbr(p->n_left, false, true);
+               nfree(p);
+               break;
+
+       default:
+               rmcops(p);
+               if (true >= 0)
+                       fixbranch(p, true);
+               if (false >= 0) {
+                       if (true >= 0)
+                               branch(false);
+                       else
+                               fixbranch(buildtree(EQ, p, bcon(0)), false);
+               }
+       }
+}
+
+/*
+ * Create a node for either TEMP or on-stack storage.
+ */
+NODE *
+cstknode(TWORD t, union dimfun *df, struct attr *ap)
+{
+       struct symtab *sp;
+
+       /* create a symtab entry suitable for this type */
+       sp = getsymtab("0hej", STEMP);
+       sp->stype = t;
+       sp->sdf = df;
+       sp->sap = ap;
+       sp->sclass = AUTO;
+       sp->soffset = NOOFFSET;
+       oalloc(sp, &autooff);
+       return nametree(sp);
+
+}
+
+/*
+ * Massage the output trees to remove C-specific nodes:
+ *     COMOPs are split into separate statements.
+ *     QUEST/COLON are rewritten to branches.
+ *     ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation.
+ *     CBRANCH conditions are rewritten for lazy-evaluation.
+ */
+static void
+rmcops(NODE *p)
+{
+       TWORD type;
+       NODE *q, *r, *tval;
+       int o, ty, lbl, lbl2;
+
+       tval = NIL;
+       o = p->n_op;
+       ty = coptype(o);
+       if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */
+               struct symtab *sp = strmemb(p->n_ap);
+               MODTYPE(p->n_type, sp->stype);
+               /*
+                * XXX may fail if these are true:
+                * - variable-sized enums
+                * - non-byte-addressed targets.
+                */
+               if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type))
+                       MODTYPE(p->n_type, INT); /* INT ok? */
+       }
+       switch (o) {
+       case QUEST:
+
+               /*
+                * Create a branch node from ?:
+                * || and && must be taken special care of.
+                */
+               type = p->n_type;
+               andorbr(p->n_left, -1, lbl = getlab());
+
+               /* Make ASSIGN node */
+               /* Only if type is not void */
+               q = p->n_right->n_left;
+               comops(q);
+               if (type != VOID) {
+                       tval = cstknode(q->n_type, q->n_df, q->n_ap);
+                       q = buildtree(ASSIGN, ccopy(tval), q);
+               }
+               rmcops(q);
+               ecode(q); /* Done with assign */
+               branch(lbl2 = getlab());
+               plabel( lbl);
+
+               q = p->n_right->n_right;
+               comops(q);
+               if (type != VOID) {
+                       q = buildtree(ASSIGN, ccopy(tval), q);
+               }
+               rmcops(q);
+               ecode(q); /* Done with assign */
+
+               plabel( lbl2);
+
+               nfree(p->n_right);
+               if (p->n_type != VOID) {
+                       *p = *tval;
+                       nfree(tval);
+               } else {
+                       p->n_op = ICON;
+                       glval(p) = 0;
+                       p->n_sp = NULL;
+               }
+               break;
+
+       case ULE:
+       case ULT:
+       case UGE:
+       case UGT:
+       case EQ:
+       case NE:
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+       case ANDAND:
+       case OROR:
+       case NOT:
+#ifdef SPECIAL_CCODES
+#error fix for private CCODES handling
+#else
+               r = talloc();
+               *r = *p;
+               andorbr(r, -1, lbl = getlab());
+
+               tval = cstknode(p->n_type, p->n_df, p->n_ap);
+
+               ecode(buildtree(ASSIGN, ccopy(tval), bcon(1)));
+               branch(lbl2 = getlab());
+               plabel( lbl);
+               ecode(buildtree(ASSIGN, ccopy(tval), bcon(0)));
+               plabel( lbl2);
+
+               *p = *tval;
+               nfree(tval);
+
+#endif
+               break;
+       case CBRANCH:
+               andorbr(p->n_left, glval(p->n_right), -1);
+               nfree(p->n_right);
+               p->n_op = ICON; p->n_type = VOID;
+               break;
+       case COMOP:
+               cerror("COMOP error");
+
+       default:
+               if (ty == LTYPE)
+                       return;
+               rmcops(p->n_left);
+               if (ty == BITYPE)
+                       rmcops(p->n_right);
+       }
+}
+
+/*
+ * Return 1 if an assignment is found.
+ */
+static int
+has_se(NODE *p)
+{
+       if (cdope(p->n_op) & ASGFLG)
+               return 1;
+       if (coptype(p->n_op) == LTYPE)
+               return 0;
+       if (has_se(p->n_left))
+               return 1;
+       if (coptype(p->n_op) == BITYPE)
+               return has_se(p->n_right);
+       return 0;
+}
+
+/*
+ * Find and convert asgop's to separate statements.
+ * Be careful about side effects.
+ * assign tells whether ASSIGN should be considered giving
+ * side effects or not.
+ */
+static NODE *
+delasgop(NODE *p)
+{
+       NODE *q, *r;
+       int tval;
+
+       if (p->n_op == INCR || p->n_op == DECR) {
+               /*
+                * Rewrite x++ to (x += 1) -1; and deal with it further down.
+                * Pass2 will remove -1 if unnecessary.
+                */
+               q = ccopy(p);
+               tfree(p->n_left);
+               q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ;
+               p->n_op = (p->n_op==INCR)?MINUS:PLUS;
+               p->n_left = delasgop(q);
+
+       } else if ((cdope(p->n_op)&ASGOPFLG) &&
+           p->n_op != RETURN && p->n_op != CAST) {
+               NODE *l = p->n_left;
+               NODE *ll = l->n_left;
+
+               if (has_se(l)) {
+                       q = tempnode(0, ll->n_type, ll->n_df, ll->n_ap);
+                       tval = regno(q);
+                       r = tempnode(tval, ll->n_type, ll->n_df,ll->n_ap);
+                       l->n_left = q;
+                       /* Now the left side of node p has no side effects. */
+                       /* side effects on the right side must be obeyed */
+                       p = delasgop(p);
+                       
+                       r = buildtree(ASSIGN, r, ll);
+                       r = delasgop(r);
+                       ecode(r);
+               } else {
+#if 0 /* Cannot call buildtree() here, it would invoke double add shifts */
+                       p->n_right = buildtree(UNASG p->n_op, ccopy(l),
+                           p->n_right);
+#else
+                       p->n_right = block(UNASG p->n_op, ccopy(l),
+                           p->n_right, p->n_type, p->n_df, p->n_ap);
+#endif
+                       p->n_op = ASSIGN;
+                       p->n_right = delasgop(p->n_right);
+                       p->n_right = clocal(p->n_right);
+               }
+               
+       } else {
+               if (coptype(p->n_op) == LTYPE)
+                       return p;
+               p->n_left = delasgop(p->n_left);
+               if (coptype(p->n_op) == BITYPE)
+                       p->n_right = delasgop(p->n_right);
+       }
+       return p;
+}
+
+#ifndef FIELDOPS
+
+/* avoid promotion to int */
+#define        TYPMOD(o, p, n, t)      clocal(block(o, p, n, t, 0, 0))
+#define        TYPLS(p, n, t)  TYPMOD(LS, p, n, t)
+#define        TYPRS(p, n, t)  TYPMOD(RS, p, n, t)
+#define        TYPOR(p, q, t)  TYPMOD(OR, p, q, t)
+#define        TYPAND(p, q, t) TYPMOD(AND, p, q, t)
+
+/*
+ * Read an unaligned bitfield from position pointed to by p starting at
+ * off and size fsz and return a tree of type t with resulting data.
+ */
+static NODE *
+rdualfld(NODE *p, TWORD t, TWORD ct, int off, int fsz)
+{
+       int t2f, inbits, tsz, ctsz;
+       NODE *q, *r;
+
+       ct = ENUNSIGN(ct);
+       ctsz = (int)tsize(ct, 0, 0);
+
+       /* traverse until first data byte */
+       for (t2f = 0; off > ctsz; t2f++, off -= ctsz)
+               ;
+#ifdef UNALIGNED_ACCESS
+       /* try to squeeze it into an int */
+       if (off + fsz > ctsz && off + fsz <= SZINT) {
+               ct = UNSIGNED;
+               ctsz = SZINT;
+       }
+#endif
+       p = makety(p, PTR|ct, 0, 0, 0);
+       if (off + fsz <= ctsz) {
+               /* only one operation needed */
+               q = buildtree(UMUL, buildtree(PLUS, p, bcon(t2f)), 0);
+               if (!ISUNSIGNED(t)) {
+                       ct = DEUNSIGN(ct);
+                       q = makety(q, ct, 0, 0, 0);
+               }
+               q = TYPLS(q, bcon(ctsz-fsz-off), ct);
+               q = TYPRS(q, bcon(ctsz-fsz), ct);
+               q = makety(q, t, 0, 0, 0);
+       } else {
+               q = buildtree(UMUL, buildtree(PLUS, ccopy(p), bcon(t2f)), 0);
+               q = makety(TYPRS(q, bcon(off), ct), t, 0, 0, 0);
+               inbits = ctsz - off;
+               t2f++;
+
+               while (fsz > inbits) {
+                       r = buildtree(UMUL,
+                           buildtree(PLUS, ccopy(p), bcon(t2f)), 0);
+                       r = makety(r, t, 0, 0, 0);
+                       r = TYPLS(r, bcon(inbits), t);
+                       q = TYPOR(q, r, t);
+                       inbits += ctsz;
+                       t2f++;
+               }
+               /* sign/zero extend XXX - RS must sign extend */
+               tsz = (int)tsize(t, 0, 0);
+               if (!ISUNSIGNED(t)) {
+                       t = DEUNSIGN(t);
+                       q = makety(q, t, 0, 0, 0);
+               }
+               q = TYPLS(q, bcon(tsz-fsz), t);
+               q = TYPRS(q, bcon(tsz-fsz), t);
+               tfree(p);
+       }
+
+       return q;
+}
+
+/*
+ * Write val to a (unaligned) bitfield with length fsz positioned off bits  
+ * from d. Bitfield type is t, and type to use when writing is ct.
+ * neither f nor d should have any side effects if copied.
+ * Multiples of ct are supposed to be written without problems.
+ * Both val and d are free'd after use.
+ */
+static NODE *
+wrualfld(NODE *val, NODE *d, TWORD t, TWORD ct, int off, int fsz)
+{ 
+       NODE *p, *q, *r, *rn, *s;
+       int ctsz, t2f, inbits;
+       ctsz = (int)tsize(ct, 0, 0);
+  
+       ct = ENUNSIGN(ct);
+       d = makety(d, PTR|ct, 0, 0, 0);
+
+       for (t2f = 0; off > ctsz; t2f++, off -= ctsz)
+               ;
+       if (off + fsz <= ctsz) {
+               r = tempnode(0, ct, 0, 0);
+
+               /* only one operation needed */
+               d = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0);  
+               p = ccopy(d); 
+               p = TYPAND(p, xbcon(~(SZMASK(fsz) << off), 0, ct), ct);
+
+               val = makety(val, ct, 0, 0, 0);
+               q = TYPAND(val, xbcon(SZMASK(fsz), 0, ct), ct);
+               q = buildtree(ASSIGN, ccopy(r), q);
+
+               q = TYPLS(q, bcon(off), ct);   
+               p = TYPOR(p, q, ct);
+               p = makety(p, t, 0, 0, 0);     
+               rn = buildtree(ASSIGN, d, p);
+               rn = buildtree(COMOP, rn, makety(r, t, 0, 0, 0));
+       } else {
+               s = makety(ccopy(val), t, 0, 0, 0);
+               s = TYPAND(s, xbcon(SZMASK(fsz), 0, t), t);
+
+               r = buildtree(UMUL, buildtree(PLUS, ccopy(d), bcon(t2f)), 0);
+               p = ccopy(r);
+               p = TYPAND(p, xbcon(SZMASK(off), 0, ct), ct);
+               q = ccopy(val); 
+               q = TYPLS(q, bcon(off), t);  
+               q = makety(q, ct, 0, 0, 0);
+               p = TYPOR(p, q, ct);
+               rn = buildtree(ASSIGN, r, p);
+               inbits = ctsz - off;
+               t2f++;
+
+               while (fsz > inbits+ctsz) {
+                       r = buildtree(UMUL,
+                           buildtree(PLUS, ccopy(d), bcon(t2f)), 0);
+                       q = ccopy(val);
+                       q = TYPRS(q, bcon(inbits), t);
+                       q = makety(q, ct, 0, 0, 0);
+                       rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, q));
+                       t2f++;
+                       inbits += ctsz;
+               }
+
+               r = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0);
+               p = ccopy(r);
+               p = TYPAND(p, makety(xbcon(~SZMASK(fsz-inbits), 0, ct),
+                   ct, 0, 0, 0), ct);
+               q = TYPRS(val, bcon(inbits), t);
+               q = TYPAND(q, xbcon(SZMASK(fsz-inbits), 0, t), t);
+               q = makety(q, ct, 0, 0, 0);
+               p = TYPOR(p, q, ct);
+               rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, p));
+               rn = buildtree(COMOP, rn, s);
+       }
+       return rn;
+}
+
+/*
+ * Rewrite bitfield operations to shifts.
+ */
+static NODE *
+rmfldops(NODE *p)
+{
+       TWORD t, ct;
+       NODE *q, *r, *t1, *t2, *bt, *t3, *t4;
+       int fsz, foff;
+
+       if (p->n_op == FLD) {
+               /* Rewrite a field read operation */
+               fsz = UPKFSZ(p->n_rval);
+               foff = UPKFOFF(p->n_rval);
+               q = buildtree(ADDROF, p->n_left, NIL);
+
+               ct = t = p->n_type;
+#ifdef GCC_COMPAT
+               if (attr_find(p->n_ap, GCC_ATYP_PACKED) &&
+                   coptype(q->n_op) != LTYPE) {
+                       t1 = tempnode(0, q->n_type, 0, 0);
+                       bt = buildtree(ASSIGN, ccopy(t1), q);
+                       q = t1;
+#ifndef UNALIGNED_ACCESS
+                       ct = UCHAR;
+#endif
+               } else
+#endif
+                       bt = bcon(0);
+               q = rdualfld(q, t, ct, foff, fsz);
+               p->n_left = bt;
+               p->n_right = q;
+               p->n_op = COMOP;
+       } else if (((cdope(p->n_op)&ASGOPFLG) || p->n_op == ASSIGN ||
+           p->n_op == INCR || p->n_op == DECR) && p->n_left->n_op == FLD) {
+               /*
+                * Rewrite a field write operation
+                * More difficult than a read op since we must care
+                * about side effects.
+                */
+               q = p->n_left;
+               fsz = UPKFSZ(q->n_rval);
+               foff = UPKFOFF(q->n_rval);
+               t = q->n_left->n_type;
+#if TARGET_ENDIAN == TARGET_BE
+               foff = (int)tsize(t, 0, 0) - fsz - foff;
+#endif
+               bt = NULL;
+               if (p->n_right->n_op != ICON && p->n_right->n_op != NAME) {
+                       t2 = tempnode(0, p->n_right->n_type, 0, 0);
+                       bt = buildtree(ASSIGN, ccopy(t2), p->n_right);
+               } else
+                       t2 = p->n_right;
+
+               ct = t;
+#ifdef GCC_COMPAT
+#ifndef UNALIGNED_ACCESS
+               if (attr_find(q->n_ap, GCC_ATYP_PACKED))
+                       ct = UCHAR;
+#endif
+#endif
+               /* t2 is what we have to write (RHS of ASSIGN) */
+               /* bt is (eventually) something that must be written */
+
+
+               if (q->n_left->n_op == UMUL) {
+                       /* LHS of assignment may have side effects */
+                       q = q->n_left;
+                       t1 = tempnode(0, q->n_left->n_type, 0, 0);
+                       r = buildtree(ASSIGN, ccopy(t1), q->n_left);
+                       
+                       bt = bt ? block(COMOP, bt, r, INT, 0, 0) : r;
+                       q->n_left = t1;
+               }
+               t1 = buildtree(ADDROF, p->n_left->n_left, 0);
+
+               /* t1 is lval where to write (and read) */
+
+               if (p->n_op == ASSIGN) {
+                       q = wrualfld(t2, t1, t, ct, foff, fsz);
+                       if (bt)
+                               q = block(COMOP, bt, q, t, 0, 0);
+                       nfree(p->n_left);
+                       p->n_left = bcon(0);
+                       p->n_right = q;
+                       p->n_op = COMOP;
+               } else if ((cdope(p->n_op)&ASGOPFLG)) {
+                       /* And here is the asgop-specific code */
+                       t3 = tempnode(0, t, 0, 0);
+                       q = rdualfld(ccopy(t1), t, ct, foff, fsz);
+                       q = buildtree(UNASG p->n_op, q, t2);
+                       q = buildtree(ASSIGN, ccopy(t3), q);
+                       r = wrualfld(ccopy(t3), t1, t, ct, foff, fsz);
+                       q = buildtree(COMOP, q, r);
+                       q = buildtree(COMOP, q, t3);
+
+                       nfree(p->n_left);
+                       p->n_left = bt ? bt : bcon(0);
+                       p->n_right = q;
+                       p->n_op = COMOP;
+               } else {
+                       t3 = tempnode(0, t, 0, 0);
+                       t4 = tempnode(0, t, 0, 0);
+
+                       q = rdualfld(ccopy(t1), t, ct, foff, fsz);
+                       q = buildtree(ASSIGN, ccopy(t3), q);
+                       r = buildtree(p->n_op==INCR?PLUS:MINUS, ccopy(t3), t2);
+                       r = buildtree(ASSIGN, ccopy(t4), r);
+                       q = buildtree(COMOP, q, r);
+                       r = wrualfld(t4, t1, t, ct, foff, fsz);
+                       q = buildtree(COMOP, q, r);
+               
+                       if (bt)
+                               q = block(COMOP, bt, q, t, 0, 0);
+                       nfree(p->n_left);
+                       p->n_left = q;
+                       p->n_right = t3;
+                       p->n_op = COMOP;
+               }
+       }
+       if (coptype(p->n_op) != LTYPE)
+               p->n_left = rmfldops(p->n_left);
+       if (coptype(p->n_op) == BITYPE)
+               p->n_right = rmfldops(p->n_right);
+       return p;
+}
+#endif
+
+void
+ecomp(NODE *p)
+{
+
+#ifdef PCC_DEBUG
+       if (edebug)
+               fwalk(p, eprint, 0);
+#endif
+       if (!reached) {
+               warner(Wunreachable_code);
+               reached = 1;
+       }
+       p = optim(p);
+#ifndef FIELDOPS
+       p = rmfldops(p);
+#endif
+       comops(p);
+       rmcops(p);
+       p = delasgop(p);
+       if (p->n_op == ICON && p->n_type == VOID)
+               tfree(p);
+       else
+               ecode(p);
+}
+
+
+#if defined(MULTIPASS)
+void   
+p2tree(NODE *p)
+{
+       struct symtab *q;
+       int ty;
+
+       myp2tree(p);  /* local action can be taken here */
+
+       ty = coptype(p->n_op);
+
+       printf("%d\t", p->n_op);
+
+       if (ty == LTYPE) {
+               printf(CONFMT, glval(p));
+               printf("\t");
+       }
+       if (ty != BITYPE) {
+               if (p->n_op == NAME || p->n_op == ICON)
+                       printf("0\t");
+               else
+                       printf("%d\t", p->n_rval);
+               }
+
+       printf("%o\t", p->n_type);
+
+       /* handle special cases */
+
+       switch (p->n_op) {
+
+       case NAME:
+       case ICON:
+               /* print external name */
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)) {
+                               printf(LABFMT, q->soffset);
+                       } else
+                               printf("%s\n",
+                                   q->soname ? q->soname : exname(q->sname));
+               } else
+                       printf("\n");
+               break;
+
+       case STARG:
+       case STASG:
+       case STCALL:
+       case USTCALL:
+               /* print out size */
+               /* use lhs size, in order to avoid hassles
+                * with the structure `.' operator
+                */
+
+               /* note: p->left not a field... */
+               printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df,
+                   p->n_left->n_ap));
+               printf("\t%d\t\n", talign(STRTY, p->n_left->n_ap));
+               break;
+
+       case XARG:
+       case XASM:
+               break;
+
+       default:
+               printf(  "\n" );
+       }
+
+       if (ty != LTYPE)
+               p2tree(p->n_left);
+       if (ty == BITYPE)
+               p2tree(p->n_right);
+}
+#else
+static char *
+sptostr(struct symtab *sp)
+{
+       char *cp = inlalloc(32);
+       int n = sp->soffset;
+       if (n < 0)
+               n = -n;
+       snprintf(cp, 32, LABFMT, n);
+       return cp;
+}
+
+void
+p2tree(NODE *p)
+{
+       struct attr *oap, *ap;
+       struct symtab *q;
+       int ty;
+
+       myp2tree(p);  /* local action can be taken here */
+
+       /* Fix left imaginary types */
+       if (ISITY(BTYPE(p->n_type)))
+               MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT));
+
+       /* cleanup attributes.
+        * copy those that are supposed to go into pass2 */
+       oap = p->n_ap;
+       p->n_ap = NULL;
+       for (ap = oap; ap; ap = ap->next)
+               if (ap->atype < ATTR_MI_MAX)
+                       p->n_ap = attr_add(p->n_ap, attr_dup(ap));
+       /* XXX store size of attr in itself */
+
+       ty = coptype(p->n_op);
+
+       switch( p->n_op ){
+
+       case NAME:
+       case ICON:
+               if ((q = p->n_sp) != NULL) {
+                       if ((q->sclass == STATIC && q->slevel > 0)
+#ifdef GCC_COMPAT
+                           || q->sflags == SLBLNAME
+#endif
+                           ) {
+                               p->n_name = sptostr(q);
+                       } else {
+                               if ((p->n_name = q->soname) == NULL)
+                                       p->n_name = addname(exname(q->sname));
+                       }
+               } else
+                       p->n_name = "";
+               break;
+
+       case STASG:
+       case STARG:
+       case STCALL:
+       case USTCALL:
+               /* STASG used for stack array init */
+               if (p->n_op == STASG && ISARY(p->n_type)) {
+                       int size1 = (int)tsize(p->n_type, p->n_left->n_df,
+                           p->n_left->n_ap)/SZCHAR;
+                       ap->iarg(0) = (int)tsize(p->n_type, p->n_right->n_df,
+                           p->n_right->n_ap)/SZCHAR;
+                       if (size1 < ap->iarg(0))
+                               ap->iarg(0) = size1;
+                       ap->iarg(1) = talign(p->n_type,
+                           p->n_left->n_ap)/SZCHAR;
+                       break;
+               }
+               /* set up size parameters */
+               ap->iarg(0) = (int)((tsize(STRTY, p->n_left->n_df,
+                   p->n_left->n_ap)+SZCHAR-1)/SZCHAR);
+               ap->iarg(1) = talign(STRTY,p->n_left->n_ap)/SZCHAR;
+               if (ap->iarg(1) == 0)
+                       ap->iarg(1) = 1; /* At least char for packed structs */
+               break;
+
+       case XARG:
+       case XASM:
+               break;
+
+       default:
+               p->n_name = "";
+               }
+
+       if( ty != LTYPE ) p2tree( p->n_left );
+       if( ty == BITYPE ) p2tree( p->n_right );
+       }
+
+#endif
+
+/*
+ * Change void data types into char.
+ */
+static void
+delvoid(NODE *p, void *arg)
+{
+       /* Convert "PTR undef" (void *) to "PTR uchar" */
+       if (BTYPE(p->n_type) == VOID)
+               p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+       if (BTYPE(p->n_type) == BOOL) {
+               if (p->n_op == SCONV && p->n_type == BOOL) {
+                       /* create a jump and a set */
+                       NODE *r;
+                       int l, l2;
+
+                       r = tempnode(0, BOOL_TYPE, NULL, 0);
+                       cbranch(buildtree(EQ, p->n_left, bcon(0)),
+                           bcon(l = getlab()));
+                       *p = *r;
+                       ecode(buildtree(ASSIGN, tcopy(r), bcon(1)));
+                       branch(l2 = getlab());
+                       plabel(l);
+                       ecode(buildtree(ASSIGN, r, bcon(0)));
+                       plabel(l2);
+               } else
+                       p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE;
+       }
+               
+}
+
+/*
+ * Change calls inside calls to separate statement.
+ */
+static NODE *
+deldcall(NODE *p, int split)
+{
+       NODE *q, *r;
+       int o = p->n_op;
+
+       if (cdope(o) & CALLFLG) {
+               if (split) {
+                       q = cstknode(p->n_type, p->n_df, p->n_ap);
+                       r = ccopy(q);
+                       q = block(ASSIGN, q, p, p->n_type, p->n_df, p->n_ap);
+                       ecode(q);
+                       return r;
+               }
+               split++;
+       }
+       if (coptype(o) == BITYPE)
+               p->n_right = deldcall(p->n_right, split);
+       if (coptype(o) != LTYPE)
+               p->n_left = deldcall(p->n_left, split);
+       return p;
+}
+
+#ifndef WORD_ADDRESSED
+
+static NODE *
+pprop(NODE *p, TWORD t, struct attr *ap)
+{
+       int o = p->n_op;
+       TWORD t2;
+
+#ifdef PCC_DEBUG
+       if (p->n_op == TEMP && p->n_type != t &&
+           !(ISPTR(p->n_type) && ISPTR(t))) {
+               cerror("TEMP type change: %x -> %x", p->n_type, t);
+       }
+#endif
+
+       p->n_type = t;
+       p->n_ap = ap;
+       switch (o) {
+       case UMUL:
+               t = INCREF(t);
+               break;
+       case ADDROF:
+               t2 = p->n_left->n_type;
+               if (p->n_left->n_op == TEMP) {
+                       /* Will be converted to memory in pass2 */
+                       if (!ISPTR(t2) && DECREF(t) != t2) 
+                               ; /* XXX cannot convert this */
+                       else
+                               p->n_left->n_type = DECREF(t);
+                       return p;
+               }
+               if (ISPTR(t2) && !ISPTR(DECREF(t)))
+                       break; /* not quite correct */
+               t = DECREF(t);
+               break;
+       case PCONV:
+               return p;
+
+       case PLUSEQ:
+       case PLUS:
+       case INCR:
+       case DECR:
+               if (!ISPTR(p->n_left->n_type)) {
+                       if (!ISPTR(p->n_right->n_type))
+                               cerror("no * in PLUS");
+                       p->n_right = pprop(p->n_right, t, ap);
+               } else
+                       p->n_left = pprop(p->n_left, t, ap);
+               return p;
+
+       case MINUSEQ:
+       case MINUS:
+               if (ISPTR(p->n_left->n_type)) {
+                       if (ISPTR(p->n_right->n_type))
+                               break; /* change both */
+                       p->n_left = pprop(p->n_left, t, ap);
+               } else 
+                       p->n_right = pprop(p->n_right, t, ap);
+               return p;
+
+       case CALL:
+       case UCALL:
+       case STCALL: /* may end up here if struct passed in regs */
+       case USTCALL:
+               return p;
+
+       case STASG: /* if struct is cast to pointer */
+               return p;
+
+       case ASSIGN:
+               break;
+
+       default:
+               if (coptype(o) == LTYPE)
+                       break;
+
+#ifdef PCC_DEBUG
+               fwalk(p, eprint, 0);
+#endif
+               cerror("pprop op error %d\n", o);
+       }
+       if (coptype(o) == BITYPE)
+               p->n_right = pprop(p->n_right, t, ap);
+       if (coptype(o) != LTYPE)
+               p->n_left = pprop(p->n_left, t, ap);
+       return p;
+}
+
+/*
+ * Search for PCONV's that can be removed while still keeping
+ * the type correctness.
+ */
+NODE *
+rmpconv(NODE *p)
+{
+       struct symtab *sp;
+       int o = p->n_op;
+       int ot = coptype(o);
+       NODE *q, *l;
+
+       if (ot != LTYPE)
+               p->n_left = rmpconv(p->n_left);
+       if (ot == BITYPE)
+               p->n_right = rmpconv(p->n_right);
+       if (o != PCONV)
+               return p;
+       l = p->n_left;
+       if (nncon(l) || (cdope(l->n_op) & CALLFLG))
+               ; /* Let any nonamed constant be cast to pointer directly */
+       else if (l->n_type >= INTPTR && l->n_op == ICON) {
+               /* named constants only if >= pointer size */
+               /* create INTPTR type */
+               sp = l->n_sp;
+               l->n_sp = NULL;
+               concast(l, INTPTR);
+               l->n_sp = sp;
+       } else if (!ISPTR(l->n_type))
+               return p;
+       q = pprop(p->n_left, p->n_type, p->n_ap);
+       nfree(p);
+       return q;
+}
+#endif
+
+void
+ecode(NODE *p) 
+{
+       /* walk the tree and write out the nodes.. */
+
+       if (nerrors)    
+               return;
+
+#ifdef GCC_COMPAT
+       {
+               NODE *q = p;
+
+               if (q->n_op == UMUL)
+                       q = p->n_left;
+               if (cdope(q->n_op)&CALLFLG &&
+                   attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT))
+                       werror("return value ignored");
+       }
+#endif
+#ifndef WORD_ADDRESSED
+       p = rmpconv(p);
+#endif
+       p = optim(p);
+       p = delasgop(p);
+       p = deldcall(p, 0);
+       walkf(p, delvoid, 0);
+#ifdef PCC_DEBUG
+       if (xdebug) {
+               printf("Fulltree:\n"); 
+               fwalk(p, eprint, 0); 
+       }
+#endif
+       p2tree(p);
+#if !defined(MULTIPASS)
+       send_passt(IP_NODE, p);
+#endif
+}
+
+/*
+ * Send something further on to the next pass.
+ */
+void
+send_passt(int type, ...)
+{
+       struct interpass *ip;
+       struct interpass_prolog *ipp;
+       extern int crslab;
+       va_list ap;
+       int sz;
+
+       va_start(ap, type);
+       if (cftnsp == NULL && type != IP_ASM) {
+#ifdef notyet
+               cerror("no function");
+#endif
+               if (type == IP_NODE)
+                       tfree(va_arg(ap, NODE *));
+               return;
+       }
+       if (type == IP_PROLOG || type == IP_EPILOG)
+               sz = sizeof(struct interpass_prolog);
+       else
+               sz = sizeof(struct interpass);
+
+       ip = inlalloc(sz);
+       ip->type = type;
+       ip->lineno = lineno;
+       switch (type) {
+       case IP_NODE:
+               ip->ip_node = va_arg(ap, NODE *);
+               if (ip->ip_node->n_op == LABEL) {
+                       NODE *p = ip->ip_node;
+                       ip->ip_lbl = glval(p->n_left);
+                       ip->type = IP_DEFLAB;
+                       nfree(nfree(p));
+               }
+               break;
+       case IP_EPILOG:
+               if (!isinlining) {
+                       locctr(PROG, cftnsp);
+                       defloc(cftnsp);
+               }
+               /* FALLTHROUGH */
+       case IP_PROLOG:
+               inftn = type == IP_PROLOG ? 1 : 0;
+               ipp = (struct interpass_prolog *)ip;
+               memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0,
+                   sizeof(ipp->ipp_regs));
+               ipp->ipp_autos = va_arg(ap, int);
+               ipp->ipp_name = va_arg(ap, char *);
+               ipp->ipp_type = va_arg(ap, TWORD);
+               ipp->ipp_vis = va_arg(ap, int);
+               ip->ip_lbl = va_arg(ap, int);
+               ipp->ip_tmpnum = va_arg(ap, int);
+               ipp->ip_lblnum = crslab;
+               if (type == IP_PROLOG)
+                       ipp->ip_lblnum--;
+               break;
+       case IP_DEFLAB:
+               ip->ip_lbl = va_arg(ap, int);
+               break;
+       case IP_ASM:
+               if (blevel == 0) { /* outside function */
+                       printf("%s", va_arg(ap, char *));
+                       va_end(ap);
+                       locctr(NOSEG, NULL);
+                       return;
+               }
+               ip->ip_asm = va_arg(ap, char *);
+               break;
+       default:
+               cerror("bad send_passt type %d", type);
+       }
+       va_end(ap);
+       pass1_lastchance(ip); /* target-specific info */
+       if (isinlining)
+               inline_addarg(ip);
+       else
+               pass2_compile(ip);
+}
+
+char *
+copst(int op)
+{
+       if (op <= MAXOP)
+               return opst[op];
+#define        SNAM(x,y) case x: return #y;
+       switch (op) {
+       SNAM(QUALIFIER,QUALIFIER)
+       SNAM(CLASS,CLASS)
+       SNAM(RB,])
+       SNAM(DOT,.)
+       SNAM(ELLIPSIS,...)
+       SNAM(LB,[)
+       SNAM(TYPE,TYPE)
+       SNAM(COMOP,COMOP)
+       SNAM(QUEST,?)
+       SNAM(COLON,:)
+       SNAM(ANDAND,&&)
+       SNAM(OROR,||)
+       SNAM(NOT,!)
+       SNAM(CAST,CAST)
+       SNAM(PLUSEQ,+=)
+       SNAM(MINUSEQ,-=)
+       SNAM(MULEQ,*=)
+       SNAM(DIVEQ,/=)
+       SNAM(MODEQ,%=)
+       SNAM(ANDEQ,&=)
+       SNAM(OREQ,|=)
+       SNAM(EREQ,^=)
+       SNAM(LSEQ,<<=)
+       SNAM(RSEQ,>>=)
+       SNAM(INCR,++)
+       SNAM(DECR,--)
+       SNAM(STRING,STRING)
+       SNAM(SZOF,SIZEOF)
+       SNAM(ATTRIB,ATTRIBUTE)
+       SNAM(TYMERGE,TYMERGE)
+       SNAM(LABEL,LABEL)
+       SNAM(NEWKW,NEW)
+       SNAM(NMLIST,::)
+#ifdef GCC_COMPAT
+       SNAM(XREAL,__real__)
+       SNAM(XIMAG,__imag__)
+#endif
+       default:
+               cerror("bad copst %d", op);
+       }
+       return 0; /* XXX gcc */
+}
+
+int
+cdope(int op)
+{
+       if (op <= MAXOP)
+               return dope[op];
+       switch (op) {
+       case CLOP:
+       case STRING:
+       case QUALIFIER:
+       case CLASS:
+       case RB:
+       case ELLIPSIS:
+       case TYPE:
+               return LTYPE;
+       case DOT:
+       case SZOF:
+       case COMOP:
+       case QUEST:
+       case COLON:
+       case LB:
+       case TYMERGE:
+       case NEWKW:
+       case NMLIST:
+               return BITYPE;
+       case XIMAG:
+       case XREAL:
+       case ATTRIB:
+       case LABEL:
+               return UTYPE;
+       case ANDAND:
+       case OROR:
+               return BITYPE|LOGFLG;
+       case NOT:
+               return UTYPE|LOGFLG;
+       case CAST:
+               return BITYPE|ASGFLG|ASGOPFLG;
+       case PLUSEQ:
+               return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG;
+       case MINUSEQ:
+               return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG;
+       case MULEQ:
+               return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG;
+       case OREQ:
+       case EREQ:
+       case ANDEQ:
+               return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG;
+       case DIVEQ:
+               return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG;
+       case MODEQ:
+               return BITYPE|DIVFLG|ASGFLG|ASGOPFLG;
+       case LSEQ:
+       case RSEQ:
+               return BITYPE|SHFFLG|ASGFLG|ASGOPFLG;
+       case INCR:
+       case DECR:
+               return BITYPE|ASGFLG;
+       }
+       cerror("cdope missing op %d", op);
+       return 0; /* XXX gcc */
+}
+
+/* 
+ * make a fresh copy of p
+ */
+NODE *
+ccopy(NODE *p) 
+{  
+       NODE *q;
+
+       q = talloc();
+       *q = *p;
+
+       switch (coptype(q->n_op)) {
+       case BITYPE:
+               q->n_right = ccopy(p->n_right);
+       case UTYPE: 
+               q->n_left = ccopy(p->n_left);
+       }
+
+       return(q);
+}
+
+NODE *
+nlabel(int label)
+{
+       return block(LABEL, bcon(label), NIL, 0, 0, 0);
+}
+
+/*
+ * set PROG-seg label.
+ */
+void
+plabel(int label)
+{
+       reached = 1; /* Will this always be correct? */
+       send_passt(IP_NODE, nlabel(label));
+}
+
+/*
+ * Perform integer promotion on node n.
+ */
+NODE *
+intprom(NODE *n)
+{
+       if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) {
+               if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) ||
+                   (n->n_type == USHORT && MAX_USHORT > MAX_INT))
+                       return makety(n, UNSIGNED, 0, 0, 0);
+               return makety(n, INT, 0, 0, 0);
+       }
+       return n;
+}
+
+/*
+ * Return CON/VOL/0, whichever are active for the current type.
+ */
+int
+cqual(TWORD t, TWORD q)
+{
+       while (ISARY(t))
+               t = DECREF(t), q = DECQAL(q);
+       if (t <= BTMASK)
+               q <<= TSHIFT;
+       return q & (CON|VOL);
+}
+
+int crslab = 10;
+/*
+ * Return a number for internal labels.
+ */
+int
+getlab(void)
+{
+       return crslab++;
+}
diff --git a/lang/pcc/pcc/cc/driver/Makefile.in b/lang/pcc/pcc/cc/driver/Makefile.in
new file mode 100644 (file)
index 0000000..69f5a76
--- /dev/null
@@ -0,0 +1,61 @@
+#      $Id: Makefile.in,v 1.9 2012/09/25 11:17:17 plunky Exp $
+#
+# Makefile.in for the cc driver part of pcc.
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+top_builddir=@top_builddir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+includedir = @includedir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+CC = @CC@
+EXEEXT = @EXEEXT@
+TARGOS = @targos@
+TARGOSVER = @targosver@
+TARGMACH = @targmach@
+TARGET = @target@
+VERSION = @PACKAGE_VERSION@
+PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib
+PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"$(libexecdir)/\" \
+       @ADD_CPPFLAGS@ -DINCLUDEDIR=\"$(includedir)/\" \
+       -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \
+       -DTARGOS=\"$(TARGOS)\" -DTARGOSVER=$(TARGOSVER) -Dos_$(TARGOS) \
+       -DTARGMACH=\"$(TARGMACH)\" -Dmach_$(TARGMACH) \
+       -I$(top_builddir) -I$(top_srcdir)/os/$(TARGOS) -I$(MIPDIR) -I$(MDIR)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+OBJS=driver.o platform.o strlist.o xalloc.o
+DEST=@BINPREFIX@pcc$(EXEEXT)
+
+MIPDIR=$(top_srcdir)/mip
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+
+all: $(DEST)
+
+$(DEST): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+.c.o:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+install:
+       test -z "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)"
+       $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(bindir)
+
+clean:
+       rm -f  $(OBJS) $(DEST)
+
+distclean: clean
+       rm -f  Makefile
diff --git a/lang/pcc/pcc/cc/driver/driver.c b/lang/pcc/pcc/cc/driver/driver.c
new file mode 100644 (file)
index 0000000..edbd748
--- /dev/null
@@ -0,0 +1,881 @@
+/*     $Id: driver.c,v 1.7 2011/06/03 15:34:01 plunky Exp $    */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/wait.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "driver.h"
+#include "xalloc.h"
+
+#include "config.h"
+
+static volatile sig_atomic_t exit_now;
+static volatile sig_atomic_t child;
+
+static void
+sigterm_handler(int signum)
+{
+       exit_now = 1;
+       if (child)
+               kill(child, SIGTERM);
+}
+
+static const char versionstr[] = VERSSTR;
+
+enum phases { DEFAULT, PREPROCESS, COMPILE, ASSEMBLE, LINK } last_phase =
+    DEFAULT;
+
+const char *isysroot = NULL;
+const char *sysroot = "";
+const char *preprocessor;
+const char *compiler;
+const char *assembler;
+const char *linker;
+
+struct strlist crtdirs;
+static struct strlist user_sysincdirs;
+struct strlist sysincdirs;
+struct strlist includes;
+struct strlist incdirs;
+struct strlist libdirs;
+struct strlist progdirs;
+struct strlist preprocessor_flags;
+struct strlist compiler_flags;
+struct strlist assembler_flags;
+struct strlist early_linker_flags;
+struct strlist middle_linker_flags;
+struct strlist late_linker_flags;
+struct strlist stdlib_flags;
+struct strlist early_program_csu_files;
+struct strlist late_program_csu_files;
+struct strlist early_dso_csu_files;
+struct strlist late_dso_csu_files;
+struct strlist temp_outputs;
+
+const char *final_output;
+static char *temp_directory;
+static struct strlist inputs;
+
+int pic_mode; /* 0: no PIC, 1: -fpic, 2: -fPIC */
+int save_temps;
+int debug_mode;
+int profile_mode;
+int nostdinc;
+int nostdlib;
+int nostartfiles;
+int static_mode;
+int shared_mode;
+int use_pthread;
+int verbose_mode;
+
+void
+error(const char *fmt, ...)
+{
+       va_list arg;
+       va_start(arg, fmt);
+       vfprintf(stderr, fmt, arg);
+       putc('\n', stderr);
+       va_end(arg);
+       exit(1);
+}
+
+static void
+warning(const char *fmt, ...)
+{
+       va_list arg;
+       va_start(arg, fmt);
+       vfprintf(stderr, fmt, arg);
+       putc('\n', stderr);
+       va_end(arg);
+}
+
+static void
+set_last_phase(enum phases phase)
+{
+       assert(phase != DEFAULT);
+       if (last_phase != DEFAULT && phase != last_phase)
+               error("conflicting compiler options specified");
+       last_phase = phase;
+}
+
+static void
+expand_sysroot(void)
+{
+       struct string *s;
+       struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs,
+           &user_sysincdirs, &libdirs, &progdirs, NULL };
+       const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot,
+           sysroot, sysroot, NULL };
+       size_t i, sysroot_len, value_len;
+       char *path;
+
+       assert(sizeof(lists) / sizeof(lists[0]) ==
+              sizeof(sysroots) / sizeof(sysroots[0]));
+
+       for (i = 0; lists[i] != NULL; ++i) {
+               STRLIST_FOREACH(s, lists[i]) {
+                       if (s->value[0] != '=')
+                               continue;
+                       sysroot_len = strlen(sysroots[i]);
+                       /* Skipped '=' compensates additional space for '\0' */
+                       value_len = strlen(s->value);
+                       path = xmalloc(sysroot_len + value_len);
+                       memcpy(path, sysroots[i], sysroot_len);
+                       memcpy(path + sysroot_len, s->value + 1, value_len);
+                       free(s->value);
+                       s->value = path;
+               }
+       }
+}
+
+static void
+missing_argument(const char *argp)
+{
+       error("Option `%s' required an argument", argp);
+}
+
+static void
+split_and_append(struct strlist *l, char *arg)
+{
+       char *next;
+
+       for (; arg != NULL; arg = NULL) {
+               next = strchr(arg, ',');
+               if (next != NULL)
+                       *next++ = '\0';
+               strlist_append(l, arg);
+       }
+}
+
+static int
+strlist_exec(struct strlist *l)
+{
+       char **argv;
+       size_t argc;
+       int result;
+
+       strlist_make_array(l, &argv, &argc);
+       if (verbose_mode) {
+               printf("Calling ");
+               strlist_print(l, stdout);
+               printf("\n");
+       }
+
+       if (exit_now)
+               return 1;
+
+       switch ((child = fork())) {
+       case 0:
+               execvp(argv[0], argv);
+               result = write(STDERR_FILENO, "Exec of ", 8);
+               result = write(STDERR_FILENO, argv[0], strlen(argv[0]));
+               result = write(STDERR_FILENO, "failed\n", 7);
+               (void)result;
+               _exit(127);
+       case -1:
+               error("fork failed");
+       default:
+               while (waitpid(child, &result, 0) == -1 && errno == EINTR)
+                       /* nothing */(void)0;
+               result = WEXITSTATUS(result);
+               if (result)
+                       error("%s terminated with status %d", argv[0], result);
+               while (argc-- > 0)
+                       free(argv[argc]);
+               free(argv);
+               break;
+       }
+       return exit_now;
+}
+
+static char *
+find_file(const char *file, struct strlist *path, int mode)
+{
+       struct string *s;
+       char *f;
+       size_t lf, lp;
+       int need_sep;
+
+       lf = strlen(file);
+       STRLIST_FOREACH(s, path) {
+               lp = strlen(s->value);
+               need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0;
+               f = xmalloc(lp + lf + need_sep + 1);
+               memcpy(f, s->value, lp);
+               if (need_sep)
+                       f[lp] = '/';
+               memcpy(f + lp + need_sep, file, lf + 1);
+               if (access(f, mode) == 0)
+                       return f;
+               free(f);
+       }
+       return xstrdup(file);
+}
+
+static char *
+output_name(const char *file, const char *new_suffix, int counter, int last)
+{
+       const char *old_suffix;
+       char *name;
+       size_t lf, ls, len;
+       int counter_len;
+
+       if (last && final_output)
+               return xstrdup(final_output);
+
+       old_suffix = strrchr(file, '.');
+       if (old_suffix != NULL && strchr(old_suffix, '/') != NULL)
+               old_suffix = NULL;
+       if (old_suffix == NULL)
+               old_suffix = file + strlen(file);
+
+       ls = strlen(new_suffix);
+       if (save_temps || last) {
+               lf = old_suffix - file;
+               name = xmalloc(lf + ls + 1);
+               memcpy(name, file, lf);
+               memcpy(name + lf, new_suffix, ls + 1);
+               return name;
+       }
+       if (temp_directory == NULL) {
+               const char *template;
+               char *path;
+               size_t template_len;
+               int need_sep;
+
+               template = getenv("TMPDIR");
+               if (template == NULL)
+                       template = "/tmp";
+               template_len = strlen(template);
+               if (template_len && template[template_len - 1] == '/')
+                       need_sep = 0;
+               else
+                       need_sep = 1;
+               path = xmalloc(template_len + need_sep + 6 + 1);
+               memcpy(path, template, template_len);
+               if (need_sep)
+                       path[template_len] = '/';
+               memcpy(path + template_len + need_sep, "pcc-XXXXXX", 11);
+               if (mkdtemp(path) == NULL)
+                       error("mkdtemp failed: %s", strerror(errno));
+               temp_directory = path;
+       }
+       lf = strlen(temp_directory);
+       counter_len = snprintf(NULL, 0, "%d", counter);
+       if (counter_len < 1)
+               error("snprintf failure");
+       len = lf + 1 + (size_t)counter_len + ls + 1;
+       name = xmalloc(len);
+       snprintf(name, len, "%s/%d%s", temp_directory, counter, new_suffix);
+       strlist_append(&temp_outputs, name);
+       return name;
+}
+
+static int
+preprocess_input(const char *file, char *input, char **output,
+    const char *suffix, int counter)
+{
+       struct strlist args;
+       struct string *s;
+       char *out;
+       int retval;
+
+       strlist_init(&args);
+       strlist_append_list(&args, &preprocessor_flags);
+       STRLIST_FOREACH(s, &includes) {
+               strlist_append(&args, "-i");
+               strlist_append(&args, s->value);
+       }
+       STRLIST_FOREACH(s, &incdirs) {
+               strlist_append(&args, "-I");
+               strlist_append(&args, s->value);
+       }
+       STRLIST_FOREACH(s, &user_sysincdirs) {
+               strlist_append(&args, "-S");
+               strlist_append(&args, s->value);
+       }
+       if (!nostdinc) {
+               STRLIST_FOREACH(s, &sysincdirs) {
+                       strlist_append(&args, "-S");
+                       strlist_append(&args, s->value);
+               }
+       }
+       strlist_append(&args, input);
+       if (last_phase == PREPROCESS && final_output == NULL)
+               out = xstrdup("-");
+       else
+               out = output_name(file, suffix, counter,
+                   last_phase == PREPROCESS);
+       if (strcmp(out, "-"))
+               strlist_append(&args, out);
+       strlist_prepend(&args, find_file(preprocessor, &progdirs, X_OK));
+       *output = out;
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+
+static int
+compile_input(const char *file, char *input, char **output,
+    const char *suffix, int counter)
+{
+       struct strlist args;
+       char *out;
+       int retval;
+
+       strlist_init(&args);
+       strlist_append_list(&args, &compiler_flags);
+       if (debug_mode)
+               strlist_append(&args, "-g");
+       if (pic_mode)
+               strlist_append(&args, "-k");
+       if (profile_mode)
+               warning("-pg is currently ignored");
+       strlist_append(&args, input);
+       out = output_name(file, suffix, counter, last_phase == ASSEMBLE);
+       strlist_append(&args, out);
+       strlist_prepend(&args, find_file(compiler, &progdirs, X_OK));
+       *output = out;
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+
+static int
+assemble_input(const char *file, char *input, char **output,
+    const char *suffix, int counter)
+{
+       struct strlist args;
+       char *out;
+       int retval;
+
+       strlist_init(&args);
+       strlist_append_list(&args, &assembler_flags);
+       strlist_append(&args, input);
+       out = output_name(file, ".o", counter, last_phase == COMPILE);
+       strlist_append(&args, "-o");
+       strlist_append(&args, out);
+       strlist_prepend(&args, find_file(assembler, &progdirs, X_OK));
+       *output = out;
+       retval = strlist_exec(&args);
+       strlist_free(&args);
+       return retval;
+}
+
+static int
+handle_input(const char *file)
+{
+       static int counter;
+       const char *suffix;
+       char *src;
+       int handled, retval;
+
+       ++counter;
+
+       if (strcmp(file, "-") == 0) {
+               /* XXX see -x option */
+               suffix = ".c";
+       } else {
+               suffix = strrchr(file, '.');
+               if (suffix != NULL && strchr(suffix, '/') != NULL)
+                       suffix = NULL;
+               if (suffix == NULL)
+                       suffix = "";
+       }
+
+       src = xstrdup(file);
+       if (strcmp(suffix, ".c") == 0) {
+               suffix = ".i";
+               retval = preprocess_input(file, src, &src, suffix, counter);
+               if (retval)
+                       return retval;
+               handled = 1;
+       } else if (strcmp(suffix, ".S") == 0) {
+               suffix = ".s";
+               retval = preprocess_input(file, src, &src, suffix, counter);
+               if (retval)
+                       return retval;
+               handled = 1;
+       }
+
+       if (last_phase == PREPROCESS)
+               goto done;
+
+       if (strcmp(suffix, ".i") == 0) {
+               suffix = ".s";
+               retval = compile_input(file, src, &src, suffix, counter);
+               if (retval)
+                       return retval;
+               handled = 1;
+       }
+       if (last_phase == ASSEMBLE)
+               goto done;
+
+       if (strcmp(suffix, ".s") == 0) {
+               suffix = ".o";
+               retval = assemble_input(file, src, &src, suffix, counter);
+               if (retval)
+                       return retval;
+               handled = 1;
+       }
+       if (last_phase == COMPILE)
+               goto done;
+       if (strcmp(suffix, ".o") == 0)
+               handled = 1;
+       strlist_append(&middle_linker_flags, src);
+done:
+       if (handled)
+               return 0;
+       if (last_phase == LINK)
+               warning("unknown suffix %s, passing file down to linker",
+                   suffix);
+       else
+               warning("unknown suffix %s, skipped", suffix);
+       free(src);
+       return 0;
+}
+
+static int
+run_linker(void)
+{
+       struct strlist linker_flags;
+       struct strlist *early_csu, *late_csu;
+       struct string *s;
+       int retval;
+
+       if (final_output) {
+               strlist_prepend(&early_linker_flags, final_output);
+               strlist_prepend(&early_linker_flags, "-o");
+       }
+       if (!nostdlib)
+               strlist_append_list(&late_linker_flags, &stdlib_flags);
+       if (!nostartfiles) {
+               if (shared_mode) {
+                       early_csu = &early_dso_csu_files;
+                       late_csu = &late_dso_csu_files;
+               } else {
+                       early_csu = &early_program_csu_files;
+                       late_csu = &late_program_csu_files;
+               }
+               STRLIST_FOREACH(s, early_csu)
+                       strlist_append_nocopy(&middle_linker_flags,
+                           find_file(s->value, &crtdirs, R_OK));
+               STRLIST_FOREACH(s, late_csu)
+                       strlist_append_nocopy(&late_linker_flags,
+                           find_file(s->value, &crtdirs, R_OK));
+       }
+       strlist_init(&linker_flags);
+       strlist_append_list(&linker_flags, &early_linker_flags);
+       strlist_append_list(&linker_flags, &middle_linker_flags);
+       strlist_append_list(&linker_flags, &late_linker_flags);
+       strlist_prepend(&linker_flags, find_file(linker, &progdirs, X_OK));
+
+       retval = strlist_exec(&linker_flags);
+
+       strlist_free(&linker_flags);
+       return retval;
+}
+
+static void
+cleanup(void)
+{
+       struct string *file;
+
+       STRLIST_FOREACH(file, &temp_outputs) {
+               if (unlink(file->value) == -1)
+                       warning("removal of ``%s'' failed: %s", file->value,
+                           strerror(errno));
+       }
+       if (temp_directory && rmdir(temp_directory) == -1)
+               warning("removal of ``%s'' failed: %s", temp_directory,
+                   strerror(errno));
+}
+
+int
+main(int argc, char **argv)
+{
+       struct string *input;
+       char *argp;
+       int retval;
+
+       strlist_init(&crtdirs);
+       strlist_init(&user_sysincdirs);
+       strlist_init(&sysincdirs);
+       strlist_init(&incdirs);
+       strlist_init(&includes);
+       strlist_init(&libdirs);
+       strlist_init(&progdirs);
+       strlist_init(&inputs);
+       strlist_init(&preprocessor_flags);
+       strlist_init(&compiler_flags);
+       strlist_init(&assembler_flags);
+       strlist_init(&early_linker_flags);
+       strlist_init(&middle_linker_flags);
+       strlist_init(&late_linker_flags);
+       strlist_init(&stdlib_flags);
+       strlist_init(&early_program_csu_files);
+       strlist_init(&late_program_csu_files);
+       strlist_init(&early_dso_csu_files);
+       strlist_init(&late_dso_csu_files);
+       strlist_init(&temp_outputs);
+
+       init_platform_specific(TARGOS, TARGMACH);
+
+       while (--argc) {
+               ++argv;
+               argp = *argv;
+
+               if (*argp != '-' || strcmp(argp, "-") == 0) {
+                       strlist_append(&inputs, argp);
+                       continue;
+               }
+               switch (argp[1]) {
+               case '-':
+                       if (strcmp(argp, "--param") == 0) {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               /* Unused */
+                               continue;
+                       }
+                       if (strncmp(argp, "--sysroot=", 10) == 0) {
+                               sysroot = argp + 10;
+                               continue;
+                       }
+                       if (strcmp(argp, "--version") == 0) {
+                               printf("%s\n", versionstr);
+                               exit(0);
+                       }
+                       break;
+               case 'B':
+                       strlist_append(&crtdirs, argp);
+                       strlist_append(&libdirs, argp);
+                       strlist_append(&progdirs, argp);
+                       continue;
+               case 'C':
+                       if (argp[2] == '\0') {
+                               strlist_append(&preprocessor_flags, argp);
+                               continue;
+                       }
+                       break;
+               case 'c':
+                       if (argp[2] == '\0') {
+                               set_last_phase(COMPILE);
+                               continue;
+                       }
+                       break;
+               case 'D':
+                       strlist_append(&preprocessor_flags, argp);
+                       if (argp[2] == '\0') {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               strlist_append(&preprocessor_flags, argp);
+                       }
+                       continue;
+               case 'E':
+                       if (argp[2] == '\0') {
+                               set_last_phase(PREPROCESS);
+                               continue;
+                       }
+                       break;
+               case 'f':
+                       if (strcmp(argp, "-fpic") == 0) {
+                               pic_mode = 1;
+                               continue;
+                       }
+                       if (strcmp(argp, "-fPIC") == 0) {
+                               pic_mode = 2;
+                               continue;
+                       }
+                       /* XXX GCC options */
+                       break;
+               case 'g':
+                       if (argp[2] == '\0') {
+                               debug_mode = 1;
+                               continue;
+                       }
+                       /* XXX allow variants like -g1? */
+                       break;
+               case 'I':
+                       if (argp[2] == '\0') {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               strlist_append(&incdirs, argp);
+                               continue;
+                       }
+                       strlist_append(&incdirs, argp + 2);
+                       continue;
+               case 'i':
+                       if (strcmp(argp, "-isystem") == 0) {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               strlist_append(&user_sysincdirs, argp);
+                               continue;
+                       }
+                       if (strcmp(argp, "-include") == 0) {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               strlist_append(&includes, argp);
+                               continue;
+                       }
+                       if (strcmp(argp, "-isysroot") == 0) {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               isysroot = argp;
+                               continue;
+                       }
+                       /* XXX -idirafter */
+                       /* XXX -iquote */
+                       break;
+               case 'k':
+                       if (argp[2] == '\0') {
+                               pic_mode = 1;
+                               continue;
+                       }
+                       break;
+               case 'M':
+                       if (argp[2] == '\0') {
+                               strlist_append(&preprocessor_flags, argp);
+                               continue;
+                       }
+                       break;
+               case 'm':
+                       /* XXX implement me */
+                       break;
+               case 'n':
+                       if (strcmp(argp, "-nostdinc") == 0) {
+                               nostdinc = 1;
+                               continue;
+                       }
+                       if (strcmp(argp, "-nostdinc++") == 0)
+                               continue;
+                       if (strcmp(argp, "-nostdlib") == 0) {
+                               nostdlib = 1;
+                               nostartfiles = 1;
+                               continue;
+                       }
+                       if (strcmp(argp, "-nostartfiles") == 0) {
+                               nostartfiles = 1;
+                               continue;
+                       }
+                       break;
+               case 'O':
+                       if (argp[2] != '\0' && argp[3] != '\0')
+                               break;
+                       switch(argp[2]) {
+                       case '2':
+                       case '1': case '\0':
+                               strlist_append(&compiler_flags, "-xtemps");
+                               strlist_append(&compiler_flags, "-xdeljumps");
+                               strlist_append(&compiler_flags, "-xinline");
+                       case '0':
+                               continue;
+                       }
+                       break;
+               case 'o':
+                       if (argp[2] == '\0') {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               if (final_output)
+                                       error("Only one `-o' option allowed");
+                               final_output = *argv;
+                               continue;
+                       }
+                       break;
+               case 'p':
+                       if (argp[2] == '\0' || strcmp(argp, "-pg") == 0) {
+                               profile_mode = 1;
+                               continue;
+                       }
+                       if (strcmp(argp, "-pedantic") == 0)
+                               continue;
+                       if (strcmp(argp, "-pipe") == 0)
+                               continue; /* XXX implement me */
+                       if (strcmp(argp, "-pthread") == 0) {
+                               use_pthread = 1;
+                               continue;
+                       }
+                       /* XXX -print-prog-name=XXX */
+                       /* XXX -print-multi-os-directory */
+                       break;
+               case 'r':
+                       if (argp[2] == '\0') {
+                               strlist_append(&middle_linker_flags, argp);
+                               continue;
+                       }
+                       break;
+               case 'S':
+                       if (argp[2] == '\0') {
+                               set_last_phase(ASSEMBLE);
+                               continue;
+                       }
+                       break;
+               case 's':
+                       if (strcmp(argp, "-save-temps") == 0) {
+                               save_temps = 1;
+                               continue;
+                       }
+                       if (strcmp(argp, "-shared") == 0) {
+                               shared_mode = 1;
+                               continue;
+                       }
+                       if (strcmp(argp, "-static") == 0) {
+                               static_mode = 1;
+                               continue;
+                       }
+                       if (strncmp(argp, "-std=", 5) == 0)
+                               continue; /* XXX sanitize me */
+                       break;
+               case 't':
+                       if (argp[2] == '\0') {
+                               strlist_append(&preprocessor_flags, argp);
+                               continue;
+                       }
+               case 'U':
+                       strlist_append(&preprocessor_flags, argp);
+                       if (argp[2] == '\0') {
+                               if (argc == 0)
+                                       missing_argument(argp);
+                               --argc;
+                               ++argv;
+                               strlist_append(&preprocessor_flags, argp);
+                       }
+                       continue;
+               case 'v':
+                       if (argp[2] == '\0') {
+                               verbose_mode = 1;
+                               continue;
+                       }
+                       break;
+               case 'W':
+                       if (strncmp(argp, "-Wa,", 4) == 0) {
+                               split_and_append(&assembler_flags, argp + 4);
+                               continue;
+                       }
+                       if (strncmp(argp, "-Wl,", 4) == 0) {
+                               split_and_append(&middle_linker_flags, argp + 4);
+                               continue;
+                       }
+                       if (strncmp(argp, "-Wp,", 4) == 0) {
+                               split_and_append(&preprocessor_flags, argp + 4);
+                               continue;
+                       }
+                       /* XXX warning flags */
+                       break;
+               case 'x':
+                       /* XXX -x c */
+                       /* XXX -c assembler-with-cpp */
+                       break;
+               }
+               error("unknown flag `%s'", argp);
+       }
+
+       if (last_phase == DEFAULT)
+               last_phase = LINK;
+
+       if (verbose_mode)
+               printf("%s\n", versionstr);
+
+       if (isysroot == NULL)
+               isysroot = sysroot;
+       expand_sysroot();
+
+       if (last_phase != LINK && final_output && !STRLIST_EMPTY(&inputs) &&
+           !STRLIST_NEXT(STRLIST_FIRST(&inputs)))
+               error("-o specified with more than one input");
+
+       if (last_phase == PREPROCESS && final_output == NULL)
+               final_output = "-";
+
+       if (STRLIST_EMPTY(&inputs))
+               error("No input specificed");
+
+       retval = 0;
+
+       signal(SIGTERM, sigterm_handler);
+
+       STRLIST_FOREACH(input, &inputs) {
+               if (handle_input(input->value))
+                       retval = 1;
+       }
+       if (!retval && last_phase == LINK) {
+               if (run_linker())
+                       retval = 1;
+       }
+
+       if (exit_now)
+               warning("Received signal, terminating");
+
+       cleanup();
+
+       strlist_free(&crtdirs);
+       strlist_free(&user_sysincdirs);
+       strlist_free(&sysincdirs);
+       strlist_free(&incdirs);
+       strlist_free(&includes);
+       strlist_free(&libdirs);
+       strlist_free(&progdirs);
+       strlist_free(&inputs);
+       strlist_free(&preprocessor_flags);
+       strlist_free(&compiler_flags);
+       strlist_free(&assembler_flags);
+       strlist_free(&early_linker_flags);
+       strlist_free(&middle_linker_flags);
+       strlist_free(&late_linker_flags);
+       strlist_free(&stdlib_flags);
+       strlist_free(&early_program_csu_files);
+       strlist_free(&late_program_csu_files);
+       strlist_free(&early_dso_csu_files);
+       strlist_free(&late_dso_csu_files);
+       strlist_free(&temp_outputs);
+
+       return retval;
+}
diff --git a/lang/pcc/pcc/cc/driver/driver.h b/lang/pcc/pcc/cc/driver/driver.h
new file mode 100644 (file)
index 0000000..cf7ad49
--- /dev/null
@@ -0,0 +1,64 @@
+/*     $Id: driver.h,v 1.2 2011/05/26 16:48:40 plunky Exp $    */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#include "strlist.h"
+
+extern const char *isysroot;
+extern const char *sysroot;
+extern const char *preprocessor;
+extern const char *compiler;
+extern const char *assembler;
+extern const char *linker;
+
+extern struct strlist crtdirs;
+extern struct strlist sysincdirs;
+extern struct strlist libdirs;
+extern struct strlist progdirs;
+extern struct strlist preprocessor_flags;
+extern struct strlist compiler_flags;
+extern struct strlist assembler_flags;
+extern struct strlist early_linker_flags;
+extern struct strlist middle_linker_flags;
+extern struct strlist late_linker_flags;
+extern struct strlist stdlib_flags;
+extern struct strlist early_program_csu_files;
+extern struct strlist late_program_csu_files;
+extern struct strlist early_dso_csu_files;
+extern struct strlist late_dso_csu_files;
+
+void error(const char *fmt, ...);
+
+void init_platform_specific(const char *, const char *);
+
+#endif /* DRIVER_H */
diff --git a/lang/pcc/pcc/cc/driver/platform.c b/lang/pcc/pcc/cc/driver/platform.c
new file mode 100644 (file)
index 0000000..54aa253
--- /dev/null
@@ -0,0 +1,320 @@
+/*     $Id: platform.c,v 1.5 2012/08/09 11:41:28 ragge Exp $   */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "driver.h"
+#include "config.h"
+
+#include "ccconfig.h"
+
+#ifndef NEW_DRIVER_CFG
+#define        USE_OLD_DRIVER_CFG
+#endif
+
+#define _MKS(x)                #x
+#define MKS(x)         _MKS(x)
+
+#ifndef PREPROCESSOR
+#define PREPROCESSOR   "cpp"
+#endif
+
+#ifndef COMPILER
+#define COMPILER       "ccom"
+#endif
+
+#ifndef ASSEMBLER
+#define ASSEMBLER      "as"
+#endif
+
+#ifndef LINKER
+#define LINKER         "ld"
+#endif
+
+enum architecture {
+       ARCH_ANY,
+       ARCH_I386,
+       ARCH_X86_64
+};
+
+static const struct {
+       enum architecture arch;
+       const char *name;
+} arch_mapping[] = {
+#ifdef USE_OLD_DRIVER_CFG
+       { ARCH_ANY, TARGMACH },
+#else
+       { ARCH_I386, "i386" },
+       { ARCH_X86_64, "x86_64" } ,
+#endif
+};
+
+enum os {
+       OS_ANY,
+       OS_NETBSD,
+       OS_LINUX
+};
+
+static const struct {
+       enum os os;
+       const char *name;
+} os_mapping[] = {
+#ifdef USE_OLD_DRIVER_CFG
+       { OS_ANY, TARGOS },
+#else
+       { OS_NETBSD, "netbsd" },
+       { OS_LINUX, "linux" },
+#endif
+};
+
+struct platform_specific {
+       enum architecture arch;
+       enum os os;
+       const char * const *values;
+};
+
+#ifndef USE_OLD_DRIVER_CFG
+static const char * const early_program_csu_values0[] = { "crt0.o", NULL };
+static const char * const early_program_csu_values1[] = { "crt1.o", NULL };
+#else
+static const char * const early_program_csu_values2[] = {
+       CRT0FILE, NULL
+};
+#endif
+
+static const struct platform_specific early_program_csu[] = {
+#ifdef USE_OLD_DRIVER_CFG
+       { ARCH_ANY, OS_ANY, early_program_csu_values2 },
+#else
+       { ARCH_ANY, OS_NETBSD, early_program_csu_values0 },
+       { ARCH_ANY, OS_LINUX, early_program_csu_values1 },
+#endif
+};
+
+static const char * const late_program_csu_values0[] = {
+    "crtend.o", "crtn.o", NULL
+};
+static const struct platform_specific late_program_csu[] = {
+    { ARCH_ANY, OS_ANY, late_program_csu_values0 },
+};
+
+static const char * const early_dso_csu_values0[] = {
+    "crtio", "crtbeginS.o", NULL
+};
+static const struct platform_specific early_dso_csu[] = {
+    { ARCH_ANY, OS_ANY, early_dso_csu_values0 },
+};
+
+static const char * const late_dso_csu_values0[] = {
+    "crtendS.o", "crtn.o", NULL
+};
+static const struct platform_specific late_dso_csu[] = {
+    { ARCH_ANY, OS_ANY, late_dso_csu_values0 },
+};
+
+static const char * const predefined_macros_values0[] = {
+    "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", NULL
+};
+static const char * const predefined_macros_values1[] = {
+    "-D__NetBSD__", "-D__ELF__", NULL
+};
+static const char * const predefined_macros_values2[] = {
+    "-D__linux__", "-D__ELF__", NULL
+};
+static const char * const predefined_macros_values3[] = {
+    "-D__i386__", NULL
+};
+static const char * const predefined_macros_values4[] = {
+    "-D__PCC__=" MKS(PCC_MAJOR),
+    "-D__PCC_MINOR__=" MKS(PCC_MINOR),
+    "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR),
+    "-D__VERSION__=" MKS(VERSSTR),
+    "-D__STDC_ISO_10646__=200009L",
+    NULL
+};
+static const char * const predefined_macros_values5[] = {
+    "-D__GNUC__=4",
+    "-D__GNUC_MINOR__=3",
+    "-D__GNUC_PATCHLEVEL__=1",
+    "-D__GNUC_STDC_INLINE__=1",
+    NULL
+};
+static const struct platform_specific predefined_macros[] = {
+    { ARCH_X86_64, OS_ANY, predefined_macros_values0 },
+    { ARCH_ANY, OS_NETBSD, predefined_macros_values1 },
+    { ARCH_ANY, OS_LINUX, predefined_macros_values2 },
+    { ARCH_I386, OS_ANY, predefined_macros_values3 },
+    { ARCH_ANY, OS_ANY, predefined_macros_values4 },
+    { ARCH_ANY, OS_ANY, predefined_macros_values5 },
+};
+
+static const char * const early_linker_values0[] = {
+    "-dynamic-linker", "/libexec/ld.elf_so", NULL
+};
+static const char * const early_linker_values1[] = {
+    "-m", "elf_i386", NULL
+};
+static const char * const early_linker_values2[] = {
+    "-m", "elf_x86_64", NULL
+};
+static const char * const early_linker_values3[] = {
+    "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", NULL
+};
+static const char * const early_linker_values4[] = {
+    "-m", "elf_i386", NULL
+};
+static const char * const early_linker_values5[] = {
+    "-m", "elf_x86_64", NULL
+};
+static const struct platform_specific early_linker[] = {
+    { ARCH_ANY, OS_NETBSD, early_linker_values0 },
+    { ARCH_I386, OS_NETBSD, early_linker_values1 },
+    { ARCH_X86_64, OS_NETBSD, early_linker_values2 },
+    { ARCH_ANY, OS_LINUX, early_linker_values3 },
+    { ARCH_I386, OS_LINUX, early_linker_values4 },
+    { ARCH_X86_64, OS_LINUX, early_linker_values5 },
+};
+
+static const char * const sysincdir_list_values0[] = {
+    "=/usr/include", NULL
+};
+static const char * const sysincdir_list_values1[] = {
+    /* XXX fix up for libpcc? */
+    "=/usr/lib/gcc/x86_64-linux-gnu/4.4/include", NULL
+};
+static const struct platform_specific sysincdir_list[] = {
+    { ARCH_ANY, OS_ANY, sysincdir_list_values0 },
+    { ARCH_X86_64, OS_LINUX, sysincdir_list_values1 },
+};
+
+static const char * const crtdir_list_values0[] = {
+    "=/usr/lib/i386", "=/usr/lib", NULL
+};
+static const char * const crtdir_list_values1[] = {
+    "=/usr/lib", NULL
+};
+static const char * const crtdir_list_values2[] = {
+    "=/usr/lib64", "=/usr/lib/gcc/x86_64-linux-gnu/4.4", NULL
+};
+static const struct platform_specific crtdir_list[] = {
+    { ARCH_I386, OS_NETBSD, crtdir_list_values0 },
+    { ARCH_X86_64, OS_NETBSD, crtdir_list_values1 },
+    { ARCH_X86_64, OS_LINUX, crtdir_list_values2 },
+};
+
+static const char * const stdlib_list_values0[] = {
+    "-L/usr/lib/gcc/x86_64-linux-gnu/4.4", NULL
+};
+static const char * const stdlib_list_values1[] = {
+    "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed",
+    "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", NULL
+};
+static const struct platform_specific stdlib_list[] = {
+    { ARCH_X86_64, OS_LINUX, stdlib_list_values0 },
+    { ARCH_ANY, OS_ANY, stdlib_list_values1 },
+};
+
+static const char * const program_dirs_values0[] = {
+    LIBEXECDIR, NULL
+};
+static const struct platform_specific program_dirs[] = {
+    { ARCH_ANY, OS_ANY, program_dirs_values0 },
+};
+
+#define        ARRAYLEN(a)     (sizeof(a) / sizeof((a)[0]))
+#define        ARRAYPAIR(a)    a, ARRAYLEN(a)
+
+static const struct {
+       const struct platform_specific *initializer;
+       size_t len;
+       struct strlist *list;
+} platform_specific_inits[] = {
+    { ARRAYPAIR(early_program_csu), &early_program_csu_files },
+    { ARRAYPAIR(late_program_csu), &late_program_csu_files },
+    { ARRAYPAIR(early_dso_csu), &early_dso_csu_files },
+    { ARRAYPAIR(late_dso_csu), &late_dso_csu_files },
+    { ARRAYPAIR(predefined_macros), &preprocessor_flags },
+    { ARRAYPAIR(early_linker), &early_linker_flags },
+    { ARRAYPAIR(sysincdir_list), &sysincdirs },
+    { ARRAYPAIR(crtdir_list), &crtdirs },
+    { ARRAYPAIR(stdlib_list), &stdlib_flags },
+    { ARRAYPAIR(program_dirs), &progdirs },
+};
+
+void
+init_platform_specific(const char *os_name, const char *arch_name)
+{
+       enum os os;
+       enum architecture arch;
+       size_t i, j, len;
+       const struct platform_specific *initializer;
+       struct strlist *l;
+
+       os = OS_ANY;
+       for (i = 0; i < ARRAYLEN(os_mapping); ++i) {
+               if (strcmp(os_mapping[i].name, os_name) == 0) {
+                       os = os_mapping[i].os;
+                       break;
+               }
+       }
+       if (os == OS_ANY)
+               error("unknown Operating System: %s", os_name);
+
+       arch = ARCH_ANY;
+       for (i = 0; i < ARRAYLEN(arch_mapping); ++i) {
+               if (strcmp(arch_mapping[i].name, arch_name) == 0) {
+                       arch = arch_mapping[i].arch;
+                       break;
+               }
+       }
+       if (arch == ARCH_ANY)
+               error("unknown architecture: %s", arch_name);
+
+       for (i = 0; i < ARRAYLEN(platform_specific_inits); ++i) {
+               initializer = platform_specific_inits[i].initializer;
+               len = platform_specific_inits[i].len;
+               l = platform_specific_inits[i].list;
+               for (j = 0; j < len; ++j) {
+                       if (initializer[j].arch != arch &&
+                           initializer[j].arch != ARCH_ANY)
+                               continue;
+                       if (initializer[j].os != os &&
+                           initializer[j].os != OS_ANY)
+                               continue;
+                       strlist_append_array(l, initializer[j].values);
+               }
+       }
+
+       preprocessor = PREPROCESSOR;
+       compiler = COMPILER;
+       assembler = ASSEMBLER;
+       linker = LINKER;
+}
diff --git a/lang/pcc/pcc/cc/driver/strlist.c b/lang/pcc/pcc/cc/driver/strlist.c
new file mode 100644 (file)
index 0000000..dca468c
--- /dev/null
@@ -0,0 +1,193 @@
+/*     $Id: strlist.c,v 1.3 2014/12/24 09:55:32 plunky Exp $   */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include "strlist.h"
+#include "xalloc.h"
+
+void
+strlist_init(struct strlist *l)
+{
+       l->first = l->last = NULL;
+}
+
+void
+strlist_free(struct strlist *l)
+{
+       struct string *s1, *s2;
+
+       STRLIST_FOREACH_MUTABLE(s1, l, s2) {
+               free(s1->value);
+               free(s1);
+       }
+       l->first = l->last = NULL;
+}
+
+void
+strlist_make_array(const struct strlist *l, char ***a, size_t *len)
+{
+       const struct string *s;
+       char **i;
+
+       *len = 0;
+
+       STRLIST_FOREACH(s, l)
+               ++*len;
+
+       *a = xcalloc(*len + 1, sizeof(*i));
+       i = *a;
+
+       STRLIST_FOREACH(s, l)
+               *i++ = xstrdup(s->value);
+       *i = NULL;
+}
+
+void
+strlist_print(const struct strlist *l, FILE *f, int esc)
+{
+       const struct string *s;
+       int quote, first = 1;
+       const char *p;
+
+       STRLIST_FOREACH(s, l) {
+               if (!first)
+                       putc(' ', f);
+               quote = 0;
+               if (esc) {
+                       for (p = s->value; *p; p++) {
+                               if ((*p >= '0' && *p <= '9')
+                                   || (*p >= 'a' && *p <= 'z')
+                                   || (*p >= 'A' && *p <= 'Z')
+                                   || *p == '.' || *p == '/'
+                                   || *p == '-' || *p == '_')
+                                       continue;
+                               quote = 1;
+                               break;
+                       }
+               }
+               if (quote)
+                       putc('"', f);
+               for (p = s->value; *p; p++) {
+                       if (quote && (*p == '"' || *p == '$'
+                           || *p == '\\' || *p == '`'))
+                               putc('\\', f);
+                       putc(*p, f);
+               }
+               if (quote)
+                       putc('"', f);
+               first = 0;
+       }
+}
+
+void
+strlist_append_nocopy(struct strlist *l, char *val)
+{
+       struct string *s;
+
+       s = xmalloc(sizeof(*s));
+       s->next = NULL;
+       s->value = val;
+       if (l->last != NULL) {
+               l->last->next = s;
+               l->last = s;
+       } else {
+               l->last = s;
+               l->first = s;
+       }
+}
+
+void
+strlist_append(struct strlist *l, const char *val)
+{
+       strlist_append_nocopy(l, xstrdup(val));
+}
+
+void
+strlist_append_list(struct strlist *l, const struct strlist *l2)
+{
+       struct string *s;
+
+       STRLIST_FOREACH(s, l2)
+               strlist_append(l, s->value);
+}
+
+void
+strlist_append_array(struct strlist *l, const char * const *strings)
+{
+       for (; *strings != NULL; ++strings)
+               strlist_append(l, *strings);
+}
+
+void
+strlist_prepend_nocopy(struct strlist *l, char *val)
+{
+       struct string *s;
+
+       s = xmalloc(sizeof(*s));
+       s->next = l->first;
+       s->value = val;
+       l->first = s;
+       if (l->last == NULL) {
+               l->last = s;
+       }
+}
+
+void
+strlist_prepend(struct strlist *l, const char *val)
+{
+       strlist_prepend_nocopy(l, xstrdup(val));
+}
+
+void
+strlist_prepend_list(struct strlist *l, const struct strlist *l2)
+{
+       struct string *s, *s2, *s3, *s4;
+
+       if (STRLIST_EMPTY(l2))
+               return;
+
+       if (STRLIST_EMPTY(l)) {
+               strlist_append_list(l, l2);
+               return;
+       }
+
+       s2 = NULL;
+       s4 = l->first;
+       STRLIST_FOREACH(s, l2) {
+               s3 = xmalloc(sizeof(*s3));
+               s3->value = xstrdup(s->value);
+               s3->next = s4;
+               if (s2 == NULL)
+                       l->first = s3;
+               else
+                       s2->next = s3;
+       }
+}
diff --git a/lang/pcc/pcc/cc/driver/strlist.h b/lang/pcc/pcc/cc/driver/strlist.h
new file mode 100644 (file)
index 0000000..9a73dd4
--- /dev/null
@@ -0,0 +1,73 @@
+/*     $Id: strlist.h,v 1.3 2014/12/24 09:55:32 plunky Exp $   */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef STRLIST_H
+#define STRLIST_H
+
+#include <stddef.h>
+#include <stdio.h>
+
+struct string {
+       struct string *next;
+       char *value;
+};
+
+struct strlist {
+       struct string *first;
+       struct string *last;
+};
+
+void strlist_init(struct strlist *);
+void strlist_free(struct strlist *);
+void strlist_make_array(const struct strlist *, char ***, size_t *);
+void strlist_print(const struct strlist *, FILE *, int);
+
+void strlist_prepend(struct strlist *, const char *);
+void strlist_prepend_nocopy(struct strlist *, char *);
+void strlist_prepend_list(struct strlist *, const struct strlist *);
+void strlist_append(struct strlist *, const char *);
+void strlist_append_nocopy(struct strlist *, char *);
+void strlist_append_list(struct strlist *, const struct strlist *);
+void strlist_append_array(struct strlist *, const char * const *);
+
+#define        STRLIST_FIRST(head)     ((head)->first)
+#define        STRLIST_NEXT(elem)      ((elem)->next)
+#define        STRLIST_FOREACH(var, head) \
+       for ((var) = STRLIST_FIRST(head); \
+            (var) != NULL; \
+            (var) = STRLIST_NEXT(var))
+#define        STRLIST_FOREACH_MUTABLE(var, head, var2) \
+       for ((var) = STRLIST_FIRST(head); \
+            (var) != NULL && ((var2) = STRLIST_NEXT(var), 1); \
+            (var) = (var2))
+#define        STRLIST_EMPTY(head)     (STRLIST_FIRST(head) == NULL)
+
+#endif /* STRLIST_H */
diff --git a/lang/pcc/pcc/cc/driver/xalloc.c b/lang/pcc/pcc/cc/driver/xalloc.c
new file mode 100644 (file)
index 0000000..0ca4533
--- /dev/null
@@ -0,0 +1,83 @@
+/*     $Id: xalloc.c,v 1.2 2011/05/26 16:48:40 plunky Exp $    */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xalloc.h"
+
+static void
+error(const char *str)
+{
+       fprintf(stderr, "%s\n", str);
+       exit(1);
+}
+
+void *
+xcalloc(size_t elem, size_t len)
+{
+       void *ptr;
+
+       if ((ptr = calloc(elem, len)) == NULL)
+               error("calloc failed");
+       return ptr;
+}
+
+void *
+xmalloc(size_t len)
+{
+       void *ptr;
+
+       if ((ptr = malloc(len)) == NULL)
+               error("malloc failed");
+       return ptr;
+}
+
+void *
+xrealloc(void *buf, size_t len)
+{
+       void *ptr;
+
+       if ((ptr = realloc(buf, len)) == NULL)
+               error("realloc failed");
+       return ptr;
+}
+
+char *
+xstrdup(const char *str)
+{
+       char *buf;
+
+       if ((buf = strdup(str)) == NULL)
+               error("strdup failed");
+       return buf;
+}
diff --git a/lang/pcc/pcc/cc/driver/xalloc.h b/lang/pcc/pcc/cc/driver/xalloc.h
new file mode 100644 (file)
index 0000000..b90434d
--- /dev/null
@@ -0,0 +1,42 @@
+/*     $Id: xalloc.h,v 1.2 2011/05/26 16:48:40 plunky Exp $    */
+
+/*-
+ * Copyright (c) 2011 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef XALLOC_H
+#define XALLOC_H
+
+#include <stddef.h>
+
+void   *xcalloc(size_t, size_t);
+void   *xmalloc(size_t);
+void   *xrealloc(void *, size_t);
+char   *xstrdup(const char *);
+
+#endif /* XALLOC_H */
diff --git a/lang/pcc/pcc/common/compat.c b/lang/pcc/pcc/common/compat.c
new file mode 100644 (file)
index 0000000..e341ab3
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: compat.c,v 1.13 2015/07/24 08:26:05 ragge Exp $
+ */
+
+/*
+ * Copyright (c) 1987, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     $NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp $
+ */
+
+#include <string.h>
+
+#include "config.h"
+#include "compat.h"
+
+#ifndef HAVE_STRLCAT
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(initial dst) + strlen(src); if retval >= siz,
+ * truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return(dlen + strlen(s));
+       while (*s != '\0') {
+               if (n != 1) {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+
+       return(dlen + (s - src));       /* count does not include NUL */
+}
+#endif
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0) {
+               if (siz != 0)
+                       *d = '\0';      /* NUL-terminate dst */
+               while (*s++)
+                       ;
+       }
+
+       return(s - src - 1);    /* count does not include NUL */
+}
+#endif
+
+#ifndef HAVE_GETOPT
+char *optarg;
+int optind = 1;
+int
+getopt(int argc, char * const argv[], const char *args)
+{
+        int n;
+       int nlen = strlen(args);
+        char cmd;
+        char rv;
+
+        if (argv[optind] && *argv[optind] == '-') {
+                cmd = *(argv[optind] + 1);
+
+                for (n = 0; n < nlen; n++) {
+                        if (args[n] == ':')
+                               continue;
+                        if (args[n] == cmd) {
+                                rv = *(argv[optind] + 1);
+                                if (args[n+1] == ':') {
+                                       if (*(argv[optind] + 2) != '\0') {
+                                               optarg = argv[optind] + 2;
+                                               optind += 1;
+                                       } else {
+                                               optarg = argv[optind + 1];
+                                               optind += 2;
+                                       }
+                                        if (!optarg)
+                                                optarg="";
+                                        return rv;
+                                } else {
+                                        optarg = NULL;
+                                        optind += 1;
+                                        return rv;
+                                }
+                        }
+                }       
+        }
+
+        return -1;
+}
+#endif
+
+#if !defined(HAVE_MKSTEMP) && !defined(_WIN32)
+#include <fcntl.h>     /* open() */
+#include <unistd.h>    /* getpid() */
+
+int
+mkstemp(char *path)
+{
+       char *trv;
+       unsigned int pid;
+
+       /* To guarantee multiple calls generate unique names even if
+          the file is not created. 676 different possibilities with 7
+          or more X's, 26 with 6 or less. */
+       static char xtra[2] = "aa";
+       int xcnt = 0;
+
+       pid = getpid();
+
+       /* Move to end of path and count trailing X's. */
+       for (trv = path; *trv; ++trv)
+               if (*trv == 'X')
+                       xcnt++;
+               else
+                       xcnt = 0;
+
+       /* Use at least one from xtra.  Use 2 if more than 6 X's. */
+       if (*(trv - 1) == 'X')
+               *--trv = xtra[0];
+       if (xcnt > 6 && *(trv - 1) == 'X')
+               *--trv = xtra[1];
+
+       /* Set remaining X's to pid digits with 0's to the left. */
+       while (*--trv == 'X') {
+               *trv = (pid % 10) + '0';
+               pid /= 10;
+       }
+
+       /* update xtra for next call. */
+       if (xtra[0] != 'z')
+               xtra[0]++;
+       else {
+               xtra[0] = 'a';
+               if (xtra[1] != 'z')
+                       xtra[1]++;
+               else
+                       xtra[1] = 'a';
+       }
+
+       return open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
+}
+#endif
+
+#ifndef HAVE_FFS
+int
+ffs(int x) 
+{ 
+       int r = 1;
+       if (!x) return 0; 
+       if (!(x & 0xffff)) { x >>= 16; r += 16; }
+       if (!(x &   0xff)) { x >>= 8;  r += 8;  }
+       if (!(x &    0xf)) { x >>= 4;  r += 4;  }
+       if (!(x &      3)) { x >>= 2;  r += 2;  }
+       if (!(x &      1)) { x >>= 1;  r += 1;  }
+
+       return r; 
+}
+#endif
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+#include <ctype.h>     /* isdigit() */
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+
+static void 
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
+    int min, int max);
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
+    int min, int max, int flags);
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+    int min, int max, int flags);
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS     (1 << 0)
+#define DP_F_PLUS      (1 << 1)
+#define DP_F_SPACE     (1 << 2)
+#define DP_F_NUM       (1 << 3)
+#define DP_F_ZERO      (1 << 4)
+#define DP_F_UP        (1 << 5)
+#define DP_F_UNSIGNED  (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT     1
+#define DP_C_LONG      2
+#define DP_C_LDOUBLE   3
+#define DP_C_LONG_LONG 4
+
+#define char_to_int(p) (p - '0')
+#define abs_val(p) (p < 0 ? -p : p)
+
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+       char *strvalue, ch;
+       long value;
+       long double fvalue;
+       int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
+       size_t currlen = 0;
+  
+       ch = *format++;
+
+       while (state != DP_S_DONE) {
+               if ((ch == '\0') || (currlen >= maxlen)) 
+                       state = DP_S_DONE;
+
+               switch(state) {
+               case DP_S_DEFAULT:
+                       if (ch == '%') 
+                               state = DP_S_FLAGS;
+                       else 
+                               dopr_outch(buffer, &currlen, maxlen, ch);
+                       ch = *format++;
+                       break;
+               case DP_S_FLAGS:
+                       switch (ch) {
+                       case '-':
+                               flags |= DP_F_MINUS;
+                               ch = *format++;
+                               break;
+                       case '+':
+                               flags |= DP_F_PLUS;
+                               ch = *format++;
+                               break;
+                       case ' ':
+                               flags |= DP_F_SPACE;
+                               ch = *format++;
+                               break;
+                       case '#':
+                               flags |= DP_F_NUM;
+                               ch = *format++;
+                               break;
+                       case '0':
+                               flags |= DP_F_ZERO;
+                               ch = *format++;
+                               break;
+                       default:
+                               state = DP_S_MIN;
+                               break;
+                       }
+                       break;
+               case DP_S_MIN:
+                       if (isdigit((unsigned char)ch)) {
+                               min = 10 * min + char_to_int (ch);
+                               ch = *format++;
+                       } else if (ch == '*') {
+                               min = va_arg (args, int);
+                               ch = *format++;
+                               state = DP_S_DOT;
+                       } else 
+                               state = DP_S_DOT;
+                       break;
+               case DP_S_DOT:
+                       if (ch == '.') {
+                               state = DP_S_MAX;
+                               ch = *format++;
+                       } else 
+                               state = DP_S_MOD;
+                       break;
+               case DP_S_MAX:
+                       if (isdigit((unsigned char)ch)) {
+                               if (max < 0)
+                                       max = 0;
+                               max = 10 * max + char_to_int(ch);
+                               ch = *format++;
+                       } else if (ch == '*') {
+                               max = va_arg (args, int);
+                               ch = *format++;
+                               state = DP_S_MOD;
+                       } else 
+                               state = DP_S_MOD;
+                       break;
+               case DP_S_MOD:
+                       switch (ch) {
+                       case 'h':
+                               cflags = DP_C_SHORT;
+                               ch = *format++;
+                               break;
+                       case 'l':
+                               cflags = DP_C_LONG;
+                               ch = *format++;
+                               if (ch == 'l') {
+                                       cflags = DP_C_LONG_LONG;
+                                       ch = *format++;
+                               }
+                               break;
+                       case 'q':
+                               cflags = DP_C_LONG_LONG;
+                               ch = *format++;
+                               break;
+                       case 'L':
+                               cflags = DP_C_LDOUBLE;
+                               ch = *format++;
+                               break;
+                       default:
+                               break;
+                       }
+                       state = DP_S_CONV;
+                       break;
+               case DP_S_CONV:
+                       switch (ch) {
+                       case 'd':
+                       case 'i':
+                               if (cflags == DP_C_SHORT) 
+                                       value = va_arg(args, int);
+                               else if (cflags == DP_C_LONG)
+                                       value = va_arg(args, long int);
+                               else if (cflags == DP_C_LONG_LONG)
+                                       value = va_arg (args, long long);
+                               else
+                                       value = va_arg (args, int);
+                               fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+                               break;
+                       case 'o':
+                               flags |= DP_F_UNSIGNED;
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg(args, unsigned int);
+                               else if (cflags == DP_C_LONG)
+                                       value = va_arg(args, unsigned long int);
+                               else if (cflags == DP_C_LONG_LONG)
+                                       value = va_arg(args, unsigned long long);
+                               else
+                                       value = va_arg(args, unsigned int);
+                               fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+                               break;
+                       case 'u':
+                               flags |= DP_F_UNSIGNED;
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg(args, unsigned int);
+                               else if (cflags == DP_C_LONG)
+                                       value = va_arg(args, unsigned long int);
+                               else if (cflags == DP_C_LONG_LONG)
+                                       value = va_arg(args, unsigned long long);
+                               else
+                                       value = va_arg(args, unsigned int);
+                               fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+                               break;
+                       case 'X':
+                               flags |= DP_F_UP;
+                       case 'x':
+                               flags |= DP_F_UNSIGNED;
+                               if (cflags == DP_C_SHORT)
+                                       value = va_arg(args, unsigned int);
+                               else if (cflags == DP_C_LONG)
+                                       value = va_arg(args, unsigned long int);
+                               else if (cflags == DP_C_LONG_LONG)
+                                       value = va_arg(args, unsigned long long);
+                               else
+                                       value = va_arg(args, unsigned int);
+                               fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+                               break;
+                       case 'f':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg(args, long double);
+                               else
+                                       fvalue = va_arg(args, double);
+                               /* um, floating point? */
+                               fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+                               break;
+                       case 'E':
+                               flags |= DP_F_UP;
+                       case 'e':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg(args, long double);
+                               else
+                                       fvalue = va_arg(args, double);
+                               break;
+                       case 'G':
+                               flags |= DP_F_UP;
+                       case 'g':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg(args, long double);
+                               else
+                                       fvalue = va_arg(args, double);
+                               break;
+                       case 'c':
+                               dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+                               break;
+                       case 's':
+                               strvalue = va_arg(args, char *);
+                               if (max < 0) 
+                                       max = maxlen; /* ie, no max */
+                               fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+                               break;
+                       case 'p':
+                               strvalue = va_arg(args, void *);
+                               fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+                               break;
+                       case 'n':
+                               if (cflags == DP_C_SHORT) {
+                                       short int *num;
+                                       num = va_arg(args, short int *);
+                                       *num = currlen;
+                               } else if (cflags == DP_C_LONG) {
+                                       long int *num;
+                                       num = va_arg(args, long int *);
+                                       *num = currlen;
+                               } else if (cflags == DP_C_LONG_LONG) {
+                                       long long *num;
+                                       num = va_arg(args, long long *);
+                                       *num = currlen;
+                               } else {
+                                       int *num;
+                                       num = va_arg(args, int *);
+                                       *num = currlen;
+                               }
+                               break;
+                       case '%':
+                               dopr_outch(buffer, &currlen, maxlen, ch);
+                               break;
+                       case 'w': /* not supported yet, treat as next char */
+                               ch = *format++;
+                               break;
+                       default: /* Unknown, skip */
+                       break;
+                       }
+                       ch = *format++;
+                       state = DP_S_DEFAULT;
+                       flags = cflags = min = 0;
+                       max = -1;
+                       break;
+               case DP_S_DONE:
+                       break;
+               default: /* hmm? */
+                       break; /* some picky compilers need this */
+               }
+       }
+       if (currlen < maxlen - 1) 
+               buffer[currlen] = '\0';
+       else 
+               buffer[maxlen - 1] = '\0';
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max)
+{
+       int cnt = 0, padlen, strln;     /* amount to pad */
+  
+       if (value == 0) 
+               value = "<NULL>";
+
+       for (strln = 0; value[strln]; ++strln); /* strlen */
+       padlen = min - strln;
+       if (padlen < 0) 
+               padlen = 0;
+       if (flags & DP_F_MINUS) 
+               padlen = -padlen; /* Left Justify */
+
+       while ((padlen > 0) && (cnt < max)) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               --padlen;
+               ++cnt;
+       }
+       while (*value && (cnt < max)) {
+               dopr_outch(buffer, currlen, maxlen, *value++);
+               ++cnt;
+       }
+       while ((padlen < 0) && (cnt < max)) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               ++padlen;
+               ++cnt;
+       }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    long value, int base, int min, int max, int flags)
+{
+       unsigned long uvalue;
+       char convert[20];
+       int signvalue = 0, place = 0, caps = 0;
+       int spadlen = 0; /* amount to space pad */
+       int zpadlen = 0; /* amount to zero pad */
+
+#define PADMAX(x,y)    ((x) > (y) ? (x) : (y))
+
+       if (max < 0)
+               max = 0;
+
+       uvalue = value;
+
+       if (!(flags & DP_F_UNSIGNED)) {
+               if (value < 0) {
+                       signvalue = '-';
+                       uvalue = -value;
+               } else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+                       signvalue = '+';
+               else if (flags & DP_F_SPACE)
+                       signvalue = ' ';
+       }
+  
+       if (flags & DP_F_UP) 
+               caps = 1; /* Should characters be upper case? */
+       do {
+               convert[place++] =
+                   (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+                   [uvalue % (unsigned)base];
+               uvalue = (uvalue / (unsigned)base );
+       } while (uvalue && (place < 20));
+       if (place == 20) 
+               place--;
+       convert[place] = 0;
+
+       zpadlen = max - place;
+       spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0);
+       if (zpadlen < 0)
+               zpadlen = 0;
+       if (spadlen < 0)
+               spadlen = 0;
+       if (flags & DP_F_ZERO) {
+               zpadlen = PADMAX(zpadlen, spadlen);
+               spadlen = 0;
+       }
+       if (flags & DP_F_MINUS) 
+               spadlen = -spadlen; /* Left Justifty */
+
+       /* Spaces */
+       while (spadlen > 0) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               --spadlen;
+       }
+
+       /* Sign */
+       if (signvalue) 
+               dopr_outch(buffer, currlen, maxlen, signvalue);
+
+       /* Zeros */
+       if (zpadlen > 0) {
+               while (zpadlen > 0) {
+                       dopr_outch(buffer, currlen, maxlen, '0');
+                       --zpadlen;
+               }
+       }
+
+       /* Digits */
+       while (place > 0) 
+               dopr_outch(buffer, currlen, maxlen, convert[--place]);
+  
+       /* Left Justified spaces */
+       while (spadlen < 0) {
+               dopr_outch (buffer, currlen, maxlen, ' ');
+               ++spadlen;
+       }
+}
+
+static long double 
+ldpow10(int exp)
+{
+       long double result = 1;
+
+       while (exp) {
+               result *= 10;
+               exp--;
+       }
+  
+       return result;
+}
+
+static long 
+lroundl(long double value)
+{
+       long intpart = value;
+
+       value -= intpart;
+       if (value >= 0.5)
+               intpart++;
+
+       return intpart;
+}
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+      int min, int max, int flags)
+{
+       char iconvert[20], fconvert[20];
+       int signvalue = 0, iplace = 0, fplace = 0;
+       int padlen = 0; /* amount to pad */
+       int zpadlen = 0, caps = 0;
+       long intpart, fracpart;
+       long double ufvalue;
+  
+       /* 
+        * AIX manpage says the default is 0, but Solaris says the default
+        * is 6, and sprintf on AIX defaults to 6
+        */
+       if (max < 0)
+               max = 6;
+
+       ufvalue = abs_val(fvalue);
+
+       if (fvalue < 0)
+               signvalue = '-';
+       else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+               signvalue = '+';
+       else if (flags & DP_F_SPACE)
+               signvalue = ' ';
+
+       intpart = ufvalue;
+
+       /* 
+        * Sorry, we only support 9 digits past the decimal because of our 
+        * conversion method
+        */
+       if (max > 9)
+               max = 9;
+
+       /* We "cheat" by converting the fractional part to integer by
+        * multiplying by a factor of 10
+        */
+       fracpart = lroundl((ldpow10 (max)) * (ufvalue - intpart));
+
+       if (fracpart >= ldpow10 (max)) {
+               intpart++;
+               fracpart -= ldpow10 (max);
+       }
+
+       /* Convert integer part */
+       do {
+               iconvert[iplace++] =
+                   (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+                   [intpart % 10];
+               intpart = (intpart / 10);
+       } while(intpart && (iplace < 20));
+       if (iplace == 20) 
+               iplace--;
+       iconvert[iplace] = 0;
+
+       /* Convert fractional part */
+       do {
+               fconvert[fplace++] =
+                   (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+                   [fracpart % 10];
+               fracpart = (fracpart / 10);
+       } while(fracpart && (fplace < 20));
+       if (fplace == 20) 
+               fplace--;
+       fconvert[fplace] = 0;
+
+       /* -1 for decimal point, another -1 if we are printing a sign */
+       padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+       zpadlen = max - fplace;
+       if (zpadlen < 0)
+               zpadlen = 0;
+       if (padlen < 0) 
+               padlen = 0;
+       if (flags & DP_F_MINUS) 
+               padlen = -padlen; /* Left Justifty */
+
+       if ((flags & DP_F_ZERO) && (padlen > 0)) {
+               if (signvalue) {
+                       dopr_outch(buffer, currlen, maxlen, signvalue);
+                       --padlen;
+                       signvalue = 0;
+               }
+               while (padlen > 0) {
+                       dopr_outch(buffer, currlen, maxlen, '0');
+                       --padlen;
+               }
+       }
+       while (padlen > 0) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               --padlen;
+       }
+       if (signvalue) 
+               dopr_outch(buffer, currlen, maxlen, signvalue);
+
+       while (iplace > 0) 
+               dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+       /*
+        * Decimal point.  This should probably use locale to find the 
+        * correct char to print out.
+        */
+       dopr_outch(buffer, currlen, maxlen, '.');
+
+       while (fplace > 0) 
+               dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+
+       while (zpadlen > 0) {
+               dopr_outch(buffer, currlen, maxlen, '0');
+               --zpadlen;
+       }
+
+       while (padlen < 0) {
+               dopr_outch(buffer, currlen, maxlen, ' ');
+               ++padlen;
+       }
+}
+
+static void 
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+       if (*currlen < maxlen)
+               buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int 
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+       str[0] = 0;
+       dopr(str, count, fmt, args);
+
+       return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int 
+snprintf(char *str,size_t count,const char *fmt,...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       (void) vsnprintf(str, count, fmt, ap);
+       va_end(ap);
+
+       return(strlen(str));
+}
+
+#endif /* !HAVE_SNPRINTF */
diff --git a/lang/pcc/pcc/common/compat.h b/lang/pcc/pcc/common/compat.h
new file mode 100644 (file)
index 0000000..c5330a8
--- /dev/null
@@ -0,0 +1,46 @@
+/*     $Id: compat.h,v 1.6 2015/07/24 08:26:05 ragge Exp $     */
+
+/*
+ * Just compatibility function prototypes.
+ * Public domain.
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#ifndef HAVE_STRLCPY
+#include <stddef.h>    /* size_t */
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_STRLCAT
+#include <stddef.h>    /* size_t */
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_GETOPT
+extern char *optarg;
+extern int optind;
+int getopt(int, char * const [], const char *);
+#endif
+
+#ifndef HAVE_MKSTEMP
+int mkstemp(char *);
+#endif
+
+#ifndef HAVE_FFS
+int ffs(int);
+#endif
+
+#ifndef HAVE_SNPRINTF
+#include <stddef.h>    /* size_t */
+int snprintf(char *str, size_t count, const char *fmt, ...);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+#include <stddef.h>    /* size_t */
+#include <stdarg.h>    /* va_list */
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+#endif
+
+#endif
diff --git a/lang/pcc/pcc/common/softfloat.h b/lang/pcc/pcc/common/softfloat.h
new file mode 100644 (file)
index 0000000..7bfe7f4
--- /dev/null
@@ -0,0 +1,139 @@
+/*     $Id: softfloat.h,v 1.3 2016/03/05 15:31:25 ragge Exp $  */
+
+/*
+ * Copyright (c) 2015 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Definitions for softfloat routines.
+ */
+
+
+typedef struct softfloat {
+       unsigned long long significand;
+       short exponent;
+       short kind;
+} SF;
+typedef SF *SFP;
+
+#define C(x,y) C2(x,y)
+#define C2(x,y) x##y
+
+#ifdef USE_IEEEFP_32
+#define        IEEEFP_32_RADIX 2
+#define IEEEFP_32_DIG 6
+#define IEEEFP_32_EPSILON 1.19209290E-07F
+#define IEEEFP_32_MAX_10_EXP +38
+#define IEEEFP_32_MAX_EXP +128
+#define IEEEFP_32_MAX 3.40282347E+38F
+#define IEEEFP_32_MIN_10_EXP -37
+#define IEEEFP_32_MIN_EXP -125
+#define IEEEFP_32_MIN 1.17549435E-38F
+#define IEEEFP_32_MANT_DIG 24
+#define IEEEFP_32_DECIMAL_DIG 9
+
+#define IEEEFP_32_TRUE_MIN 1.40129846E-45F
+#define IEEEFP_32_HAS_SUBNORM 1
+#endif
+#ifdef IEEEFP_64
+#endif
+#ifdef IEEEFP_X80
+#endif
+#ifdef IEEEFP_128
+#endif
+
+#define        TARGET_FLT_RADIX        C(FLT_FP,_RADIX)
+
+#ifndef NATIVE_FLOATING_POINT
+
+/*
+ * Description of a floating point format, based what is in gdtoa package.
+ * The first members are the same as in gdtoa,  the rest are pcc specific.
+ */
+typedef struct FPI {
+       int nbits;
+       int emin;
+       int emax;
+       int rounding;
+
+       int sudden_underflow:1;
+       int explicit_one:1; /* if MSB is explicitely stored */
+       int has_inf_nan:1;  /* highest exponent means INF and NaN */
+       int has_neg_zero:1;
+       int has_radix_16:1;
+       int storage;
+       int exp_bias;
+} FPI;
+
+/* SF.kind values; same as STRTODG_* values */
+enum {
+       SF_Zero         = 0,
+       SF_Normal       = 1,
+       SF_Denormal     = 2,
+       SF_Infinite     = 3,
+       SF_NaN          = 4, /* default quiet NaN */
+       SF_NaNbits      = 5, /* (not used) */
+       SF_NoNumber     = 6, /* signaling NaN */
+       SF_kmask        = 7,
+
+       /* The following may be or-ed into one of the above values. */
+       SF_Neg          = 0x80, /* does not affect SFEXCP_Inex(lo|hi) */
+       SFEXCP_Inexlo   = 0x100, /* returned result rounded toward zero */
+       SFEXCP_Inexhi   = 0x200, /* returned result rounded away from zero */
+       SFEXCP_Inexact  = 0x300,
+       SFEXCP_Underflow= 0x400,
+       SFEXCP_Overflow = 0x800,
+       SFEXCP_DivByZero= 0x1000,
+       SFEXCP_Invalid  = 0x2000,
+
+       SFEXCP_Aborted  = 0x8000, /* Not IEEE; operation not performed */
+       SFEXCP_ALLmask  = 0xFF00 /* All exceptions (mask) */
+};
+
+/* FPI.rounding values: same as FLT_ROUNDS */
+enum {
+       FPI_Round_zero = 0,     /* same meaning as FE_TOWARDZERO */
+       FPI_Round_near = 1,     /* same meaning as FE_TONEAREST */
+       FPI_Round_up = 2,       /* same meaning as FE_UPWARD */
+       FPI_Round_down = 3,     /* same meaning as FE_DOWNWARD */
+/* Warning: if adding new modes, keep same meaning for 2 low bits. */
+       FPI_Round_near_from0 = 5, /* to nearest but ties up (Vax) */
+
+       FPI_RoundNotSet = -4,   /* to implement dynamic rounding */
+};
+
+extern FPI * fpis[3]; /* FLOAT, DOUBLE, LDOUBLE, respectively */
+
+SF soft_neg(SF);
+SF soft_int2fp(CONSZ p, TWORD v);
+CONSZ soft_fp2int(SF p, TWORD v);
+SF soft_fp2fp(SF p, TWORD v);
+SFP soft_cast(CONSZ v, TWORD);
+SF soft_plus(SF, SF);
+SF soft_minus(SF, SF);
+SF soft_mul(SF, SF);
+SF soft_div(SF, SF);
+int soft_cmp(SF, SF, int);
+int soft_isz(SF);
+SF strtosf(char *);
+#endif
diff --git a/lang/pcc/pcc/common/unicode.c b/lang/pcc/pcc/common/unicode.c
new file mode 100644 (file)
index 0000000..bf8b138
--- /dev/null
@@ -0,0 +1,115 @@
+/*     $Id: unicode.c,v 1.9 2015/07/19 13:20:37 ragge Exp $    */
+/*
+ * Copyright (c) 2014 Eric Olson <ejolson@renomath.org>
+ * Some rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "pass1.h"
+#include "manifest.h"
+#include "unicode.h"
+
+/*
+ * decode 32-bit code point from UTF-8
+ * move pointer
+ */
+long 
+u82cp(char **q)
+{
+       unsigned char *t = (unsigned char *)*q;
+       unsigned long c, r;
+       int i, sz;
+
+       if (*t == '\\')
+               c = esccon((char **)&t);
+       else
+               c = *t++;
+
+       /* always eat the first value */
+       *q = (char *)t;
+
+       if (c > 0x7F) {
+               if ((c & 0xE0) == 0xC0) {
+                       sz = 2;
+                       r = c & 0x1F;
+               } else if ((c & 0xF0) == 0xE0) {
+                       sz = 3;
+                       r = c & 0x0F;
+               } else if ((c & 0xF8) == 0xF0) {
+                       sz = 4;
+                       r = c & 0x07;
+               } else if ((c & 0xFC) == 0xF8) {
+                       sz = 5;
+                       r = c & 0x03;
+               } else if ((c & 0xFE) == 0xFC) {
+                       sz = 6;
+                       r = c & 0x01;
+               } else {
+                       u8error("invalid utf-8 prefix");
+                       return 0xFFFFUL;
+               }
+
+               for (i = 1; i < sz; i++) {
+                       if (*t == '\\')
+                               c = esccon((char **)&t);
+                       else
+                               c = *t++;
+
+                       if ((c & 0xC0) == 0x80) {
+                               r = (r << 6) + (c & 0x3F);
+                       } else {
+                               u8error("utf-8 encoding %d bytes too short", sz - i);
+                               return 0xFFFFUL;
+                       }
+               }
+
+               *q = (char *)t;
+       } else {
+               r = c;
+       }
+
+       return r;
+}
+
+/*
+ * Create UTF-16 from unicode number.
+ * Expects s to point to two words.
+ */
+void
+cp2u16(long num, unsigned short *s)
+{
+       s[0] = s[1] = 0;
+       if (num <= 0xd7ff || (num >= 0xe000 && num <= 0xffffL)) {
+               *s = num;
+       } else if (num >= 0x010000L && num <= 0x10ffffL) {
+               num -= 0x010000L;
+               s[0] = ((num >> 10) + 0xd800);
+               s[1] = ((num & 0x3ff) + 0xdc00);
+       } else if (num > 0x10ffffL)
+               werror("illegal UTF-16 value");
+}
diff --git a/lang/pcc/pcc/common/unicode.h b/lang/pcc/pcc/common/unicode.h
new file mode 100644 (file)
index 0000000..42736d7
--- /dev/null
@@ -0,0 +1,10 @@
+/*     $Id: unicode.h,v 1.5 2015/07/19 13:20:37 ragge Exp $    */
+
+#ifndef _UNICODE_H
+#define _UNICODE_H
+
+extern long u82cp(char **q);
+extern void u8error(const char *fmt, ...);
+extern void cp2u16(long num, unsigned short *s);
+
+#endif
diff --git a/lang/pcc/pcc/config.guess b/lang/pcc/pcc/config.guess
new file mode 100644 (file)
index 0000000..7bdfbf6
--- /dev/null
@@ -0,0 +1,1421 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-11-04'
+
+# 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+       # If the system lacks a compiler, then just pick glibc.
+       # We could probably try harder.
+       LIBC=gnu
+
+       eval $set_cc_for_build
+       cat <<-EOF > $dummy.c
+       #include <features.h>
+       #if defined(__UCLIBC__)
+       LIBC=uclibc
+       #elif defined(__dietlibc__)
+       LIBC=dietlibc
+       #else
+       LIBC=gnu
+       #endif
+       EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+       ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           sh5el) machine=sh5le-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep -q __ELF__
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit ;;
+    *:Bitrig:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+       exit ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    *:SolidBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+       exitcode=$?
+       trap '' 0
+       exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+       echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    s390x:SunOS:*:*)
+       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+       eval $set_cc_for_build
+       SUN_ARCH="i386"
+       # If there is a compiler, see if it is configured for 64-bit objects.
+       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+       # This test works for both compilers.
+       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               SUN_ARCH="x86_64"
+           fi
+       fi
+       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+       echo m68k-milan-mint${UNAME_RELEASE}
+       exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+       echo m68k-hades-mint${UNAME_RELEASE}
+       exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+       echo m68k-unknown-mint${UNAME_RELEASE}
+       exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c &&
+         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`$dummy $dummyarg` &&
+           { echo "$SYSTEM_NAME"; exit; }
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit ;;
+    AViiON:dgux:*:*)
+       # DG/UX returns AViiON for all architectures
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${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 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+               then
+                       echo "$SYSTEM_NAME"
+               else
+                       echo rs6000-ibm-aix3.2.5
+               fi
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit ;;
+    *:AIX:*:[4567])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/lslpp ] ; then
+               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                   sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                   case "${sc_cpu_version}" in
+                     523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                     528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                     532)                      # CPU_PA_RISC2_0
+                       case "${sc_kernel_bits}" in
+                         32) HP_ARCH="hppa2.0n" ;;
+                         64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                       esac ;;
+                   esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^            //' << EOF >$dummy.c
+
+               #define _HPUX_SOURCE
+               #include <stdlib.h>
+               #include <unistd.h>
+
+               int main ()
+               {
+               #if defined(_SC_KERNEL_BITS)
+                   long bits = sysconf(_SC_KERNEL_BITS);
+               #endif
+                   long cpu  = sysconf (_SC_CPU_VERSION);
+
+                   switch (cpu)
+                       {
+                       case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+                       case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+                       case CPU_PA_RISC2_0:
+               #if defined(_SC_KERNEL_BITS)
+                           switch (bits)
+                               {
+                               case 64: puts ("hppa2.0w"); break;
+                               case 32: puts ("hppa2.0n"); break;
+                               default: puts ("hppa2.0"); break;
+                               } break;
+               #else  /* !defined(_SC_KERNEL_BITS) */
+                           puts ("hppa2.0"); break;
+               #endif
+                       default: puts ("hppa1.0"); break;
+                       }
+                   exit (0);
+               }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           eval $set_cc_for_build
+
+           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+           # generating 64-bit code.  GNU and HP use different nomenclature:
+           #
+           # $ CC_FOR_BUILD=cc ./config.guess
+           # => hppa2.0w-hp-hpux11.23
+           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+           # => hppa64-hp-hpux11.23
+
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+               grep -q __LP64__
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+               { echo "$SYSTEM_NAME"; exit; }
+       echo unknown-hitachi-hiuxwe2
+       exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+       exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+       exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+       exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+       exit ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    5000:UNIX_System_V:4.*:*)
+       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:FreeBSD:*:*)
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       case ${UNAME_PROCESSOR} in
+           amd64)
+               echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           *)
+               echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+       esac
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    *:MINGW64*:*)
+       echo ${UNAME_MACHINE}-pc-mingw64
+       exit ;;
+    *:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    *:MSYS*:*)
+       echo ${UNAME_MACHINE}-pc-msys
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    *:Interix*:*)
+       case ${UNAME_MACHINE} in
+           x86)
+               echo i586-pc-interix${UNAME_RELEASE}
+               exit ;;
+           authenticamd | genuineintel | EM64T)
+               echo x86_64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+           IA64)
+               echo ia64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+       esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix${UNAME_RELEASE}
+       exit ;;
+    aarch64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    aarch64_be:Linux:*:*)
+       UNAME_MACHINE=aarch64_be
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+       esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    arm*:Linux:*:*)
+       eval $set_cc_for_build
+       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_EABI__
+       then
+           echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       else
+           if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+               | grep -q __ARM_PCS_VFP
+           then
+               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+           else
+               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+           fi
+       fi
+       exit ;;
+    avr32*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    cris:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+       exit ;;
+    crisv32:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+       exit ;;
+    frv:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    hexagon:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    i*86:Linux:*:*)
+       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=${UNAME_MACHINE}el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=${UNAME_MACHINE}
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+       ;;
+    openrisc*:Linux:*:*)
+       echo or1k-unknown-linux-${LIBC}
+       exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    padre:Linux:*:*)
+       echo sparc-unknown-linux-${LIBC}
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-${LIBC}
+       exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+         PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+         *)    echo hppa-unknown-linux-${LIBC} ;;
+       esac
+       exit ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-${LIBC}
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-${LIBC}
+       exit ;;
+    ppc64le:Linux:*:*)
+       echo powerpc64le-unknown-linux-${LIBC}
+       exit ;;
+    ppcle:Linux:*:*)
+       echo powerpcle-unknown-linux-${LIBC}
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    tile*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+       exit ;;
+    x86_64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    xtensa*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
+    i*86:DYNIX/ptx:4*:*)
+       # 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.
+       echo i386-sequent-sysv4
+       exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+       # Unixware is an offshoot of SVR4, but it has its own version
+       # number series starting with 2...
+       # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+       # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+       # uname -m prints for DJGPP always 'pc', but it prints nothing about
+       # the processor, so we play safe by assuming i586.
+       # Note: whatever this is, it MUST be the same as what config.sub
+       # prints for the "djgpp" host, or else GDB configury will decide that
+       # this is a cross-build.
+       echo i586-pc-msdosdjgpp
+       exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+       OS_REL='.3'
+       test -r /etc/.relid \
+           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+           && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit ;;
+    PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                       # says <Richard.M.Bartel@ccMail.Census.GOV>
+       echo i586-unisys-sysv4
+       exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit ;;
+    i*86:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo ${UNAME_MACHINE}-stratus-vos
+       exit ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+       exit ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit ;;
+    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
+       echo i586-pc-haiku
+       exit ;;
+    x86_64:Haiku:*:*)
+       echo x86_64-unknown-haiku
+       exit ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-7:SUPER-UX:*:*)
+       echo sx7-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8:SUPER-UX:*:*)
+       echo sx8-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8R:SUPER-UX:*:*)
+       echo sx8r-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       eval $set_cc_for_build
+       if test "$UNAME_PROCESSOR" = unknown ; then
+           UNAME_PROCESSOR=powerpc
+       fi
+       if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+           if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+               if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                   (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                   grep IS_64BIT_ARCH >/dev/null
+               then
+                   case $UNAME_PROCESSOR in
+                       i386) UNAME_PROCESSOR=x86_64 ;;
+                       powerpc) UNAME_PROCESSOR=powerpc64 ;;
+                   esac
+               fi
+           fi
+       elif test "$UNAME_PROCESSOR" = i386 ; then
+           # Avoid executing cc on OS X 10.9, as it ships with a stub
+           # that puts up a graphical alert prompting to install
+           # developer tools.  Any system running Mac OS X 10.7 or
+           # later (Darwin 11 and later) is required to have a 64-bit
+           # processor. This is not true of the ARM version of Darwin
+           # that Apple uses in portable devices.
+           UNAME_PROCESSOR=x86_64
+       fi
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+       echo neo-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+       echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+    i*86:AROS:*:*)
+       echo ${UNAME_MACHINE}-pc-aros
+       exit ;;
+    x86_64:VMkernel:*:*)
+       echo ${UNAME_MACHINE}-unknown-esx
+       exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/lang/pcc/pcc/config.h.in b/lang/pcc/pcc/config.h.in
new file mode 100644 (file)
index 0000000..14a1fef
--- /dev/null
@@ -0,0 +1,188 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Using a.out ABI */
+#undef AOUTABI
+
+/* Define path to alternate assembler */
+#undef ASSEMBLER
+
+/* Using Classic 68k ABI */
+#undef CLASSIC68K
+
+/* Using COFF ABI */
+#undef COFFABI
+
+/* Define path to alternate compiler */
+#undef COMPILER
+
+/* Using ECOFF ABI */
+#undef ECOFFABI
+
+/* Using ELF ABI */
+#undef ELFABI
+
+/* Define to 1 if printf supports C99 size specifiers */
+#undef HAVE_C99_FORMAT
+
+/* Define to 1 if you have the `ffs' function. */
+#undef HAVE_FFS
+
+/* Define to 1 if you have the `getopt' function. */
+#undef HAVE_GETOPT
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strtold' function. */
+#undef HAVE_STRTOLD
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if host is BIG endian */
+#undef HOST_BIG_ENDIAN
+
+/* Define if host is LITTLE endian */
+#undef HOST_LITTLE_ENDIAN
+
+/* Define alternate standard lib directory */
+#undef LIBDIR
+
+/* Define path to alternate linker */
+#undef LINKER
+
+/* Using Mach-O ABI */
+#undef MACHOABI
+
+/* Define target Multi-Arch path */
+#undef MULTIARCH_PATH
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Major version no */
+#undef PCC_MAJOR
+
+/* Minor version no */
+#undef PCC_MINOR
+
+/* Minor minor version no */
+#undef PCC_MINORMINOR
+
+/* Using PE/COFF ABI */
+#undef PECOFFABI
+
+/* Define path to alternate preprocessor */
+#undef PREPROCESSOR
+
+/* Enable STABS debugging output */
+#undef STABS
+
+/* Enable DWARF debugging output */
+#undef DWARF
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define alternate standard include directory */
+#undef STDINC
+
+/* Define if target defaults to BIG endian */
+#undef TARGET_BIG_ENDIAN
+
+/* Define if target defaults to LITTLE endian */
+#undef TARGET_LITTLE_ENDIAN
+
+/* Enable thread-local storage (TLS). */
+#undef TLS
+
+/* Version string */
+#undef VERSSTR
+
+/* Size of wide-character type in chars */
+#undef WCHAR_SIZE
+
+/* Type to use for wide characters */
+#undef WCHAR_TYPE
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
diff --git a/lang/pcc/pcc/config.sub b/lang/pcc/pcc/config.sub
new file mode 100644 (file)
index 0000000..e7cd3f5
--- /dev/null
@@ -0,0 +1,1813 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2015 Free Software Foundation, Inc.
+
+timestamp='2015-08-20'
+
+# 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2015 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis | -knuth | -cray | -microblaze*)
+               os=
+               basic_machine=$1
+               ;;
+       -bluegene*)
+               os=-cnk
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*178)
+               os=-lynxos178
+               ;;
+       -lynx*5)
+               os=-lynxos5
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+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.
+       1750a | 580 \
+       | a29k \
+       | aarch64 | aarch64_be \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arceb \
+       | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+       | avr | avr32 \
+       | ba \
+       | be32 | be64 \
+       | bfin \
+       | c4x | c8051 | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | e2k | epiphany \
+       | fido | fr30 | frv | ft32 \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | hexagon \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | k1om \
+       | le32 | le64 \
+       | lm32 \
+       | m16c | m32c | m32r | m32rle | m68000 | m68k | m88k \
+       | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64octeon | mips64octeonel \
+       | mips64orion | mips64orionel \
+       | mips64r5900 | mips64r5900el \
+       | mips64vr | mips64vrel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa32r6 | mipsisa32r6el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64r6 | mipsisa64r6el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipsr5900 | mipsr5900el \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | moxie \
+       | mt \
+       | msp430 \
+       | nds32 | nds32le | nds32be \
+       | nios | nios2 | nios2eb | nios2el \
+       | nova | ns16k | ns32k \
+       | open8 | or1k | or1knd | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle \
+       | pyramid \
+       | riscv32 | riscv64 \
+       | rl78 | rx \
+       | score \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu \
+       | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+       | ubicom32 \
+       | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+       | visium \
+       | we32k \
+       | x86 | xc16x | xstormy16 | xtensa \
+       | z8k | z80)
+               basic_machine=$basic_machine-unknown
+               ;;
+       c54x)
+               basic_machine=tic54x-unknown
+               ;;
+       c55x)
+               basic_machine=tic55x-unknown
+               ;;
+       c6x)
+               basic_machine=tic6x-unknown
+               ;;
+       leon|leon[3-9])
+               basic_machine=sparc-$basic_machine
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       strongarm | thumb | xscale)
+               basic_machine=arm-unknown
+               ;;
+       xgate)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       xscaleeb)
+               basic_machine=armeb-unknown
+               ;;
+
+       xscaleel)
+               basic_machine=armel-unknown
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | aarch64-* | aarch64_be-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* | avr32-* \
+       | ba-* \
+       | be32-* | be64-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* \
+       | c8051-* | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | e2k-* | elxsi-* \
+       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | hexagon-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | k1om-* \
+       | le32-* | le64-* \
+       | lm32-* \
+       | m16c-* | m32c-* | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+       | microblaze-* | microblazeel-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64octeon-* | mips64octeonel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64r5900-* | mips64r5900el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa32r6-* | mipsisa32r6el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64r6-* | mipsisa64r6el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipsr5900-* | mipsr5900el-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | nds32-* | nds32le-* | nds32be-* \
+       | nios-* | nios2-* | nios2eb-* | nios2el-* \
+       | none-* | nova-* | np1-* | ns16k-* | ns32k-* \
+       | open8-* \
+       | or1k*-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+       | pyramid-* \
+       | riscv32-* | riscv64-* \
+       | rl78-* | romp-* | rs6000-* | rx-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+       | tahoe-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tile*-* \
+       | tron-* \
+       | ubicom32-* \
+       | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+       | vax-* \
+       | visium-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xc16x-* | xps100-* \
+       | xstormy16-* | xtensa*-* \
+       | ymp-* \
+       | z8k-* | z80-*)
+               ;;
+       # Recognize the basic CPU types without company name, with glob match.
+       xtensa*)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               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)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aros)
+               basic_machine=i386-pc
+               os=-aros
+               ;;
+        asmjs)
+               basic_machine=asmjs-unknown
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       blackfin)
+               basic_machine=bfin-unknown
+               os=-linux
+               ;;
+       blackfin-*)
+               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
+       c54x-*)
+               basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c55x-*)
+               basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c6x-*)
+               basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       cegcc)
+               basic_machine=arm-unknown
+               os=-cegcc
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16 | cr16-*)
+               basic_machine=cr16-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dicos)
+               basic_machine=i686-pc
+               os=-dicos
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       leon-*|leon[3-9]-*)
+               basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+               ;;
+       m68knommu)
+               basic_machine=m68k-unknown
+               os=-linux
+               ;;
+       m68knommu-*)
+               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       microblaze*)
+               basic_machine=microblaze-xilinx
+               ;;
+       mingw64)
+               basic_machine=x86_64-pc
+               os=-mingw64
+               ;;
+       mingw32)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       mingw32ce)
+               basic_machine=arm-unknown
+               os=-mingw32ce
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       moxiebox)
+               basic_machine=moxie-unknown
+               os=-moxiebox
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       msys)
+               basic_machine=i686-pc
+               os=-msys
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       nacl)
+               basic_machine=le32-unknown
+               os=-nacl
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       neo-tandem)
+               basic_machine=neo-tandem
+               ;;
+       nse-tandem)
+               basic_machine=nse-tandem
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       parisc)
+               basic_machine=hppa-unknown
+               os=-linux
+               ;;
+       parisc-*)
+               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc | ppcbe)    basic_machine=powerpc-unknown
+               ;;
+       ppc-* | ppcbe-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos | rdos64)
+               basic_machine=x86_64-pc
+               os=-rdos
+               ;;
+       rdos32)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sde)
+               basic_machine=mipsisa32-sde
+               os=-elf
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh5el)
+               basic_machine=sh5le-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       strongarm-* | thumb-*)
+               basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tile*)
+               basic_machine=$basic_machine-unknown
+               os=-linux-gnu
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       xscale-* | xscalee[bl]-*)
+               basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       z80-*-coff)
+               basic_machine=z80-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# 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)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+       # First match some system type aliases
+       # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -auroraux)
+               os=-auroraux
+               ;;
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # 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* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* | -plan9* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* | -aros* | -cloudabi* | -sortix* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+             | -bitrig* | -openbsd* | -solidbsd* | -litebsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* | -cegcc* \
+             | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+             | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -tpf*)
+               os=-tpf
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -dicos*)
+               os=-dicos
+               ;;
+       -nacl*)
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       score-*)
+               os=-elf
+               ;;
+       spu-*)
+               os=-elf
+               ;;
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       c8051-*)
+               os=-elf
+               ;;
+       hexagon-*)
+               os=-elf
+               ;;
+       tic54x-*)
+               os=-coff
+               ;;
+       tic55x-*)
+               os=-coff
+               ;;
+       tic6x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mep-*)
+               os=-elf
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -cnk*|-aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/lang/pcc/pcc/configure b/lang/pcc/pcc/configure
new file mode 100755 (executable)
index 0000000..d40b18a
--- /dev/null
@@ -0,0 +1,6506 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for Portable C Compiler 1.2.0.DEVEL.
+#
+# Report bugs to <pcc@lists.ludd.ltu.se>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: pcc@lists.ludd.ltu.se about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='Portable C Compiler'
+PACKAGE_TARNAME='pcc'
+PACKAGE_VERSION='1.2.0.DEVEL'
+PACKAGE_STRING='Portable C Compiler 1.2.0.DEVEL'
+PACKAGE_BUGREPORT='pcc@lists.ludd.ltu.se'
+PACKAGE_URL='http://pcc.ludd.ltu.se/'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+CF1
+CF0
+CCNAMES
+ADD_CPPFLAGS
+ADD_CFLAGS
+hostos
+targmach
+targosver
+targos
+ALLOCA
+LEXLIB
+LEX_OUTPUT_ROOT
+LEX
+YFLAGS
+YACC
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+SET_MAKE
+EGREP
+GREP
+CPP
+CC_FOR_BUILD
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+BINPREFIX
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_multiarch
+with_incdir
+with_libdir
+with_assembler
+with_linker
+enable_tls
+enable_Werror
+enable_gcc_compat
+enable_pcc_debug
+enable_twopass
+enable_stripping
+enable_nativefp
+with_yasm
+enable_native
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures Portable C Compiler 1.2.0.DEVEL to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/pcc]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of Portable C Compiler 1.2.0.DEVEL:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-multiarch=yes/no/auto/<triplet>
+                          Enable use of Linux Multi-Arch paths (default: auto)
+  --enable-tls            Enable Thread-local storage (TLS).
+  --enable-Werror         Enable use of compiler -Werror flag
+  --disable-gcc-compat    Disable GCC compatibility
+  --disable-pcc-debug     Disable PCC debugging
+  --enable-twopass        Link PCC as a two-pass compiler
+  --disable-stripping     Disable stripping of symbols in installed binaries
+  --disable-nativefp      Disable use of compiler host floating point.
+  --enable-native         Build the compiler as a native rather than
+                          cross-build compiler
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-incdir=<path>    Specify the default include path.
+  --with-libdir=<path>    Specify the default library path.
+  --with-assembler=<path> Specify alternate assember.
+  --with-linker=<path>    Specify alternate linker.
+  --use-yasm              Use yasm assembler
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  YACC        The `Yet Another Compiler Compiler' implementation to use.
+              Defaults to the first program found out of: `bison -y', `byacc',
+              `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <pcc@lists.ludd.ltu.se>.
+Portable C Compiler home page: <http://pcc.ludd.ltu.se/>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+Portable C Compiler configure 1.2.0.DEVEL
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ------------------------------------ ##
+## Report this to pcc@lists.ludd.ltu.se ##
+## ------------------------------------ ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+        return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+           return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by Portable C Compiler $as_me 1.2.0.DEVEL, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+abi=unknown
+endian=little
+targosver=0
+tls=no
+gcccompat=yes
+pccdebug=yes
+stripping=yes
+native=no
+nativefp=yes
+useyasm=no
+stabs=no
+dwarf=no
+# allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short)
+wchar_type=INT
+
+case "$target_os" in
+
+    apple)
+       targos=apple
+       abi=classic68k
+       stabs=yes
+       case "$target_cpu" in
+           m68k) targmach=m68k endian=big ;;
+       esac
+       ;;
+
+    bsd)
+       targos=bsd
+       abi=aout
+       case "$target_cpu" in
+           pdp11) targmach=pdp11 ;;
+           nova) targmach=nova ;;
+       esac
+       wchar_type=USHORT
+       ;;
+
+    darwin*)
+       targos=darwin
+       abi=macho
+       stabs=yes
+       case "$target_os" in
+           *10.*) targosver=10 ;;
+           *9.*) targosver=9 ;;
+           *8.*) targosver=8 ;;
+           *7.*) targosver=7 ;;
+       esac
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           powerpc) targmach=powerpc endian=big ;;
+           x86_64) targmach=amd64 ;;
+       esac
+        ;;
+
+    dragonfly*)
+       targos=dragonfly
+       abi=elf
+       stabs=yes
+       tls=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    freebsd*)
+       targos=freebsd
+       abi=elf
+       stabs=yes
+       case "$target_os" in
+           *10.*) targosver=10 ;;
+           *9.*) targosver=9 ;;
+           *8.*) targosver=8 ;;
+           *7.*) targosver=7 ;;
+           *6.*) targosver=6 ;;
+           *5.*) targosver=5 ;;
+           *4.*) targosver=4 ;;
+       esac
+       case "$target_cpu" in
+           i386) targmach=i386 ;;
+           sparc64) targmach=sparc64 endian=big ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    linux-android*)
+       targos=android
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           arm*) targmach=arm ;;
+           i?86) targmach=i386 ;;
+           x86_64) targmach=amd64 ;;
+           mipseb) targmach=mips endian=big ;;
+           mips*) targmach=mips ;;
+       esac
+       ;;
+
+    linux*)
+       targos=linux
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           arm*) targmach=arm ;;
+           i?86) targmach=i386 ;;
+           powerpc*) targmach=powerpc endian=big ;;
+           x86_64) targmach=amd64 ;;
+           mipseb) targmach=mips endian=big ;;
+           mips*) targmach=mips ;;
+       esac
+       case "$target_os" in
+           *-musl*) ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_MUSL" ;;
+       esac
+       ;;
+
+    litebsd*)
+       targos=litebsd
+       abi=elf
+       wchar_type=USHORT
+       case "$target_cpu" in
+           mips*) targmach=mips ;;
+       esac
+       ;;
+
+    midnightbsd*)
+       targos=midnightbsd
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           sparc64) targmach=sparc64 endian=big ;;
+       esac
+       ;;
+
+    mingw*)
+       targos=win32
+       abi=pecoff
+       wchar_type=USHORT
+       targmach=i386
+       altincdir="c:/mingw/include"
+       altlibdir="c:/mingw/lib"
+       ;;
+
+    minix*)
+       targos=minix
+       stabs=yes
+       case "$target_os" in
+           minix3) abi=aout ;;
+           minix3.*) abi=elf ;;
+           # default to ELF
+           *) abi=elf ;;
+       esac
+       case "$target_cpu" in
+           i86) targmach=i86 ;;
+           i?86) targmach=i386 ;;
+           arm*) targmach=arm ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    mirbsd*)
+       targos=mirbsd
+       abi=elf
+       stabs=yes
+       wchar_type=USHORT
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+       esac
+       ;;
+
+    netbsd*)
+       targos=netbsd
+       abi=elf
+       stabs=yes
+       case "$target_os" in
+           *7.*) targosver=7 ;;
+           *6.*) targosver=6 ;;
+           *5.*) targosver=5 ;;
+           *4.*) targosver=4 ;;
+           *3.*) targosver=3 ;;
+           *2.*) targosver=2 ;;
+           *1.*) targosver=1 ;;
+       esac
+       case "$target_cpu" in
+           armeb) targmach=arm endian=big ;;
+           arm*) targmach=arm ;;
+           i?86) targmach=i386 ;;
+           m68k*) targmach=m68k endian=big ;;
+           mipseb) targmach=mips endian=big ;;
+           mips*) targmach=mips ;;
+           pdp10) targmach=pdp10 ;;
+           powerpc) targmach=powerpc endian=big ;;
+           riscv32) targmach=riscv32 ;;
+           riscv64) targmach=riscv64 ;;
+           sparc64) targmach=sparc64 endian=big ;;
+           vax) targmach=vax ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    nextstep*)
+       targos=nextstep
+       abi=macho
+       stabs=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           sparc) targmach=sparc endian=big ;;
+           hppa) targmach=hppa endian=big ;;
+       esac
+       ;;
+
+    openbsd*)
+       targos=openbsd
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           vax) targmach=vax ;;
+           powerpc) targmach=powerpc endian=big ;;
+           sparc64) targmach=sparc64 endian=big ;;
+           m68k) targmach=m68k endian=big ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    sysv4*)
+       targos=sysv4
+       abi=elf
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+       esac
+       ;;
+
+    sunos*|solaris*)
+        targos=sunos
+        abi=elf
+       stabs=yes
+        case "$target_cpu" in
+            i?86) targmach=i386 ;;
+            sparc*) targmach=sparc64 endian=big ;;
+        esac
+        ;;
+
+    windows*|pe*)
+       target_alias=i386-pe
+       targos=win32
+       abi=pecoff
+       wchar_type=USHORT
+       targmach=i386
+       ;;
+
+    *)
+        targos="$target_os"
+       case "$target_cpu" in
+           m16c) targmach=m16c ;;
+           nova) targmach=nova ;;
+           i86) targmach=i86 ;;
+       esac
+       ;;
+esac
+
+if test "X$targos" = X -o "X$targmach" = X ; then
+       as_fn_error $? "'$target' is not (yet) supported by pcc." "$LINENO" 5
+fi
+
+case "$host_os" in
+
+    apple)
+        hostos=apple
+       ;;
+    bsd)
+        hostos=bsd
+       ;;
+    darwin*)
+       hostos=darwin
+       ;;
+    dragonfly*)
+        hostos=dragonfly
+       ;;
+    freebsd*)
+        hostos=freebsd
+       ;;
+    linux*)
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -D_BSD_SOURCE"
+        hostos=linux
+       ;;
+    litebsd*)
+       hostos=litebsd
+       ;;
+    midnightbsd*)
+        hostos=midnightbsd
+       ;;
+    mingw*)
+        hostos=win32
+       ;;
+    minix*)
+        hostos=minix
+       ;;
+    mirbsd*)
+        hostos=mirbsd
+       ;;
+    netbsd*)
+        hostos=netbsd
+       ;;
+    nextstep*)
+        hostos=nextstep
+       ;;
+    openbsd*)
+        hostos=openbsd
+       ;;
+    sunos*|solaris*)
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600"
+        hostos=sunos
+       ;;
+    pe*|windows*)
+       # quick hack for cross-build to win32 host
+       hostos=win32
+       if "$prefix" = NONE; then
+               prefix="c:/pcc"
+               assembler="yasm.exe -p gnu -f win32"
+               linker="link.exe /nologo"
+               ADD_CPPFLAGS="$ADD_CPPFLAGS -DMSLINKER"
+       fi
+       ;;
+
+esac
+
+if test "X$endian" = "Xbig" ; then
+
+$as_echo "#define TARGET_BIG_ENDIAN 1" >>confdefs.h
+
+else
+
+$as_echo "#define TARGET_LITTLE_ENDIAN 1" >>confdefs.h
+
+fi
+
+case "$abi" in
+       elf*)
+$as_echo "#define ELFABI 1" >>confdefs.h
+ ;;
+       aout)
+$as_echo "#define AOUTABI 1" >>confdefs.h
+ ;;
+       macho)
+$as_echo "#define MACHOABI 1" >>confdefs.h
+ ;;
+       coff)
+$as_echo "#define COFFABI 1" >>confdefs.h
+ ;;
+       ecoff)
+$as_echo "#define ECOFFABI 1" >>confdefs.h
+ ;;
+       pecoff)
+$as_echo "#define PECOFFABI 1" >>confdefs.h
+ ;;
+       classic68k)
+$as_echo "#define CLASSIC68K 1" >>confdefs.h
+ ;;
+esac
+
+if test "$stabs" = "yes"; then
+
+$as_echo "#define STABS 1" >>confdefs.h
+
+fi
+
+if test "$dwarf" = "yes"; then
+
+$as_echo "#define DWARF 1" >>confdefs.h
+
+fi
+
+# Specify alternate assembler, linker, include and lib paths
+# Check whether --enable-multiarch was given.
+if test "${enable_multiarch+set}" = set; then :
+  enableval=$enable_multiarch; multiarch=$enableval
+else
+  multiarch=auto
+fi
+
+
+# Check whether --with-incdir was given.
+if test "${with_incdir+set}" = set; then :
+  withval=$with_incdir; altincdir=$withval
+fi
+
+
+# Check whether --with-libdir was given.
+if test "${with_libdir+set}" = set; then :
+  withval=$with_libdir; altlibdir=$withval
+fi
+
+
+# Check whether --with-assembler was given.
+if test "${with_assembler+set}" = set; then :
+  withval=$with_assembler; assembler=$withval
+fi
+
+
+# Check whether --with-linker was given.
+if test "${with_linker+set}" = set; then :
+  withval=$with_linker; linker=$withval
+fi
+
+# Check whether --enable-tls was given.
+if test "${enable_tls+set}" = set; then :
+  enableval=$enable_tls; tls=$enableval
+fi
+
+if test "$tls" = "yes"; then
+
+$as_echo "#define TLS 1" >>confdefs.h
+
+fi
+# Check whether --enable-Werror was given.
+if test "${enable_Werror+set}" = set; then :
+  enableval=$enable_Werror; werror=$enableval
+fi
+
+if test "$werror" = "yes"; then
+       ADD_CFLAGS="$ADD_CFLAGS -Werror"
+fi
+# Check whether --enable-gcc-compat was given.
+if test "${enable_gcc_compat+set}" = set; then :
+  enableval=$enable_gcc_compat; gcccompat=$enableval
+fi
+
+if test "$gcccompat" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT";
+fi
+# Check whether --enable-pcc-debug was given.
+if test "${enable_pcc_debug+set}" = set; then :
+  enableval=$enable_pcc_debug; pccdebug=$enableval
+fi
+
+if test "$pccdebug" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DPCC_DEBUG";
+fi
+# Check whether --enable-twopass was given.
+if test "${enable_twopass+set}" = set; then :
+  enableval=$enable_twopass; twopass=$enableval
+fi
+
+if test "$twopass" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DTWOPASS";
+       CCNAMES='$(BINPREFIX)cc0$(EXEEXT) $(BINPREFIX)cc1$(EXEEXT)'
+       CF0='-DPASS1'
+       CF1='-DPASS2'
+else
+       CCNAMES='$(BINPREFIX)ccom$(EXEEXT)'
+fi
+
+# Check whether --enable-stripping was given.
+if test "${enable_stripping+set}" = set; then :
+  enableval=$enable_stripping; stripping=$enableval
+fi
+
+if test "$stripping" = "yes"; then
+       if test -z "$INSTALL_PROGRAM"; then
+               INSTALL_PROGRAM='${INSTALL} -s'
+       else
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Installed binaries may be unstripped" >&5
+$as_echo "$as_me: WARNING: Installed binaries may be unstripped" >&2;}
+       fi
+fi
+
+# Check whether --enable-nativefp was given.
+if test "${enable_nativefp+set}" = set; then :
+  enableval=$enable_nativefp; nfp=$enableval
+fi
+
+if test "$nfp" = "no"; then
+       nativefp=no
+fi
+if test "$nativefp" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DNATIVE_FLOATING_POINT"
+fi
+
+
+# Check whether --with-yasm was given.
+if test "${with_yasm+set}" = set; then :
+  withval=$with_yasm; useyasm=$withval
+fi
+
+if test "$useyasm" = "yes"; then
+       assembler="yasm"
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_YASM"
+fi
+# Check whether --enable-native was given.
+if test "${enable_native+set}" = set; then :
+  enableval=$enable_native; native=$enableval
+fi
+
+
+# Setup for ubuntu multiarch
+multiarch_path=
+case x$multiarch in
+xno)
+       ;;
+xyes)
+       multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path=
+       case $multiarch_path in
+       *-*-*) ;;
+       *)
+               as_fn_error $? "Cannot determine Multi-Arch path '$multiarch_path'!" "$LINENO" 5
+               ;;
+       esac
+       ;;
+xauto|x)
+       multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path=
+       case x$multiarch_path in
+       x*-*-*) ;;
+       x) ;;
+       *)
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unrecognised Multi-Arch path '$multiarch_path'!" >&5
+$as_echo "$as_me: WARNING: Ignoring unrecognised Multi-Arch path '$multiarch_path'!" >&2;}
+               multiarch_path=
+               ;;
+       esac
+       ;;
+x*-*-*)
+       multiarch_path=$multiarch
+       ;;
+*)
+       as_fn_error $? "Ignoring unrecognised Multi-Arch path '$multiarch_path'!" "$LINENO" 5
+       ;;
+esac
+if test -n "$multiarch_path"; then
+
+cat >>confdefs.h <<_ACEOF
+#define MULTIARCH_PATH "$multiarch_path"
+_ACEOF
+
+       multiarch="\"$multiarch_path\""
+else
+       multiarch="(no)"
+fi
+# setup for building a cross-compiler
+if test "X$native" = "Xyes" -o "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then
+       BINPREFIX=""
+else
+       BINPREFIX="${target_alias}-"
+       test "X$prefix" = XNONE && prefix="$ac_default_prefix"
+       test "X$exec_prefix" = XNONE && exec_prefix="${prefix}"
+       if test -z "$altincdir"; then
+               altincdir=${exec_prefix}/${target_alias}/include
+       fi
+       if test -z "$altlibdir"; then
+               altlibdir=${exec_prefix}/${target_alias}/lib
+       fi
+       if test -z "$assembler"; then
+               assembler=${BINPREFIX}as
+       fi
+       if test -z  "$linker"; then
+               linker=${BINPREFIX}ld
+       fi
+       preprocessor="${BINPREFIX}cpp"
+       compiler="${BINPREFIX}ccom"
+fi
+
+
+if test -n "$altincdir"; then
+
+cat >>confdefs.h <<_ACEOF
+#define STDINC "$altincdir"
+_ACEOF
+
+fi
+if test -n "$altlibdir"; then
+
+cat >>confdefs.h <<_ACEOF
+#define LIBDIR "${altlibdir}/"
+_ACEOF
+
+fi
+if test -n "$assembler"; then
+
+cat >>confdefs.h <<_ACEOF
+#define ASSEMBLER "$assembler"
+_ACEOF
+
+fi
+if test -n "$linker"; then
+
+cat >>confdefs.h <<_ACEOF
+#define LINKER "$linker"
+_ACEOF
+
+fi
+if test -n "$preprocessor"; then
+
+cat >>confdefs.h <<_ACEOF
+#define PREPROCESSOR "$preprocessor"
+_ACEOF
+
+fi
+if test -n "$compiler"; then
+
+cat >>confdefs.h <<_ACEOF
+#define COMPILER "$compiler"
+_ACEOF
+
+fi
+
+case $wchar_type in
+USHORT) wchar_size=2 ;;
+UNSIGNED|INT) wchar_size=4 ;;
+*) as_fn_error $? "Unknown wchar_t '$wchar_type'." "$LINENO" 5 ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define WCHAR_TYPE $wchar_type
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define WCHAR_SIZE $wchar_size
+_ACEOF
+
+
+# check for additional compiler flags
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate"
+for flag in $DESIRED_FLAGS
+do
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts $flag" >&5
+$as_echo_n "checking whether $CC accepts $flag... " >&6; }
+       cflags="$CFLAGS"
+       CFLAGS="$CFLAGS $flag -Werror"
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+           use_flag=yes
+
+else
+
+           use_flag=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       CFLAGS="$cflags"
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_flag" >&5
+$as_echo "$use_flag" >&6; }
+       if test $use_flag = yes; then
+           ADD_CFLAGS="$ADD_CFLAGS $flag"
+       fi
+done
+
+# setup for cross-compiling mkext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a C compiler for mkext" >&5
+$as_echo_n "checking for a C compiler for mkext... " >&6; }
+if test $cross_compiling = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross compiling" >&5
+$as_echo "cross compiling" >&6; }
+        for ac_prog in pcc gcc cc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC_FOR_BUILD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC_FOR_BUILD"; then
+  ac_cv_prog_CC_FOR_BUILD="$CC_FOR_BUILD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC_FOR_BUILD="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC_FOR_BUILD=$ac_cv_prog_CC_FOR_BUILD
+if test -n "$CC_FOR_BUILD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC_FOR_BUILD" >&5
+$as_echo "$CC_FOR_BUILD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$CC_FOR_BUILD" && break
+done
+
+else
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: not cross compiling" >&5
+$as_echo "not cross compiling" >&6; }
+        CC_FOR_BUILD=${CC-cc}
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 printf size specifiers" >&5
+$as_echo_n "checking for C99 printf size specifiers... " >&6; }
+if ${ac_cv_have_c99_format+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+  if test "$cross_compiling" = yes; then :
+   ac_cv_have_c99_format=yes
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+    $ac_includes_default
+int
+main ()
+{
+
+      char buf[64];
+      if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
+        exit(1);
+      else if (strcmp(buf, "12345"))
+        exit(2);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+   ac_cv_have_c99_format=yes
+else
+   ac_cv_have_c99_format=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_c99_format" >&5
+$as_echo "$ac_cv_have_c99_format" >&6; }
+if test $ac_cv_have_c99_format = yes; then
+
+$as_echo "#define HAVE_C99_FORMAT 1" >>confdefs.h
+
+fi
+
+# Byteorder of host
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+              not a universal capable compiler
+            #endif
+            typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+       # Check for potential -arch flags.  It is not universal unless
+       # there are at least two -arch flags with different values.
+       ac_arch=
+       ac_prev=
+       for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+        if test -n "$ac_prev"; then
+          case $ac_word in
+            i?86 | x86_64 | ppc | ppc64)
+              if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+                ac_arch=$ac_word
+              else
+                ac_cv_c_bigendian=universal
+                break
+              fi
+              ;;
+          esac
+          ac_prev=
+        elif test "x$ac_word" = "x-arch"; then
+          ac_prev=arch
+        fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+            #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+                    && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+                    && LITTLE_ENDIAN)
+             bogus endian macros
+            #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+               #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+                not big endian
+               #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+             bogus endian macros
+            #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+                not big endian
+               #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+                 { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+               short int ascii_ii[] =
+                 { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+               int use_ascii (int i) {
+                 return ascii_mm[i] + ascii_ii[i];
+               }
+               short int ebcdic_ii[] =
+                 { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+               short int ebcdic_mm[] =
+                 { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+               int use_ebcdic (int i) {
+                 return ebcdic_mm[i] + ebcdic_ii[i];
+               }
+               extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+             ac_cv_c_bigendian=yes
+           fi
+           if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+             if test "$ac_cv_c_bigendian" = unknown; then
+               ac_cv_c_bigendian=no
+             else
+               # finding both strings is unlikely to happen, but who knows?
+               ac_cv_c_bigendian=unknown
+             fi
+           fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+            /* Are we little or big endian?  From Harbison&Steele.  */
+            union
+            {
+              long int l;
+              char c[sizeof (long int)];
+            } u;
+            u.l = 1;
+            return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+
+$as_echo "#define HOST_BIG_ENDIAN 1" >>confdefs.h
+;; #(
+   no)
+
+$as_echo "#define HOST_LITTLE_ENDIAN 1" >>confdefs.h
+ ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+
+# Checks for programs.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           rm -rf conftest.one conftest.two conftest.dir
+           echo one > conftest.one
+           echo two > conftest.two
+           mkdir conftest.dir
+           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+             test -s conftest.one && test -s conftest.two &&
+             test -s conftest.dir/conftest.one &&
+             test -s conftest.dir/conftest.two
+           then
+             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+             break 3
+           fi
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_YACC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LEX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LEX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
+$as_echo "$LEX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument.  */
+    yyless ((input () != 0)); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ { ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
+$as_echo_n "checking lex output file root... " >&6; }
+if ${ac_cv_prog_lex_root+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
+$as_echo "$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
+$as_echo_n "checking lex library... " >&6; }
+if ${ac_cv_lib_lex+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_lex=$ac_lib
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
+$as_echo "$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
+$as_echo_n "checking whether yytext is a pointer... " >&6; }
+if ${ac_cv_prog_lex_yytext_pointer+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+  #define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_prog_lex_yytext_pointer=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
+$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+
+# Checks for libraries.
+
+# Checks for header files.
+# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h])
+for ac_header in string.h malloc.h libgen.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if ${ac_cv_header_sys_wait_h+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+  int s;
+  wait (&s);
+  s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_sys_wait_h=yes
+else
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+
+# Checks for library functions.
+##  AC_FUNC_STRTOD
+# AC_FUNC_VPRINTF
+# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol])
+for ac_func in strtold vsnprintf snprintf mkstemp strlcat strlcpy getopt ffs vfork
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
+$as_echo_n "checking for working alloca.h... " >&6; }
+if ${ac_cv_working_alloca_h+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+                         if (p) return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_working_alloca_h=yes
+else
+  ac_cv_working_alloca_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5
+$as_echo "$ac_cv_working_alloca_h" >&6; }
+if test $ac_cv_working_alloca_h = yes; then
+
+$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5
+$as_echo_n "checking for alloca... " >&6; }
+if ${ac_cv_func_alloca_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  ifdef HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+void *alloca (size_t);
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+                                   if (p) return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_func_alloca_works=yes
+else
+  ac_cv_func_alloca_works=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5
+$as_echo "$ac_cv_func_alloca_works" >&6; }
+
+if test $ac_cv_func_alloca_works = yes; then
+
+$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h
+
+else
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble.  Some versions do not even contain alloca or
+# contain a buggy version.  If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
+
+ALLOCA=\${LIBOBJDIR}alloca.$ac_objext
+
+$as_echo "#define C_ALLOCA 1" >>confdefs.h
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5
+$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; }
+if ${ac_cv_os_cray+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#if defined CRAY && ! defined CRAY2
+webecray
+#else
+wenotbecray
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "webecray" >/dev/null 2>&1; then :
+  ac_cv_os_cray=yes
+else
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5
+$as_echo "$ac_cv_os_cray" >&6; }
+if test $ac_cv_os_cray = yes; then
+  for ac_func in _getb67 GETB67 getb67; do
+    as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+    break
+fi
+
+  done
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5
+$as_echo_n "checking stack direction for C alloca... " >&6; }
+if ${ac_cv_c_stack_direction+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  ac_cv_c_stack_direction=0
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+find_stack_direction (int *addr, int depth)
+{
+  int dir, dummy = 0;
+  if (! addr)
+    addr = &dummy;
+  *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
+  dir = depth ? find_stack_direction (addr, depth - 1) : 0;
+  return dir + dummy;
+}
+
+int
+main (int argc, char **argv)
+{
+  return find_stack_direction (0, argc + !argv + 20) < 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_stack_direction=1
+else
+  ac_cv_c_stack_direction=-1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5
+$as_echo "$ac_cv_c_stack_direction" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'`
+pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'`
+pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'`
+test -n "$MPVERSION" && MPVERSION=", $MPVERSION"
+versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target$MPVERSION\""
+
+
+cat >>confdefs.h <<_ACEOF
+#define PCC_MAJOR $pcc_major
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PCC_MINOR $pcc_minor
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PCC_MINORMINOR $pcc_minorminor
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSSTR $versstr
+_ACEOF
+
+
+ac_config_files="$ac_config_files Makefile cc/Makefile cc/cc/Makefile cc/cpp/Makefile cc/ccom/Makefile cc/cxxcom/Makefile cc/driver/Makefile f77/Makefile f77/f77/Makefile f77/fcom/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+       cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+         mv -f confcache "$cache_file"$$ &&
+         mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+         mv -f confcache "$cache_file" ;;
+       esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by Portable C Compiler $as_me 1.2.0.DEVEL, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <pcc@lists.ludd.ltu.se>.
+Portable C Compiler home page: <http://pcc.ludd.ltu.se/>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+Portable C Compiler config.status 1.2.0.DEVEL
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/Makefile" ;;
+    "cc/cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cc/Makefile" ;;
+    "cc/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cpp/Makefile" ;;
+    "cc/ccom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/ccom/Makefile" ;;
+    "cc/cxxcom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cxxcom/Makefile" ;;
+    "cc/driver/Makefile") CONFIG_FILES="$CONFIG_FILES cc/driver/Makefile" ;;
+    "f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/Makefile" ;;
+    "f77/f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/f77/Makefile" ;;
+    "f77/fcom/Makefile") CONFIG_FILES="$CONFIG_FILES f77/fcom/Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
+h
+s///
+s/^/:/
+s/[     ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[  ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[    ]*#[    ]*define[       ][      ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+       || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+eval "exec_prefix=$exec_prefix"
+eval "bindir=$bindir"
+eval "libexecdir=$libexecdir"
+
+echo
+echo "Target CPU is .................... ${targmach}"
+echo "Target ABI is .................... ${abi}"
+echo "Target OS is ..................... ${targos}"
+echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}"
+echo "Installing compiler into ......... ${bindir}"
+echo "Installing pre-processor into .... ${libexecdir}"
+echo "Using assembler .................. ${assembler-<default>}"
+echo "Using linker ..................... ${linker-<default>}"
+echo "Using Multi-Arch path ............ ${multiarch}"
+echo "Using include path ............... ${altincdir-<default>}"
+echo "Using library path ............... ${altlibdir-<default>}"
+echo "Has TLS support .................. $tls"
+echo "Has native floating point ........ $nativefp"
+echo "Has GCC compatibility ............ $gcccompat"
+echo "Has PCC debugging ................ $pccdebug"
+echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)"
+echo
+echo "Configure finished.  Do 'make && make install' to compile and install.
+"
diff --git a/lang/pcc/pcc/configure.ac b/lang/pcc/pcc/configure.ac
new file mode 100644 (file)
index 0000000..6affe90
--- /dev/null
@@ -0,0 +1,702 @@
+                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([Portable C Compiler], [1.2.0.DEVEL], [pcc@lists.ludd.ltu.se], [pcc], [http://pcc.ludd.ltu.se/])
+AC_CONFIG_HEADER([config.h])
+
+AC_CANONICAL_TARGET
+
+abi=unknown
+endian=little
+targosver=0
+tls=no
+gcccompat=yes
+pccdebug=yes
+stripping=yes
+native=no
+nativefp=yes
+useyasm=no
+stabs=no
+dwarf=no
+# allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short)
+wchar_type=INT
+
+case "$target_os" in
+
+    apple)
+       targos=apple
+       abi=classic68k
+       stabs=yes
+       case "$target_cpu" in
+           m68k) targmach=m68k endian=big ;;
+       esac
+       ;;
+
+    bsd)
+       targos=bsd
+       abi=aout
+       case "$target_cpu" in
+           pdp11) targmach=pdp11 ;;
+           nova) targmach=nova ;;
+       esac
+       wchar_type=USHORT
+       ;;
+
+    darwin*)
+       targos=darwin
+       abi=macho
+       stabs=yes
+       case "$target_os" in
+           *10.*) targosver=10 ;;
+           *9.*) targosver=9 ;;
+           *8.*) targosver=8 ;;
+           *7.*) targosver=7 ;;
+       esac
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           powerpc) targmach=powerpc endian=big ;;
+           x86_64) targmach=amd64 ;;
+       esac
+        ;;
+
+    dragonfly*)
+       targos=dragonfly
+       abi=elf
+       stabs=yes
+       tls=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    freebsd*)
+       targos=freebsd
+       abi=elf
+       stabs=yes
+       case "$target_os" in
+           *10.*) targosver=10 ;;
+           *9.*) targosver=9 ;;
+           *8.*) targosver=8 ;;
+           *7.*) targosver=7 ;;
+           *6.*) targosver=6 ;;
+           *5.*) targosver=5 ;;
+           *4.*) targosver=4 ;;
+       esac
+       case "$target_cpu" in
+           i386) targmach=i386 ;;
+           sparc64) targmach=sparc64 endian=big ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    linux-android*)
+       targos=android
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           arm*) targmach=arm ;;
+           i?86) targmach=i386 ;;
+           x86_64) targmach=amd64 ;;
+           mipseb) targmach=mips endian=big ;;
+           mips*) targmach=mips ;;
+       esac
+       ;;
+
+    linux*)
+       targos=linux
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           arm*) targmach=arm ;;
+           i?86) targmach=i386 ;;
+           powerpc*) targmach=powerpc endian=big ;;
+           x86_64) targmach=amd64 ;;
+           mipseb) targmach=mips endian=big ;;
+           mips*) targmach=mips ;;
+       esac
+       case "$target_os" in
+           *-musl*) ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_MUSL" ;;
+       esac
+       ;;
+
+    litebsd*)
+       targos=litebsd
+       abi=elf
+       wchar_type=USHORT
+       case "$target_cpu" in
+           mips*) targmach=mips ;;
+       esac
+       ;;
+
+    midnightbsd*)
+       targos=midnightbsd
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           sparc64) targmach=sparc64 endian=big ;;
+       esac
+       ;;
+
+    mingw*)
+       targos=win32
+       abi=pecoff
+       wchar_type=USHORT
+       targmach=i386
+       altincdir="c:/mingw/include"
+       altlibdir="c:/mingw/lib"
+       ;;
+
+    minix*)
+       targos=minix
+       stabs=yes
+       case "$target_os" in
+           minix3) abi=aout ;;
+           minix3.*) abi=elf ;;
+           # default to ELF
+           *) abi=elf ;;
+       esac
+       case "$target_cpu" in
+           i86) targmach=i86 ;;
+           i?86) targmach=i386 ;;
+           arm*) targmach=arm ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    mirbsd*)
+       targos=mirbsd
+       abi=elf
+       stabs=yes
+       wchar_type=USHORT
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+       esac
+       ;;
+
+    netbsd*)
+       targos=netbsd
+       abi=elf
+       stabs=yes
+       case "$target_os" in
+           *7.*) targosver=7 ;;
+           *6.*) targosver=6 ;;
+           *5.*) targosver=5 ;;
+           *4.*) targosver=4 ;;
+           *3.*) targosver=3 ;;
+           *2.*) targosver=2 ;;
+           *1.*) targosver=1 ;;
+       esac
+       case "$target_cpu" in
+           armeb) targmach=arm endian=big ;;
+           arm*) targmach=arm ;;
+           i?86) targmach=i386 ;;
+           m68k*) targmach=m68k endian=big ;;
+           mipseb) targmach=mips endian=big ;;
+           mips*) targmach=mips ;;
+           pdp10) targmach=pdp10 ;;
+           powerpc) targmach=powerpc endian=big ;;
+           riscv32) targmach=riscv32 ;;
+           riscv64) targmach=riscv64 ;;
+           sparc64) targmach=sparc64 endian=big ;;
+           vax) targmach=vax ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    nextstep*)
+       targos=nextstep
+       abi=macho
+       stabs=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           sparc) targmach=sparc endian=big ;;
+           hppa) targmach=hppa endian=big ;;
+       esac
+       ;;
+
+    openbsd*)
+       targos=openbsd
+       abi=elf
+       stabs=yes
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+           vax) targmach=vax ;;
+           powerpc) targmach=powerpc endian=big ;;
+           sparc64) targmach=sparc64 endian=big ;;
+           m68k) targmach=m68k endian=big ;;
+           x86_64) targmach=amd64 ;;
+       esac
+       ;;
+
+    sysv4*)
+       targos=sysv4
+       abi=elf
+       case "$target_cpu" in
+           i?86) targmach=i386 ;;
+       esac
+       ;;
+
+    sunos*|solaris*)
+        targos=sunos
+        abi=elf
+       stabs=yes
+        case "$target_cpu" in
+            i?86) targmach=i386 ;;
+            sparc*) targmach=sparc64 endian=big ;;
+        esac
+        ;;
+
+    windows*|pe*)
+       target_alias=i386-pe
+       targos=win32
+       abi=pecoff
+       wchar_type=USHORT
+       targmach=i386
+       ;;
+
+    *)
+        targos="$target_os"
+       case "$target_cpu" in
+           m16c) targmach=m16c ;;
+           nova) targmach=nova ;;
+           i86) targmach=i86 ;;
+       esac
+       ;;
+esac
+
+if test "X$targos" = X -o "X$targmach" = X ; then
+       AC_MSG_ERROR(['$target' is not (yet) supported by pcc.])
+fi
+
+case "$host_os" in
+
+    apple)
+        hostos=apple
+       ;;
+    bsd)
+        hostos=bsd
+       ;;
+    darwin*)
+       hostos=darwin
+       ;;
+    dragonfly*)
+        hostos=dragonfly
+       ;;
+    freebsd*)
+        hostos=freebsd
+       ;;
+    linux*)
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -D_BSD_SOURCE"
+        hostos=linux
+       ;;
+    litebsd*)
+       hostos=litebsd
+       ;;
+    midnightbsd*)
+        hostos=midnightbsd
+       ;;
+    mingw*)
+        hostos=win32
+       ;;
+    minix*)
+        hostos=minix
+       ;;
+    mirbsd*)
+        hostos=mirbsd
+       ;;
+    netbsd*)
+        hostos=netbsd
+       ;;
+    nextstep*)
+        hostos=nextstep
+       ;;
+    openbsd*)
+        hostos=openbsd
+       ;;
+    sunos*|solaris*)
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600"
+        hostos=sunos
+       ;;
+    pe*|windows*)
+       # quick hack for cross-build to win32 host
+       hostos=win32
+       if "$prefix" = NONE; then
+               prefix="c:/pcc"
+               assembler="yasm.exe -p gnu -f win32"
+               linker="link.exe /nologo"
+               ADD_CPPFLAGS="$ADD_CPPFLAGS -DMSLINKER"
+       fi
+       ;;
+
+esac
+
+if test "X$endian" = "Xbig" ; then
+       AC_DEFINE(TARGET_BIG_ENDIAN, 1,
+               [Define if target defaults to BIG endian])
+else
+       AC_DEFINE(TARGET_LITTLE_ENDIAN, 1,
+               [Define if target defaults to LITTLE endian])
+fi
+
+case "$abi" in
+       elf*)           AC_DEFINE(ELFABI, 1, [Using ELF ABI]) ;;
+       aout)           AC_DEFINE(AOUTABI, 1, [Using a.out ABI]) ;;
+       macho)          AC_DEFINE(MACHOABI, 1, [Using Mach-O ABI]) ;;
+       coff)           AC_DEFINE(COFFABI, 1, [Using COFF ABI]) ;;
+       ecoff)          AC_DEFINE(ECOFFABI, 1, [Using ECOFF ABI]) ;;
+       pecoff)         AC_DEFINE(PECOFFABI, 1, [Using PE/COFF ABI]) ;;
+       classic68k)     AC_DEFINE(CLASSIC68K, 1, [Using Classic 68k ABI]) ;;
+esac
+
+if test "$stabs" = "yes"; then
+       AC_DEFINE(STABS, 1, [Enable STABS debugging output])
+fi
+
+if test "$dwarf" = "yes"; then
+       AC_DEFINE(DWARF, 1, [Enable DWARF debugging output])
+fi
+
+# Specify alternate assembler, linker, include and lib paths
+AC_ARG_ENABLE(multiarch,
+       AS_HELP_STRING([--enable-multiarch=yes/no/auto/<triplet>],
+               [Enable use of Linux Multi-Arch paths (default: auto)]),
+       [multiarch=$enableval], [multiarch=auto])
+AC_ARG_WITH(incdir,
+       AS_HELP_STRING([--with-incdir=<path>],
+               [Specify the default include path.]),
+       altincdir=$withval,
+       [])
+AC_ARG_WITH(libdir,
+       AS_HELP_STRING([--with-libdir=<path>],
+               [Specify the default library path.]),
+       altlibdir=$withval,
+       [])
+AC_ARG_WITH(assembler,
+       AS_HELP_STRING([--with-assembler=<path>],
+               [Specify alternate assember.]),
+       assembler=$withval,
+       [])
+AC_ARG_WITH(linker,
+       AS_HELP_STRING([--with-linker=<path>],
+               [Specify alternate linker.]),
+       linker=$withval,
+       [])
+AC_ARG_ENABLE(tls,
+       AS_HELP_STRING([--enable-tls],
+               [Enable Thread-local storage (TLS).]),
+       [tls=$enableval], [])
+if test "$tls" = "yes"; then
+       AC_DEFINE(TLS, 1, [Enable thread-local storage (TLS).])
+fi
+AC_ARG_ENABLE(Werror,
+       AS_HELP_STRING([--enable-Werror],
+               [Enable use of compiler -Werror flag]),
+       [werror=$enableval], [])
+if test "$werror" = "yes"; then
+       ADD_CFLAGS="$ADD_CFLAGS -Werror"
+fi
+AC_ARG_ENABLE(gcc-compat,
+       AS_HELP_STRING([--disable-gcc-compat],
+               [Disable GCC compatibility]),
+       [gcccompat=$enableval], [])
+if test "$gcccompat" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT";
+fi
+AC_ARG_ENABLE(pcc-debug,
+       AS_HELP_STRING([--disable-pcc-debug],
+               [Disable PCC debugging]),
+       [pccdebug=$enableval], [])
+if test "$pccdebug" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DPCC_DEBUG";
+fi
+AC_ARG_ENABLE(twopass,
+       AS_HELP_STRING([--enable-twopass],
+               [Link PCC as a two-pass compiler]),
+       [twopass=$enableval], [])
+if test "$twopass" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DTWOPASS";
+       CCNAMES='$(BINPREFIX)cc0$(EXEEXT) $(BINPREFIX)cc1$(EXEEXT)'
+       CF0='-DPASS1'
+       CF1='-DPASS2'
+else
+       CCNAMES='$(BINPREFIX)ccom$(EXEEXT)'
+fi
+
+AC_ARG_ENABLE(stripping,
+       AS_HELP_STRING([--disable-stripping],
+               [Disable stripping of symbols in installed binaries]),
+       [stripping=$enableval], [])
+if test "$stripping" = "yes"; then
+       if test -z "$INSTALL_PROGRAM"; then
+               INSTALL_PROGRAM='${INSTALL} -s'
+       else
+               AC_MSG_WARN([Installed binaries may be unstripped])
+       fi
+fi
+
+AC_ARG_ENABLE(nativefp,
+       AS_HELP_STRING([--disable-nativefp],
+               [Disable use of compiler host floating point.]),
+       [nfp=$enableval], [])
+if test "$nfp" = "no"; then
+       nativefp=no
+fi
+if test "$nativefp" = "yes"; then
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DNATIVE_FLOATING_POINT"
+fi
+
+AC_ARG_WITH(yasm,
+       AS_HELP_STRING([--use-yasm], [Use yasm assembler]),
+       useyasm=$withval,
+       [])
+if test "$useyasm" = "yes"; then
+       assembler="yasm"
+       ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_YASM"
+fi
+AC_ARG_ENABLE(native,
+       AS_HELP_STRING([--enable-native],
+               [Build the compiler as a native rather than cross-build compiler]),
+       [native=$enableval], [])
+
+# Setup for ubuntu multiarch
+multiarch_path=
+case x$multiarch in
+xno)
+       ;;
+xyes)
+       multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path=
+       case $multiarch_path in
+       *-*-*) ;;
+       *)
+               AC_MSG_ERROR([Cannot determine Multi-Arch path '$multiarch_path'!])
+               ;;
+       esac
+       ;;
+xauto|x)
+       multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path=
+       case x$multiarch_path in
+       x*-*-*) ;;
+       x) ;;
+       *)
+               AC_MSG_WARN([Ignoring unrecognised Multi-Arch path '$multiarch_path'!])
+               multiarch_path=
+               ;;
+       esac
+       ;;
+x*-*-*)
+       multiarch_path=$multiarch
+       ;;
+*)
+       AC_MSG_ERROR([Ignoring unrecognised Multi-Arch path '$multiarch_path'!])
+       ;;
+esac
+if test -n "$multiarch_path"; then
+       AC_DEFINE_UNQUOTED([MULTIARCH_PATH], ["$multiarch_path"],
+               [Define target Multi-Arch path])
+       multiarch="\"$multiarch_path\""
+else
+       multiarch="(no)"
+fi
+# setup for building a cross-compiler
+if test "X$native" = "Xyes" -o "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then
+       BINPREFIX=""
+else
+       BINPREFIX="${target_alias}-"
+       test "X$prefix" = XNONE && prefix="$ac_default_prefix"
+       test "X$exec_prefix" = XNONE && exec_prefix="${prefix}"
+       if test -z "$altincdir"; then
+               altincdir=${exec_prefix}/${target_alias}/include
+       fi
+       if test -z "$altlibdir"; then
+               altlibdir=${exec_prefix}/${target_alias}/lib
+       fi
+       if test -z "$assembler"; then
+               assembler=${BINPREFIX}as
+       fi
+       if test -z  "$linker"; then
+               linker=${BINPREFIX}ld
+       fi
+       preprocessor="${BINPREFIX}cpp"
+       compiler="${BINPREFIX}ccom"
+fi
+AC_SUBST(BINPREFIX)
+
+if test -n "$altincdir"; then
+       AC_DEFINE_UNQUOTED(STDINC, "$altincdir",
+               [Define alternate standard include directory])
+fi
+if test -n "$altlibdir"; then
+       AC_DEFINE_UNQUOTED(LIBDIR, "${altlibdir}/",
+               [Define alternate standard lib directory])
+fi
+if test -n "$assembler"; then
+       AC_DEFINE_UNQUOTED(ASSEMBLER, "$assembler",
+               [Define path to alternate assembler])
+fi
+if test -n "$linker"; then
+       AC_DEFINE_UNQUOTED(LINKER, "$linker",
+               [Define path to alternate linker])
+fi
+if test -n "$preprocessor"; then
+       AC_DEFINE_UNQUOTED(PREPROCESSOR, "$preprocessor",
+               [Define path to alternate preprocessor])
+fi
+if test -n "$compiler"; then
+       AC_DEFINE_UNQUOTED(COMPILER, "$compiler",
+               [Define path to alternate compiler])
+fi
+
+case $wchar_type in
+USHORT) wchar_size=2 ;;
+UNSIGNED|INT) wchar_size=4 ;;
+*) AC_MSG_ERROR([Unknown wchar_t '$wchar_type'.]) ;;
+esac
+
+AC_DEFINE_UNQUOTED(WCHAR_TYPE, $wchar_type, [Type to use for wide characters])
+AC_DEFINE_UNQUOTED(WCHAR_SIZE, $wchar_size, [Size of wide-character type in chars])
+
+# check for additional compiler flags
+AC_PROG_CC
+DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate"
+for flag in $DESIRED_FLAGS
+do
+       AC_MSG_CHECKING([whether $CC accepts $flag])
+       cflags="$CFLAGS"
+       CFLAGS="$CFLAGS $flag -Werror"
+       AC_COMPILE_IFELSE([
+           AC_LANG_PROGRAM([[]], [[]])
+         ], [
+           use_flag=yes
+         ], [
+           use_flag=no
+       ])
+       CFLAGS="$cflags"
+
+       AC_MSG_RESULT([$use_flag])
+       if test $use_flag = yes; then
+           ADD_CFLAGS="$ADD_CFLAGS $flag"
+       fi
+done
+
+# setup for cross-compiling mkext
+AC_MSG_CHECKING([for a C compiler for mkext])
+if test $cross_compiling = yes; then
+        AC_MSG_RESULT([cross compiling])
+        AC_CHECK_PROGS(CC_FOR_BUILD, [pcc gcc cc])
+else
+        AC_MSG_RESULT([not cross compiling])
+        CC_FOR_BUILD=${CC-cc}
+        AC_SUBST(CC_FOR_BUILD)
+fi
+
+AC_CACHE_CHECK([for C99 printf size specifiers], ac_cv_have_c99_format, [
+  AC_RUN_IFELSE([
+    AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], [[
+      char buf[64];
+      if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
+        exit(1);
+      else if (strcmp(buf, "12345"))
+        exit(2);
+      ]])],
+    [ ac_cv_have_c99_format=yes ],
+    [ ac_cv_have_c99_format=no ],
+    [ ac_cv_have_c99_format=yes ])
+])
+if test $ac_cv_have_c99_format = yes; then
+  AC_DEFINE([HAVE_C99_FORMAT], 1,
+    [Define to 1 if printf supports C99 size specifiers])
+fi
+
+# Byteorder of host
+AC_C_BIGENDIAN([AC_DEFINE(HOST_BIG_ENDIAN, 1, [Define if host is BIG endian])],
+       [AC_DEFINE(HOST_LITTLE_ENDIAN, 1, [Define if host is LITTLE endian])],
+       [])
+
+# Checks for programs.
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_PROG_LEX
+
+# Checks for libraries.
+
+# Checks for header files.
+# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([string.h malloc.h libgen.h])
+AC_HEADER_SYS_WAIT
+
+# Checks for library functions.
+##  AC_FUNC_STRTOD
+# AC_FUNC_VPRINTF
+# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol])
+AC_CHECK_FUNCS([strtold vsnprintf snprintf mkstemp strlcat strlcpy getopt ffs vfork])
+AC_FUNC_ALLOCA
+
+AC_EXEEXT
+
+AC_SUBST(targos)
+AC_SUBST(targosver)
+AC_SUBST(targmach)
+AC_SUBST(hostos)
+AC_SUBST(prefix)
+AC_SUBST(exec_prefix)
+AC_SUBST(libexecdir)
+AC_SUBST(includedir)
+AC_SUBST(PACKAGE_VERSION)
+AC_SUBST(ADD_CFLAGS)
+AC_SUBST(ADD_CPPFLAGS)
+AC_SUBST(CCNAMES)
+AC_SUBST(CF0)
+AC_SUBST(CF1)
+
+pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'`
+pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'`
+pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'`
+test -n "$MPVERSION" && MPVERSION=", $MPVERSION"
+versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target$MPVERSION\""
+
+AC_DEFINE_UNQUOTED(PCC_MAJOR, $pcc_major, [Major version no])
+AC_DEFINE_UNQUOTED(PCC_MINOR, $pcc_minor, [Minor version no])
+AC_DEFINE_UNQUOTED(PCC_MINORMINOR, $pcc_minorminor, [Minor minor version no])
+AC_DEFINE_UNQUOTED(VERSSTR, $versstr, [Version string])
+
+AC_CONFIG_FILES([Makefile
+               cc/Makefile
+               cc/cc/Makefile
+               cc/cpp/Makefile
+               cc/ccom/Makefile
+               cc/cxxcom/Makefile
+               cc/driver/Makefile
+               f77/Makefile
+               f77/f77/Makefile
+               f77/fcom/Makefile
+])
+AC_OUTPUT
+
+eval "exec_prefix=$exec_prefix"
+eval "bindir=$bindir"
+eval "libexecdir=$libexecdir"
+
+echo
+echo "Target CPU is .................... ${targmach}"
+echo "Target ABI is .................... ${abi}"
+echo "Target OS is ..................... ${targos}"
+echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}"
+echo "Installing compiler into ......... ${bindir}"
+echo "Installing pre-processor into .... ${libexecdir}"
+echo "Using assembler .................. ${assembler-<default>}"
+echo "Using linker ..................... ${linker-<default>}"
+echo "Using Multi-Arch path ............ ${multiarch}"
+echo "Using include path ............... ${altincdir-<default>}"
+echo "Using library path ............... ${altlibdir-<default>}"
+echo "Has TLS support .................. $tls"
+echo "Has native floating point ........ $nativefp"
+echo "Has GCC compatibility ............ $gcccompat"
+echo "Has PCC debugging ................ $pccdebug"
+echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)"
+echo
+echo "Configure finished.  Do 'make && make install' to compile and install.
+"
diff --git a/lang/pcc/pcc/f77/Makefile.in b/lang/pcc/pcc/f77/Makefile.in
new file mode 100644 (file)
index 0000000..060aad1
--- /dev/null
@@ -0,0 +1,28 @@
+#      $Id: Makefile.in,v 1.7 2011/06/07 13:56:05 plunky Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+@SET_MAKE@
+
+ALL_SUBDIRS=    f77 fcom
+DIST_SUBDIRS=   $(ALL_SUBDIRS)
+
+all install clean:
+       @for subdir in $(ALL_SUBDIRS); do \
+               _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \
+               echo "===> $$_nextdir_"; \
+               (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \
+                   exec $(MAKE) $(MFLAGS) $@) || exit $$?; \
+               echo "<=== $$_nextdir_"; \
+       done
+
+distclean:
+       @for subdir in $(DIST_SUBDIRS); do \
+               _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \
+               echo "===> $$_nextdir_"; \
+               (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \
+                   exec $(MAKE) $(MFLAGS) $@) || exit $$?; \
+               echo "<=== $$_nextdir_"; \
+       done
+       rm -f Makefile
diff --git a/lang/pcc/pcc/f77/f77/Makefile.in b/lang/pcc/pcc/f77/f77/Makefile.in
new file mode 100644 (file)
index 0000000..aef692b
--- /dev/null
@@ -0,0 +1,56 @@
+#      $Id: Makefile.in,v 1.22 2012/09/25 11:17:17 plunky Exp $
+#
+# Makefile.in for the f77 frontend of pcc.
+#
+VPATH=@srcdir@
+top_srcdir=@top_srcdir@
+top_builddir=@top_builddir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+includedir = @includedir@
+CC = @CC@
+TARGOS = @targos@
+TARGOSVER = @targosver@
+TARGMACH = @targmach@
+TARGET = @target@
+VERSION = @PACKAGE_VERSION@
+PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib
+PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include
+F77LIBDIR=-L$(prefix)/lib
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -DLANG_F77 \
+       -DLIBEXECDIR=\"$(libexecdir)\" -DINCLUDEDIR=\"$(includedir)\" \
+       -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \
+       -DLIBDIR=\"$(F77LIBDIR)\" -Dmach_$(TARGMACH) -Dos_$(TARGOS) \
+       -I$(FCOMDIR) -I$(top_builddir) -I$(top_srcdir)/os/$(TARGOS) -I$(MDIR)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+OBJS=f77.o
+DEST=@BINPREFIX@f77
+
+MIPDIR=$(top_srcdir)/mip
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+FCOMDIR=$(top_srcdir)/f77/fcom
+
+all: $(DEST)
+
+$(DEST): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+.c.o:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+install:
+       $(INSTALL_PROGRAM) $(DEST) $(bindir)
+
+clean:
+       rm -f  $(OBJS) $(DEST)
+
+distclean: clean
+       rm -f  Makefile
diff --git a/lang/pcc/pcc/f77/f77/f77.1 b/lang/pcc/pcc/f77/f77/f77.1
new file mode 100644 (file)
index 0000000..d947c90
--- /dev/null
@@ -0,0 +1,175 @@
+.\"    $Id: f77.1,v 1.2 2008/12/24 17:40:41 sgk Exp $
+.\"
+.\" Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" Redistributions of source code and documentation must retain the above
+.\" copyright notice, this list of conditions and the following disclaimer.
+.\" Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditionsand the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\"    This product includes software developed or owned by Caldera
+.\"    International, Inc.
+.\" Neither the name of Caldera International, Inc. nor the names of other
+.\" contributors may be used to endorse or promote products derived from
+.\" this software without specific prior written permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.TH F77 1
+.SH NAME
+f77 \- Fortran 77 compiler
+.SH SYNOPSIS
+.B f77
+[ option ] ... file ...
+.SH DESCRIPTION
+.I F77
+is the UNIX Fortran 77 compiler.
+It accepts several types of arguments:
+.PP
+Arguments whose names end with `.f' are taken to be
+Fortran 77 source programs;
+they are compiled, and
+each object program is left on the file in the current directory
+whose name is that of the source with `.o' substituted
+for '.f'.
+.PP
+Arguments whose names end with `.r' or `.e' are taken to be Ratfor or EFL
+source programs, respectively; these are first transformed by the
+appropriate preprocessor, then compiled by f77.
+.PP
+In the same way,
+arguments whose names end with `.c' or `.s' are taken to be C or assembly source programs
+and are compiled or assembled, producing a `.o' file.
+.PP
+The following options have the same meaning as in
+.IR cc (1).
+See
+.IR ld (1)
+for load-time options.
+.TP
+.B \-c
+Suppress loading and produce `.o' files for each source 
+file.
+.TP
+.B \-p
+Prepare object files for profiling, see
+.IR  prof (1).
+.TP
+.SM
+.B \-O
+Invoke an
+object-code optimizer.
+.TP
+.SM
+.B \-S
+Compile the named programs, and leave the
+assembler-language output on corresponding files suffixed `.s'.
+(No `.o' is created.).
+.TP
+.B \-f
+Use a floating point interpreter (for PDP11's that lack
+11/70-style floating point).
+.TP
+.BR \-o " output"
+Name the final output file
+.I output
+instead of `a.out'.
+.PP
+The following options are peculiar to
+.IR f77 .
+.TP
+.SM
+.BR \-onetrip
+Compile DO loops that are performed at least once if reached.
+(Fortran 77 DO loops are not performed at all if the upper limit is smaller than the lower limit.)
+.TP
+.BR \-u
+Make the default type of a variable `undefined' rather than using the default Fortran rules.
+.TP
+.BR \-q
+Suppress printing of procedure names during compilation.
+.TP
+.BR \-C
+Compile code to check that subscripts are within declared array bounds.
+.TP
+.BR \-w
+Suppress all warning messages.
+If the option is `\-w66', only Fortran 66 compatibility warnings are suppressed.
+.TP
+.BR \-F
+Apply EFL and Ratfor preprocessor to relevant files, put the result in the file
+with the suffix changed to `.f', but do not compile.
+.TP
+.BR \-m
+Apply the M4 preprocessor to each `.r' or `.e' file before transforming
+it with the Ratfor or EFL preprocessor.
+.TP
+.TP
+.BI \-E x
+Use the string
+.I x
+as an EFL option in processing `.e' files.
+.TP
+.BI \-R x
+Use the string 
+.I x
+as a Ratfor option in processing `.r' files.
+.PP
+Other arguments
+are taken
+to be either loader option arguments, or F77-compatible
+object programs, typically produced by an earlier
+run,
+or perhaps libraries of F77-compatible routines.
+These programs, together with the results of any
+compilations specified, are loaded (in the order
+given) to produce an executable program with name
+`a.out'.
+.SH FILES
+.nf
+.ta \w'/usr/lib/libF77.a   'u
+file.[fresc]   input file
+file.o object file
+a.out  loaded output
+./fort[pid].?  temporary
+/usr/lib/f77pass1      compiler
+/lib/f1        pass 2
+/lib/c2        optional optimizer
+/usr/lib/libF77.a      intrinsic function library
+/usr/lib/libI77.a      Fortran I/O library
+/lib/libc.a    C library, see section 3
+.fi
+.SH "SEE ALSO"
+S. I. Feldman,
+P. J. Weinberger,
+.I
+A Portable Fortran 77 Compiler
+.br
+prof(1), cc(1), ld(1)
+.SH DIAGNOSTICS
+The diagnostics produced by
+.I f77
+itself are intended to be
+self-explanatory.
+Occasional messages may be produced by the loader.
+.SH BUGS
+The Fortran 66 subset of the language has been
+exercised extensively;
+the newer features have not.
diff --git a/lang/pcc/pcc/f77/f77/f77.c b/lang/pcc/pcc/f77/f77/f77.c
new file mode 100644 (file)
index 0000000..d5c79f8
--- /dev/null
@@ -0,0 +1,799 @@
+/*     $Id: f77.c,v 1.22 2011/08/04 08:32:32 mickey Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+char xxxvers[] = "FORTRAN 77 DRIVER, VERSION 1.11,   28 JULY 1978\n";
+
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "ccconfig.h"
+
+typedef FILE *FILEP;
+typedef int flag;
+#define        YES 1
+#define NO 0
+
+FILEP diagfile;
+
+static int pid;
+static int sigivalue   = 0;
+static int sigqvalue   = 0;
+
+#ifndef FCOM
+#define        FCOM            "fcom"
+#endif
+
+#ifndef ASSEMBLER
+#define ASSEMBLER       "as"
+#endif
+
+#ifndef LINKER
+#define LINKER          "ld"
+#endif
+
+static char *fcom      = LIBEXECDIR "/" FCOM ;
+static char *asmname   = ASSEMBLER ;
+static char *ldname    = LINKER ;
+static char *startfiles[] = STARTFILES;
+static char *endfiles[] = ENDFILES;
+static char *dynlinker[] = DYNLINKER;
+static char *crt0file = CRT0FILE;
+static char *macroname = "m4";
+static char *shellname = "/bin/sh";
+static char *aoutname  = "a.out" ;
+static char *libdir    = LIBDIR ;
+static char *liblist[] = F77LIBLIST;
+
+static char *infname;
+static char asmfname[15];
+static char prepfname[15];
+
+#define MAXARGS 100
+int ffmax;
+static char *ffary[MAXARGS];
+static char eflags[30] = "";
+static char rflags[30] = "";
+static char lflag[3]   = "-x";
+static char *eflagp    = eflags;
+static char *rflagp    = rflags;
+static char **loadargs;
+static char **loadp;
+static int oflag;
+
+static flag loadflag   = YES;
+static flag saveasmflag        = NO;
+static flag profileflag        = NO;
+static flag optimflag  = NO;
+static flag debugflag  = NO;
+static flag verbose    = NO;
+static flag fortonly   = NO;
+static flag macroflag  = NO;
+
+static char *setdoto(char *), *lastchar(char *), *lastfield(char *);
+static void intrupt(int);
+static void enbint(void (*)(int));
+static void crfnames(void);
+static void fatal1(char *, ...);
+static void done(int), texec(char *, char **);
+static char *copyn(int, char *);
+static int dotchar(char *), unreadable(char *), sys(char *), dofort(char *);
+static int nodup(char *);
+static int await(int);
+static void rmf(char *), doload(char *[], char *[]), doasm(char *);
+static int callsys(char *, char **);
+static void errorx(char *, ...);
+
+static void
+addarg(char **ary, int *num, char *arg)
+{
+       ary[(*num)++] = arg;
+       if ((*num) == MAXARGS) {
+               fprintf(stderr, "argument array too small\n");
+               exit(1);
+       }
+}
+
+int
+main(int argc, char **argv)
+{
+       int i, c, status;
+       char *s;
+       char fortfile[20], *t;
+       char buff[100];
+
+       diagfile = stderr;
+
+       sigivalue = (int) signal(SIGINT, SIG_IGN) & 01;
+       sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01;
+       enbint(intrupt);
+
+       pid = getpid();
+       crfnames();
+
+       loadargs = (char **)calloc(1, (argc + 20) * sizeof(*loadargs));
+       if (!loadargs)
+               fatal1("out of memory");
+       loadp = loadargs;
+
+       --argc;
+       ++argv;
+
+       while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0') {
+               for(s = argv[0]+1 ; *s ; ++s)
+                       switch(*s) {
+                       case 'T':  /* use special passes */
+                               switch(*++s) {
+                               case '1':
+                                       fcom = s+1; goto endfor;
+                               case 'a':
+                                       asmname = s+1; goto endfor;
+                               case 'l':
+                                       ldname = s+1; goto endfor;
+                               case 'm':
+                                       macroname = s+1; goto endfor;
+                               default:
+                                       fatal1("bad option -T%c", *s);
+                               }
+                               break;
+
+                       case 'w': /* F66 warn or no warn */
+                               addarg(ffary, &ffmax, s-1);
+                               break;
+
+                       case 'q':
+                               /*
+                                * Suppress printing of procedure names during
+                                * compilation.
+                                */
+                               addarg(ffary, &ffmax, s-1);
+                               break;
+
+                       copyfflag:
+                       case 'u':
+                       case 'U':
+                       case 'M':
+                       case '1':
+                       case 'C':
+                               addarg(ffary, &ffmax, s-1);
+                               break;
+
+                       case 'O':
+                               optimflag = YES;
+                               addarg(ffary, &ffmax, s-1);
+                               break;
+
+                       case 'm':
+                               if(s[1] == '4')
+                                       ++s;
+                               macroflag = YES;
+                               break;
+
+                       case 'S':
+                               saveasmflag = YES;
+
+                       case 'c':
+                               loadflag = NO;
+                               break;
+
+                       case 'v':
+                               verbose = YES;
+                               break;
+
+                       case 'd':
+                               debugflag = YES;
+                               goto copyfflag;
+
+                       case 'p':
+                               profileflag = YES;
+                               goto copyfflag;
+
+                       case 'o':
+                               if(!strcmp(s, "onetrip")) {
+                                       addarg(ffary, &ffmax, s-1);
+                                       goto endfor;
+                               }
+                               oflag = 1;
+                               aoutname = *++argv;
+                               --argc;
+                               break;
+
+                       case 'F':
+                               fortonly = YES;
+                               loadflag = NO;
+                               break;
+
+                       case 'I':
+                               if(s[1]=='2' || s[1]=='4' || s[1]=='s')
+                                       goto copyfflag;
+                               fprintf(diagfile, "invalid flag -I%c\n", s[1]);
+                               done(1);
+
+                       case 'l':       /* letter ell--library */
+                               s[-1] = '-';
+                               *loadp++ = s-1;
+                               goto endfor;
+
+                       case 'E':       /* EFL flag argument */
+                               while(( *eflagp++ = *++s))
+                                       ;
+                               *eflagp++ = ' ';
+                               goto endfor;
+                       case 'R':
+                               while(( *rflagp++ = *++s ))
+                                       ;
+                               *rflagp++ = ' ';
+                               goto endfor;
+                       default:
+                               lflag[1] = *s;
+                               *loadp++ = copyn(strlen(lflag), lflag);
+                               break;
+                       }
+endfor:
+       --argc;
+       ++argv;
+       }
+
+       if (verbose)
+               fprintf(stderr, xxxvers);
+
+       if (argc == 0)
+               errorx("No input files");
+
+#ifdef mach_pdp11
+       if(nofloating)
+               *loadp++ = (profileflag ? NOFLPROF : NOFLFOOT);
+       else
+#endif
+
+       for(i = 0 ; i<argc ; ++i)
+               switch(c =  dotchar(infname = argv[i]) ) {
+               case 'r':       /* Ratfor file */
+               case 'e':       /* EFL file */
+                       if( unreadable(argv[i]) )
+                               break;
+                       s = fortfile;
+                       t = lastfield(argv[i]);
+                       while(( *s++ = *t++))
+                               ;
+                       s[-2] = 'f';
+
+                       if(macroflag) {
+                               snprintf(buff, sizeof(buff), "%s %s >%s",
+                                   macroname, infname, prepfname);
+                               if(sys(buff)) {
+                                       rmf(prepfname);
+                                       break;
+                               }
+                               infname = prepfname;
+                       }
+
+                       if(c == 'e')
+                               snprintf(buff, sizeof(buff), "efl %s %s >%s",
+                                   eflags, infname, fortfile);
+                       else
+                               snprintf(buff, sizeof(buff), "ratfor %s %s >%s",
+                                   rflags, infname, fortfile);
+                       status = sys(buff);
+                       if(macroflag)
+                               rmf(infname);
+                       if(status) {
+                               loadflag = NO;
+                               rmf(fortfile);
+                               break;
+                       }
+
+                       if( ! fortonly ) {
+                               infname = argv[i] = lastfield(argv[i]);
+                               *lastchar(infname) = 'f';
+       
+                               if( dofort(argv[i]) )
+                                       loadflag = NO;
+                               else    {
+                                       if( nodup(t = setdoto(argv[i])) )
+                                               *loadp++ = t;
+                                       rmf(fortfile);
+                               }
+                       }
+                       break;
+
+               case 'f':       /* Fortran file */
+               case 'F':
+                       if( unreadable(argv[i]) )
+                               break;
+                       if( dofort(argv[i]) )
+                               loadflag = NO;
+                       else if( nodup(t=setdoto(argv[i])) )
+                               *loadp++ = t;
+                       break;
+
+               case 'c':       /* C file */
+               case 's':       /* Assembler file */
+                       if( unreadable(argv[i]) )
+                               break;
+                       fprintf(diagfile, "%s:\n", argv[i]);
+                       snprintf(buff, sizeof(buff), "cc -c %s", argv[i]);
+                       if( sys(buff) )
+                               loadflag = NO;
+                       else
+                               if( nodup(t = setdoto(argv[i])) )
+                                       *loadp++ = t;
+                       break;
+
+               case 'o':
+                       if( nodup(argv[i]) )
+                               *loadp++ = argv[i];
+                       break;
+
+               default:
+                       if( ! strcmp(argv[i], "-o") )
+                               aoutname = argv[++i];
+                       else
+                               *loadp++ = argv[i];
+                       break;
+               }
+
+       if(loadflag)
+               doload(loadargs, loadp);
+       done(0);
+       return 0;
+}
+
+#define        ADD(x)  addarg(params, &nparms, (x))
+
+static int
+dofort(char *s)
+{
+       int nparms, i;
+       char *params[MAXARGS];
+
+       nparms = 0;
+       ADD(FCOM);
+       for (i = 0; i < ffmax; i++)
+               ADD(ffary[i]);
+       ADD(s);
+       ADD(asmfname);
+       ADD(NULL);
+
+       infname = s;
+       if (callsys(fcom, params))
+               errorx("Error.  No assembly.");
+       doasm(s);
+
+       if (saveasmflag == NO)
+               rmf(asmfname);
+       return(0);
+}
+
+
+static void
+doasm(char *s)
+{
+       char *obj;
+       char *params[MAXARGS];
+       int nparms;
+
+       if (oflag && loadflag == NO)
+               obj = aoutname;
+       else
+               obj = setdoto(s);
+
+       nparms = 0;
+       ADD(asmname);
+       ADD("-o");
+       ADD(obj);
+       ADD(asmfname);
+       ADD(NULL);
+
+       if (callsys(asmname, params))
+               fatal1("assembler error");
+       if(verbose)
+               fprintf(diagfile, "\n");
+}
+
+
+static void
+doload(char *v0[], char *v[])
+{
+       int nparms, i;
+       char *params[MAXARGS];
+       char **p;
+
+       nparms = 0;
+       ADD(ldname);
+       ADD("-X");
+       ADD("-d");
+       for (i = 0; dynlinker[i]; i++)
+               ADD(dynlinker[i]);
+       ADD("-o");
+       ADD(aoutname);
+       ADD(crt0file);
+       for (i = 0; startfiles[i]; i++)
+               ADD(startfiles[i]);
+       *v = NULL;
+       for(p = v0; *p ; p++)
+               ADD(*p);
+       if (libdir)
+               ADD(libdir);
+       for(p = liblist ; *p ; p++)
+               ADD(*p);
+       for (i = 0; endfiles[i]; i++)
+               ADD(endfiles[i]);
+       ADD(NULL);
+
+       if (callsys(ldname, params))
+               fatal1("couldn't load %s", ldname);
+
+       if(verbose)
+               fprintf(diagfile, "\n");
+}
+
+/* Process control and Shell-simulating routines */
+
+/*
+ * Execute f[] with parameter array v[].
+ * Copied from cc.
+ */
+static int
+callsys(char f[], char *v[])
+{
+       int t, status = 0;
+       pid_t p;
+       char *s;
+
+       if (debugflag || verbose) {
+               fprintf(stderr, "%s ", f);
+               for (t = 1; v[t]; t++)
+                       fprintf(stderr, "%s ", v[t]);
+               fprintf(stderr, "\n");
+       }
+
+       if ((p = fork()) == 0) {
+#ifdef notyet
+               if (Bflag) {
+                       size_t len = strlen(Bflag) + 8;
+                       char *a = malloc(len);
+                       if (a == NULL) {
+                               error("callsys: malloc failed");
+                               exit(1);
+                       }
+                       if ((s = strrchr(f, '/'))) {
+                               strlcpy(a, Bflag, len);
+                               strlcat(a, s, len);
+                               execv(a, v);
+                       }
+               }
+#endif
+               execvp(f, v);
+               if ((s = strrchr(f, '/')))
+                       execvp(s+1, v);
+               fprintf(stderr, "Can't find %s\n", f);
+               _exit(100);
+       } else {
+               if (p == -1) {
+                       printf("Try again\n");
+                       return(100);
+               }
+       }
+       while (waitpid(p, &status, 0) == -1 && errno == EINTR)
+               ;
+       if (WIFEXITED(status))
+               return (WEXITSTATUS(status));
+       if (WIFSIGNALED(status))
+               done(1);
+       fatal1("Fatal error in %s", f);
+       return 0; /* XXX */
+}
+
+
+static int
+sys(char *str)
+{
+       char *s, *t;
+       char *argv[100], path[100];
+       char *inname, *outname;
+       int append = 0;
+       int wait_pid;
+       int argc;
+
+
+       if(debugflag)
+               fprintf(diagfile, "%s\n", str);
+       inname  = NULL;
+       outname = NULL;
+       argv[0] = shellname;
+       argc = 1;
+
+       t = str;
+       while( isspace((int)*t) )
+               ++t;
+       while(*t) {
+               if(*t == '<')
+                       inname = t+1;
+               else if(*t == '>') {
+                       if(t[1] == '>') {
+                               append = YES;
+                               outname = t+2;
+                       } else  {
+                               append = NO;
+                               outname = t+1;
+                       }
+               } else
+                       argv[argc++] = t;
+               while( !isspace((int)*t) && *t!='\0' )
+                       ++t;
+               if(*t) {
+                       *t++ = '\0';
+                       while( isspace((int)*t) )
+                               ++t;
+               }
+       }
+
+       if(argc == 1)   /* no command */
+               return(-1);
+       argv[argc] = 0;
+
+       s = path;
+       t = "/usr/bin/";
+       while(*t)
+               *s++ = *t++;
+       for(t = argv[1] ; (*s++ = *t++) ; )
+               ;
+       if((wait_pid = fork()) == 0) {
+               if(inname)
+                       freopen(inname, "r", stdin);
+               if(outname)
+                       freopen(outname, (append ? "a" : "w"), stdout);
+               enbint(SIG_DFL);
+
+               texec(path+9, argv);  /* command */
+               texec(path+4, argv);  /*  /bin/command */
+               texec(path  , argv);  /* /usr/bin/command */
+
+               fatal1("Cannot load %s",path+9);
+       }
+
+       return( await(wait_pid) );
+}
+
+/* modified version from the Shell */
+static void
+texec(char *f, char **av)
+{
+
+       execv(f, av+1);
+
+       if (errno==ENOEXEC) {
+               av[1] = f;
+               execv(shellname, av);
+               fatal1("No shell!");
+       }
+       if (errno==ENOMEM)
+               fatal1("%s: too large", f);
+}
+
+/*
+ * Cleanup and exit with value k.
+ */
+static void
+done(int k)
+{
+       static int recurs       = NO;
+
+       if(recurs == NO) {
+               recurs = YES;
+               if (saveasmflag == NO)
+                       rmf(asmfname);
+       }
+       exit(k);
+}
+
+
+static void
+enbint(void (*k)(int))
+{
+if(sigivalue == 0)
+       signal(SIGINT,k);
+if(sigqvalue == 0)
+       signal(SIGQUIT,k);
+}
+
+
+
+static void
+intrupt(int a)
+{
+done(2);
+}
+
+
+static int
+await(int wait_pid)
+{
+int w, status;
+
+enbint(SIG_IGN);
+while ( (w = wait(&status)) != wait_pid)
+       if(w == -1)
+               fatal1("bad wait code");
+enbint(intrupt);
+if(status & 0377)
+       {
+       if(status != SIGINT)
+               fprintf(diagfile, "Termination code %d", status);
+       done(3);
+       }
+return(status>>8);
+}
+\f
+/* File Name and File Manipulation Routines */
+
+static int
+unreadable(char *s)
+{
+       FILE *fp;
+
+       if((fp = fopen(s, "r"))) {
+               fclose(fp);
+               return(NO);
+       } else {
+               fprintf(diagfile, "Error: Cannot read file %s\n", s);
+               loadflag = NO;
+               return(YES);
+       }
+}
+
+
+static void
+crfnames(void)
+{
+       snprintf(asmfname,  sizeof(asmfname),  "fort%d.%s", pid, "s");
+       snprintf(prepfname, sizeof(prepfname), "fort%d.%s", pid, "p");
+}
+
+
+
+static void
+rmf(char *fn)
+{
+if(!debugflag && fn!=NULL && *fn!='\0')
+       unlink(fn);
+}
+
+
+static int
+dotchar(char *s)
+{
+for( ; *s ; ++s)
+       if(s[0]=='.' && s[1]!='\0' && s[2]=='\0')
+               return( s[1] );
+return(NO);
+}
+
+
+static char *
+lastfield(char *s)
+{
+char *t;
+for(t = s; *s ; ++s)
+       if(*s == '/')
+               t = s+1;
+return(t);
+}
+
+
+static char *
+lastchar(char *s)
+{
+while(*s)
+       ++s;
+return(s-1);
+}
+
+
+static char *
+setdoto(char *s)
+{
+*lastchar(s) = 'o';
+return( lastfield(s) );
+}
+
+
+static char *
+copyn(int n, char *s)
+{
+       char *p, *q;
+
+       p = q = (char *)calloc(1, (unsigned) n + 1);
+       if (!p)
+               fatal1("out of memory");
+
+       while(n-- > 0)
+               *q++ = *s++;
+       return (p);
+}
+
+
+static int
+nodup(char *s)
+{
+char **p;
+
+for(p = loadargs ; p < loadp ; ++p)
+       if( !strcmp(*p, s) )
+               return(NO);
+
+return(YES);
+}
+
+
+static void
+errorx(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vfprintf(diagfile, fmt, ap);
+       fprintf(diagfile, "\n");
+       va_end(ap);
+
+       if (debugflag)
+               abort();
+       done(1);
+}
+
+
+static void
+fatal1(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fprintf(diagfile, "Compiler error in file %s: ", infname);
+       vfprintf(diagfile, fmt, ap);
+       fprintf(diagfile, "\n");
+       va_end(ap);
+
+       if (debugflag)
+               abort();
+       done(1);
+}
diff --git a/lang/pcc/pcc/f77/fcom/Makefile.in b/lang/pcc/pcc/f77/fcom/Makefile.in
new file mode 100644 (file)
index 0000000..1090cf4
--- /dev/null
@@ -0,0 +1,185 @@
+#      $Id: Makefile.in,v 1.23 2012/09/25 11:17:17 plunky Exp $
+#
+# Makefile for the Fortran 77 compiler
+#
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+CC = @CC@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -DFCOM -DLANG_F77 \
+       -Dos_$(TARGOS) -Dmach_$(TARGMACH) \
+       -I$(srcdir) -I$(builddir) -I$(top_builddir) \
+       -I$(MIPDIR) -I$(MDIR) -I$(top_srcdir)/os/$(TARGOS)
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LFLAGS =
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+TARGOS = @targos@
+TARGOSVER = @targosver@
+TARGMACH = @targmach@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+MIPDIR=$(top_srcdir)/mip
+
+DEST=@BINPREFIX@fcom$(EXEEXT)
+MKEXT=mkext$(EXEEXT)
+
+OBJS=  common.o compat.o data.o equiv.o error.o exec.o expr.o  \
+       external.o flocal.o gram.o init.o intr.o io.o lex.o     \
+       local2.o main.o match.o misc.o optim2.o order.o proc.o  \
+       put.o putscj.o reader.o regs.o table.o
+
+LOBJS= common.lo mkext.lo table.lo
+
+HDRS=  $(srcdir)/defs.h $(srcdir)/defines.h $(srcdir)/ftypes.h \
+       $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h $(MIPDIR)/node.h \
+       $(MDIR)/macdefs.h
+
+GSRC=  $(srcdir)/gram.head $(srcdir)/gram.dcl $(srcdir)/gram.expr \
+       $(srcdir)/gram.exec $(srcdir)/gram.io
+
+all: $(DEST)
+
+#
+# round 1: generate external.[ch] & gram.[ch]
+#
+
+$(LOBJS): $(HDRS)
+
+common.lo: $(MIPDIR)/common.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c
+
+mkext.lo: $(MIPDIR)/mkext.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c
+
+table.lo: $(MDIR)/table.c
+       $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c
+
+$(MKEXT): $(LOBJS)
+       $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS)
+
+external.c: $(MKEXT)
+       $(builddir)/$(MKEXT)
+
+gram.c:        $(GSRC) $(srcdir)/tokens
+       ( grep -n . < $(srcdir)/tokens | sed "s/\([^:]*\):\(.*\)/%token \2 \1/"; \
+           cat $(GSRC) ) > gram.y
+       $(YACC) $(YFLAGS) -d gram.y
+       mv -f y.tab.c gram.c
+       mv -f y.tab.h gram.h
+
+#
+# round 2: compile $(OBJS)
+#
+
+$(OBJS): $(HDRS) external.c gram.c
+
+common.o: $(MIPDIR)/common.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c
+
+compat.o: $(MIPDIR)/compat.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/compat.c
+
+data.o: $(srcdir)/data.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/data.c
+
+equiv.o: $(srcdir)/equiv.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/equiv.c
+
+error.o: $(srcdir)/error.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/error.c
+
+exec.o: $(srcdir)/exec.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/exec.c
+
+expr.o: $(srcdir)/expr.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/expr.c
+
+external.o: external.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c
+
+flocal.o: $(MDIR)/flocal.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/flocal.c
+
+gram.o: gram.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ gram.c
+
+init.o: $(srcdir)/init.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c
+
+intr.o: $(srcdir)/intr.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/intr.c
+
+io.o: $(srcdir)/io.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/io.c
+
+lex.o: $(srcdir)/lex.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/lex.c
+
+local2.o: $(MDIR)/local2.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c
+
+main.o: $(srcdir)/main.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c
+
+match.o: $(MIPDIR)/match.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c
+
+misc.o: $(srcdir)/misc.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/misc.c
+
+optim2.o: $(MIPDIR)/optim2.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c
+
+order.o: $(MDIR)/order.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c
+
+proc.o: $(srcdir)/proc.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/proc.c
+
+put.o: $(srcdir)/put.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/put.c
+
+putscj.o: $(srcdir)/putscj.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/putscj.c
+
+reader.o: $(MIPDIR)/reader.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c
+
+regs.o: $(MIPDIR)/regs.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c
+
+table.o: $(MDIR)/table.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c
+
+#
+# round 3: build $(DEST)
+#
+
+$(DEST): $(OBJS)
+       $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
+
+install: $(DEST)
+       test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)"
+       $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir)
+
+clean:
+       rm -f $(DEST) $(OBJS) $(MKEXT) $(LOBJS) \
+           y.tab.[ch] gram.[ych] external.[ch]
+
+distclean: clean
+       rm -f Makefile
diff --git a/lang/pcc/pcc/f77/fcom/data.c b/lang/pcc/pcc/f77/fcom/data.c
new file mode 100644 (file)
index 0000000..6313b5d
--- /dev/null
@@ -0,0 +1,358 @@
+/*     $Id: data.c,v 1.15 2008/05/11 15:28:03 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defines.h"
+#include "defs.h"
+
+#if 1 /* RAGGE */
+extern FILE *initfile;
+#endif
+
+/* ROUTINES CALLED DURING DATA STATEMENT PROCESSING */
+LOCAL void setdata(struct bigblock *, struct bigblock *, ftnint, ftnint);
+
+static char datafmt[] = "%s\t%05ld\t%05ld\t%d" ;
+
+/* another initializer, called from parser */
+void
+dataval(repp, valp)
+register struct bigblock *repp, *valp;
+{
+int i, nrep;
+ftnint elen, vlen;
+register struct bigblock *p;
+
+if(repp == NULL)
+       nrep = 1;
+else if (ISICON(repp) && repp->b_const.fconst.ci >= 0)
+       nrep = repp->b_const.fconst.ci;
+else
+       {
+       err("invalid repetition count in DATA statement");
+       frexpr(repp);
+       goto ret;
+       }
+frexpr(repp);
+
+if( ! ISCONST(valp) )
+       {
+       err("non-constant initializer");
+       goto ret;
+       }
+
+if(toomanyinit) goto ret;
+for(i = 0 ; i < nrep ; ++i)
+       {
+       p = nextdata(&elen, &vlen);
+       if(p == NULL)
+               {
+               err("too many initializers");
+               toomanyinit = YES;
+               goto ret;
+               }
+       setdata(p, valp, elen, vlen);
+       frexpr(p);
+       }
+
+ret:
+       frexpr(valp);
+}
+
+
+struct bigblock *nextdata(elenp, vlenp)
+ftnint *elenp, *vlenp;
+{
+register struct bigblock *ip;
+struct bigblock *pp;
+register struct bigblock *np;
+register chainp rp;
+bigptr p;
+bigptr neltp;
+register bigptr q;
+int skip;
+ftnint off;
+
+while(curdtp)
+       {
+       p = curdtp->chain.datap;
+       if(p->tag == TIMPLDO)
+               {
+               ip = p;
+               if(ip->b_impldo.implb==NULL || ip->b_impldo.impub==NULL || ip->b_impldo.varnp==NULL)
+                       fatal1("bad impldoblock 0%o", ip);
+               if(ip->isactive)
+                       ip->b_impldo.varvp->b_const.fconst.ci += ip->b_impldo.impdiff;
+               else
+                       {
+                       q = fixtype(cpexpr(ip->b_impldo.implb));
+                       if( ! ISICON(q) )
+                               goto doerr;
+                       ip->b_impldo.varvp = q;
+
+                       if(ip->b_impldo.impstep)
+                               {
+                               q = fixtype(cpexpr(ip->b_impldo.impstep));
+                               if( ! ISICON(q) )
+                                       goto doerr;
+                               ip->b_impldo.impdiff = q->b_const.fconst.ci;
+                               frexpr(q);
+                               }
+                       else
+                               ip->b_impldo.impdiff = 1;
+
+                       q = fixtype(cpexpr(ip->b_impldo.impub));
+                       if(! ISICON(q))
+                               goto doerr;
+                       ip->b_impldo.implim = q->b_const.fconst.ci;
+                       frexpr(q);
+
+                       ip->isactive = YES;
+                       rp = ALLOC(rplblock);
+                       rp->rplblock.nextp = rpllist;
+                       rpllist = rp;
+                       rp->rplblock.rplnp = ip->b_impldo.varnp;
+                       rp->rplblock.rplvp = ip->b_impldo.varvp;
+                       rp->rplblock.rpltag = TCONST;
+                       }
+
+               if( (ip->b_impldo.impdiff>0 &&
+                (ip->b_impldo.varvp->b_const.fconst.ci <= ip->b_impldo.implim))
+                || (ip->b_impldo.impdiff<0 &&
+               (ip->b_impldo.varvp->b_const.fconst.ci >= ip->b_impldo.implim)))
+                       { /* start new loop */
+                       curdtp = ip->b_impldo.datalist;
+                       goto next;
+                       }
+
+               /* clean up loop */
+
+               popstack(&rpllist);
+
+               frexpr(ip->b_impldo.varvp);
+               ip->isactive = NO;
+               curdtp = curdtp->chain.nextp;
+               goto next;
+               }
+
+       pp = p;
+       np = pp->b_prim.namep;
+       skip = YES;
+
+       if(p->b_prim.argsp==NULL && np->b_name.vdim!=NULL)
+               {   /* array initialization */
+               q = mkaddr(np);
+               off = typesize[np->vtype] * curdtelt;
+               if(np->vtype == TYCHAR)
+                       off *= np->vleng->b_const.fconst.ci;
+               q->b_addr.memoffset = mkexpr(OPPLUS, q->b_addr.memoffset, mkintcon(off) );
+               if( (neltp = np->b_name.vdim->nelt) && ISCONST(neltp))
+                       {
+                       if(++curdtelt < neltp->b_const.fconst.ci)
+                               skip = NO;
+                       }
+               else
+                       err("attempt to initialize adjustable array");
+               }
+       else
+               q = mklhs( cpexpr(pp) );
+       if(skip)
+               {
+               curdtp = curdtp->chain.nextp;
+               curdtelt = 0;
+               }
+       if(q->vtype == TYCHAR)
+               if(ISICON(q->vleng))
+                       *elenp = q->vleng->b_const.fconst.ci;
+               else    {
+                       err("initialization of string of nonconstant length");
+                       continue;
+                       }
+       else    *elenp = typesize[q->vtype];
+
+       if(np->vstg == STGCOMMON)
+               *vlenp = extsymtab[np->b_name.vardesc.varno].maxleng;
+       else if(np->vstg == STGEQUIV)
+               *vlenp = eqvclass[np->b_name.vardesc.varno].eqvleng;
+       else    {
+               *vlenp =  (np->vtype==TYCHAR ?
+                               np->vleng->b_const.fconst.ci : typesize[np->vtype]);
+               if(np->b_name.vdim)
+                       *vlenp *= np->b_name.vdim->nelt->b_const.fconst.ci;
+               }
+       return(q);
+
+doerr:
+               err("nonconstant implied DO parameter");
+               frexpr(q);
+               curdtp = curdtp->chain.nextp;
+
+next:  curdtelt = 0;
+       }
+
+return(NULL);
+}
+
+
+
+
+
+
+LOCAL void setdata(varp, valp, elen, vlen)
+struct bigblock *varp;
+ftnint elen, vlen;
+struct bigblock *valp;
+{
+union constant con;
+int i, k;
+int stg, type, valtype;
+ftnint offset;
+register char *s, *t;
+static char varname[XL+2];
+
+/* output form of name is padded with blanks and preceded
+   with a storage class digit
+*/
+
+stg = varp->vstg;
+varname[0] = (stg==STGCOMMON ? '2' : (stg==STGEQUIV ? '1' : '0') );
+s = memname(stg, varp->b_addr.memno);
+for(t = varname+1 ; *s ; )
+       *t++ = *s++;
+while(t < varname+XL+1)
+       *t++ = ' ';
+varname[XL+1] = '\0';
+
+offset = varp->b_addr.memoffset->b_const.fconst.ci;
+type = varp->vtype;
+valtype = valp->vtype;
+if(type!=TYCHAR && valtype==TYCHAR)
+       {
+       if(! ftn66flag)
+               warn("non-character datum initialized with character string");
+       varp->vleng = MKICON(typesize[type]);
+       varp->vtype = type = TYCHAR;
+       }
+else if( (type==TYCHAR && valtype!=TYCHAR) ||
+        (cktype(OPASSIGN,type,valtype) == TYERROR) )
+       {
+       err("incompatible types in initialization");
+       return;
+       }
+if(type != TYCHAR) {
+       if(valtype == TYUNKNOWN)
+               con.ci = valp->b_const.fconst.ci;
+       else    consconv(type, &con, valtype, &valp->b_const.fconst);
+}
+
+k = 1;
+switch(type)
+       {
+       case TYLOGICAL:
+               type = tylogical;
+       case TYSHORT:
+       case TYLONG:
+               fprintf(initfile, datafmt, varname, offset, vlen, type);
+               prconi(initfile, type, con.ci);
+               break;
+
+       case TYCOMPLEX:
+               k = 2;
+               type = TYREAL;
+       case TYREAL:
+               goto flpt;
+
+       case TYDCOMPLEX:
+               k = 2;
+               type = TYDREAL;
+       case TYDREAL:
+       flpt:
+
+               for(i = 0 ; i < k ; ++i)
+                       {
+                       fprintf(initfile, datafmt, varname, offset, vlen, type);
+                       prconr(initfile, type, con.cd[i]);
+                       offset += typesize[type];
+                       }
+               break;
+
+       case TYCHAR:
+               k = valp->vleng->b_const.fconst.ci;
+               if(elen < k)
+                       k = elen;
+
+               for(i = 0 ; i < k ; ++i)
+                       {
+                       fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR);
+                       fprintf(initfile, "\t%d\n", valp->b_const.fconst.ccp[i]);
+                       }
+               k = elen - valp->vleng->b_const.fconst.ci;
+               while( k-- > 0)
+                       {
+                       fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR);
+                       fprintf(initfile, "\t%d\n", ' ');
+                       }
+               break;
+
+       default:
+               fatal1("setdata: impossible type %d", type);
+       }
+
+}
+
+
+void
+frdata(p0)
+chainp p0;
+{
+register chainp p;
+register bigptr q;
+
+for(p = p0 ; p ; p = p->chain.nextp)
+       {
+       q = p->chain.datap;
+       if(q->tag == TIMPLDO)
+               {
+               if(q->isbusy)
+                       return; /* circular chain completed */
+               q->isbusy = YES;
+               frdata(q->b_impldo.datalist);
+               ckfree(q);
+               }
+       else
+               frexpr(q);
+       }
+
+frchain( &p0);
+}
diff --git a/lang/pcc/pcc/f77/fcom/defines.h b/lang/pcc/pcc/f77/fcom/defines.h
new file mode 100644 (file)
index 0000000..4ea3a65
--- /dev/null
@@ -0,0 +1,267 @@
+/*     $Id: defines.h,v 1.15 2008/05/10 07:53:41 ragge Exp $   */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+
+#ifdef FCOM
+#include "pass2.h"
+#endif
+#include "ftypes.h"
+
+#define INTERDATA 2
+#define GCOS 3
+#define PDP11 4
+#define IBM 5
+#define CMACH 6
+#define VAX 7
+
+#define DMR 2
+#define SCJ 3
+
+#define BINARY 2
+#define ASCII 3
+
+#define PREFIX 2
+#define POSTFIX 3
+
+#define M(x) (1<<x)
+#define ALLOC(x) ckalloc(sizeof(struct x))
+#define        BALLO() (bigptr)ckalloc(sizeof(struct bigblock))
+typedef void *ptr;
+typedef FILE *FILEP;
+typedef short flag;
+typedef long int ftnint;
+#define LOCAL static
+
+#define NO 0
+#define YES 1
+
+
+
+/* block tag values */
+
+#define TNAME 1
+#define TCONST 2
+#define TEXPR 3
+#define TADDR 4
+#define TPRIM 5
+#define TLIST 6
+#define TIMPLDO 7
+#define TERROR 8
+
+
+/* parser states */
+
+#define OUTSIDE 0
+#define INSIDE 1
+#define INDCL 2
+#define INDATA 3
+#define INEXEC 4
+
+/* procedure classes */
+
+#define PROCMAIN 1
+#define PROCBLOCK 2
+#define PROCSUBR 3
+#define PROCFUNCT 4
+
+
+/* storage classes */
+
+#define STGUNKNOWN 0
+#define STGARG 1
+#define STGAUTO 2
+#define STGBSS 3
+#define STGINIT 4
+#define STGCONST 5
+#define STGEXT 6
+#define STGINTR 7
+#define STGSTFUNCT 8
+#define STGCOMMON 9
+#define STGEQUIV 10
+#define STGREG 11
+#define STGLENG 12
+
+/* name classes */
+
+#define CLUNKNOWN 0
+#define CLPARAM 1
+#define CLVAR 2
+#define CLENTRY 3
+#define CLMAIN 4
+#define CLBLOCK 5
+#define CLPROC 6
+
+
+/* vproclass values */
+
+#define PUNKNOWN 0
+#define PEXTERNAL 1
+#define PINTRINSIC 2
+#define PSTFUNCT 3
+#define PTHISPROC 4
+
+/* control stack codes */
+
+#define CTLDO 1
+#define CTLIF 2
+#define CTLELSE 3
+
+
+/* operators */
+
+#define OPPLUS 1
+#define OPMINUS 2
+#define OPSTAR 3
+#define OPSLASH 4
+#define OPPOWER 5
+#define OPNEG 6
+#define OPOR 7
+#define OPAND 8
+#define OPEQV 9
+#define OPNEQV 10
+#define OPNOT 11
+#define OPCONCAT 12
+#define OPLT 13
+#define OPEQ 14
+#define OPGT 15
+#define OPLE 16
+#define OPNE 17
+#define OPGE 18
+#define OPCALL 19
+#define OPCCALL 20
+#define OPASSIGN 21
+/* #define OPPLUSEQ 22 */
+/* #define OPSTAREQ 23 */
+#define OPCONV 24
+#define OPLSHIFT 25
+#define OPMOD 26
+#define OPCOMMA 27
+/* #define OPQUEST 28 */
+/* #define OPCOLON 29 */
+#define OPABS 30
+#define OPMIN 31
+#define OPMAX 32
+#define OPADDR 33
+#define OPINDIRECT 34
+#define OPBITOR 35
+#define OPBITAND 36
+#define OPBITXOR 37
+#define OPBITNOT 38
+#define OPRSHIFT 39
+
+
+/* memory regions */
+
+#define REGARG 1
+#define REGAUTO 2
+#define REGBSS 3
+#define REGINIT 4
+#define REGCONST 5
+#define REGEXT 6
+#define REGPROG 7
+
+/* label type codes */
+
+#define LABUNKNOWN 0
+#define LABEXEC 1
+#define LABFORMAT 2
+#define LABOTHER 3
+
+
+/* INTRINSIC function codes*/
+
+#define INTREND 0
+#define INTRCONV 1
+#define INTRMIN 2
+#define INTRMAX 3
+#define INTRGEN 4
+#define INTRSPEC 5
+#define INTRBOOL 6
+#define INTRCNST 7
+
+
+/* I/O statement codes */
+
+#define IOSTDIN MKICON(5)
+#define IOSTDOUT MKICON(6)
+
+#define IOSBAD (-1)
+#define IOSPOSITIONAL 0
+#define IOSUNIT 1
+#define IOSFMT 2
+
+#define IOINQUIRE 1
+#define IOOPEN 2
+#define IOCLOSE 3
+#define IOREWIND 4
+#define IOBACKSPACE 5
+#define IOENDFILE 6
+#define IOREAD 7
+#define IOWRITE 8
+
+
+/* type masks */
+
+#define MSKLOGICAL     M(TYLOGICAL)
+#define MSKADDR        M(TYADDR)
+#define MSKCHAR        M(TYCHAR)
+#define MSKINT M(TYSHORT)|M(TYLONG)
+#define MSKREAL        M(TYREAL)|M(TYDREAL)
+#define MSKCOMPLEX     M(TYCOMPLEX)|M(TYDCOMPLEX)
+
+/* miscellaneous macros */
+
+#define ONEOF(x,y) (M(x) & (y))
+#define ISCOMPLEX(z) ONEOF(z, MSKCOMPLEX)
+#define ISREAL(z) ONEOF(z, MSKREAL)
+#define ISNUMERIC(z) ONEOF(z, MSKINT|MSKREAL|MSKCOMPLEX)
+#define ISICON(z) (z->tag==TCONST && ISINT(z->vtype))
+#define ISCHAR(z) (z->vtype==TYCHAR)
+#define ISINT(z)   ONEOF(z, MSKINT)
+#define ISCONST(z) (z->tag==TCONST)
+#define ISERROR(z) (z->tag==TERROR)
+#define ISPLUSOP(z) (z->tag==TEXPR && z->b_expr.opcode==OPPLUS)
+#define ISSTAROP(z) (z->tag==TEXPR && z->b_expr.opcode==OPSTAR)
+#define ISONE(z) (ISICON(z) && z->b_const.fconst.ci==1)
+/* #define INT(z) ONEOF(z, MSKINT|MSKCHAR) */
+#define MKICON(z) mkintcon( (ftnint)(z) )
+#define CHCON(z) mkstrcon(strlen(z), z)
+
+/* round a up to a multiple of b */
+#define roundup(a,b)    ( b * ( (a+b-1)/b) )
+
+/* prototypes for cpu-specific functions */
+void prchars(int *);
+
diff --git a/lang/pcc/pcc/f77/fcom/defs.h b/lang/pcc/pcc/f77/fcom/defs.h
new file mode 100644 (file)
index 0000000..488d2b1
--- /dev/null
@@ -0,0 +1,567 @@
+/*     $Id: defs.h,v 1.23 2011/12/12 09:18:25 plunky Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/* Copied from ../../cc/ccom/pass1.h. */
+#define DATA   1
+#define RDATA  2
+#define UDATA  4
+
+#define VL 6
+#define XL 8
+
+#define MAXINCLUDES 10
+#define MAXLITERALS 20
+#define MAXCTL 20
+#define MAXHASH 401
+#define MAXSTNO 1000
+#define MAXEXT 200
+#define MAXEQUIV 150
+#define MAXLABLIST 100
+
+typedef struct bigblock *bigptr;
+typedef union chainedblock *chainp;
+
+extern FILE *infile;
+extern FILE *diagfile;
+extern long int headoffset;
+
+extern char token [ ];
+extern int toklen;
+extern int lineno;
+extern char *infname;
+extern int needkwd;
+extern struct labelblock *thislabel;
+
+extern int mflag, tflag;
+
+extern flag profileflag;
+extern flag optimflag;
+extern flag quietflag;
+extern flag nowarnflag;
+extern flag ftn66flag;
+extern flag shiftcase;
+extern flag undeftype;
+extern flag shortsubs;
+extern flag onetripflag;
+extern flag checksubs;
+extern flag debugflag;
+extern int nerr;
+extern int nwarn;
+extern int ndata;
+
+extern int parstate;
+extern flag headerdone;
+extern int blklevel;
+extern flag saveall;
+extern flag substars;
+extern int impltype[ ];
+extern int implleng[ ];
+extern int implstg[ ];
+
+extern int tyint;
+extern int tylogical;
+extern ftnint typesize[];
+extern int typealign[];
+extern int procno;
+extern int proctype;
+extern char * procname;
+extern int rtvlabel[ ];
+extern int fudgelabel; /* to confuse the pdp11 optimizer */
+extern struct bigblock *typeaddr;
+extern struct bigblock *retslot;
+extern int cxslot;
+extern int chslot;
+extern int chlgslot;
+extern int procclass;
+extern ftnint procleng;
+extern int nentry;
+extern flag multitype;
+extern int blklevel;
+extern int lastlabno;
+extern int lastvarno;
+extern int lastargslot;
+extern int argloc;
+extern ftnint autoleng;
+extern ftnint bssleng;
+extern int retlabel;
+extern int ret0label;
+extern int dorange;
+extern int regnum[ ];
+extern bigptr regnamep[ ];
+extern int maxregvar;
+extern int highregvar;
+
+extern chainp templist;
+extern chainp holdtemps;
+extern chainp entries;
+extern chainp rpllist;
+extern chainp curdtp;
+extern ftnint curdtelt;
+extern flag toomanyinit;
+
+extern flag inioctl;
+extern int iostmt;
+extern struct bigblock *ioblkp;
+extern int nioctl;
+extern int nequiv;
+extern int nintnames;
+extern int nextnames;
+\f
+struct chain
+       {
+       chainp nextp;
+       bigptr datap;
+       };
+
+extern chainp chains;
+
+struct ctlframe
+       {
+       unsigned ctltype:8;
+       unsigned dostepsign:8;
+       int ctlabels[4];
+       int dolabel;
+       struct bigblock *donamep;
+       bigptr domax;
+       bigptr dostep;
+       };
+#define endlabel ctlabels[0]
+#define elselabel ctlabels[1]
+#define dobodylabel ctlabels[1]
+#define doposlabel ctlabels[2]
+#define doneglabel ctlabels[3]
+extern struct ctlframe ctls[ ];
+extern struct ctlframe *ctlstack;
+extern struct ctlframe *lastctl;
+
+struct extsym
+       {
+       char extname[XL];
+       unsigned extstg:4;
+       unsigned extsave:1;
+       unsigned extinit:1;
+       chainp extp;
+       ftnint extleng;
+       ftnint maxleng;
+       };
+
+extern struct extsym extsymtab[ ];
+extern struct extsym *nextext;
+extern struct extsym *lastext;
+
+struct labelblock
+       {
+       int labelno;
+       unsigned blklevel:8;
+       unsigned labused:1;
+       unsigned labinacc:1;
+       unsigned labdefined:1;
+       unsigned labtype:2;
+       ftnint stateno;
+       };
+
+extern struct labelblock labeltab[ ];
+extern struct labelblock *labtabend;
+extern struct labelblock *highlabtab;
+
+struct entrypoint
+       {
+       chainp nextp;
+       struct extsym *entryname;
+       chainp arglist;
+       int entrylabel;
+       int typelabel;
+       ptr enamep;
+       };
+
+struct primblock
+       {
+       struct bigblock *namep;
+       struct bigblock *argsp;
+       bigptr fcharp;
+       bigptr lcharp;
+       };
+
+
+struct hashentry
+       {
+       int hashval;
+       struct bigblock *varp;
+       };
+extern struct hashentry hashtab[ ];
+extern struct hashentry *lasthash;
+
+struct intrpacked      /* bits for intrinsic function description */
+       {
+       unsigned f1:3;
+       unsigned f2:4;
+       unsigned f3:7;
+       };
+
+struct nameblock
+       {
+       char varname[VL];
+       unsigned vdovar:1;
+       unsigned vdcldone:1;
+       unsigned vadjdim:1;
+       unsigned vsave:1;
+       unsigned vprocclass:3;
+       unsigned vregno:4;
+       union   {
+               int varno;
+               chainp vstfdesc;        /* points to (formals, expr) pair */
+               struct intrpacked intrdesc;     /* bits for intrinsic function */
+               } vardesc;
+       struct dimblock *vdim;
+       int voffset;
+       };
+
+
+struct paramblock
+       {
+       char varname[VL];
+       bigptr paramval;
+       } ;
+
+
+struct exprblock
+       {
+       unsigned opcode:6;
+       bigptr leftp;
+       bigptr rightp;
+       };
+
+struct dcomplex {
+       double dreal, dimag;
+};
+
+union constant
+       {
+       char *ccp;
+       ftnint ci;
+       double cd[2];
+       struct dcomplex dc;
+       };
+
+struct constblock
+       {
+       union constant fconst;
+       };
+
+
+struct listblock
+       {
+       chainp listp;
+       };
+
+
+
+struct addrblock
+       {
+       int memno;
+       bigptr memoffset;
+       unsigned istemp:1;
+       unsigned ntempelt:10;
+       };
+
+
+
+struct errorblock
+       {
+       int pad;
+       };
+
+
+struct dimblock
+       {
+       int ndim;
+       bigptr nelt;
+       bigptr baseoffset;
+       bigptr basexpr;
+       struct
+               {
+               bigptr dimsize;
+               bigptr dimexpr;
+               } dims[1];
+       };
+
+
+struct impldoblock  /* XXXX */
+       {
+#define        isactive vtype
+#define isbusy vclass
+       struct bigblock *varnp;
+       struct bigblock *varvp;
+       bigptr implb;
+       bigptr impub;
+       bigptr impstep;
+       ftnint impdiff;
+       ftnint implim;
+       chainp datalist;
+       };
+
+
+struct rplblock        /* name replacement block */
+       {
+       chainp nextp;
+       struct bigblock *rplnp;
+       ptr rplvp;
+       struct bigblock *rplxp;
+       int rpltag;
+       };
+
+
+
+struct equivblock
+       {
+       ptr equivs;
+       unsigned eqvinit:1;
+       long int eqvtop;
+       long int eqvbottom;
+       } ;
+#define eqvleng eqvtop
+
+extern struct equivblock eqvclass[ ];
+
+
+struct eqvchain
+       {
+       chainp nextp;
+       ptr eqvitem;
+       long int eqvoffset;
+       } ;
+
+union chainedblock
+       {
+       struct chain chain;
+       struct entrypoint entrypoint;
+       struct rplblock rplblock;
+       struct eqvchain eqvchain;
+       };
+
+
+struct bigblock {
+       unsigned tag:4;
+       unsigned vtype:4;
+       unsigned vclass:4;
+       unsigned vstg:4;
+       bigptr vleng;
+       union {
+               struct exprblock _expr;
+               struct addrblock _addr;
+               struct constblock _const;
+               struct errorblock _error;
+               struct listblock _list;
+               struct primblock _prim;
+               struct nameblock _name;
+               struct paramblock _param;
+               struct impldoblock _impldo;
+       } _u;
+#define        b_expr          _u._expr
+#define        b_addr          _u._addr
+#define        b_const         _u._const
+#define        b_error         _u._error
+#define        b_list          _u._list
+#define        b_prim          _u._prim
+#define        b_name          _u._name
+#define        b_param         _u._param
+#define        b_impldo        _u._impldo
+};
+
+struct literal
+       {
+       short littype;
+       short litnum;
+       union   {
+               ftnint litival;
+               double litdval;
+               struct  {
+                       char litclen;   /* small integer */
+                       char litcstr[XL];
+                       } litcval;
+               } litval;
+       };
+
+extern struct literal litpool[ ];
+extern int nliterals;
+
+
+
+
+
+/* popular functions with non integer return values */
+#define        expptr bigptr
+#define        tagptr bigptr
+
+ptr cpblock(int ,void *);
+
+ptr ckalloc(int);
+char *varstr(int, char *), *nounder(int, char *), *varunder(int, char *);
+char *copyn(int, char *), *copys(char *);
+chainp hookup(chainp, chainp), mkchain(bigptr, chainp);
+ftnint convci(int, char *), iarrlen(struct bigblock *q);
+ftnint lmin(ftnint, ftnint), lmax(ftnint, ftnint);
+ftnint simoffset(expptr *);
+char *memname(int, int), *convic(ftnint), *setdoto(char *);
+double convcd(int, char *);
+struct extsym *mkext(char *), 
+       *newentry(struct bigblock *),
+       *comblock(int, char *s);
+struct bigblock *mkname(int, char *);
+struct labelblock *mklabel(ftnint);
+struct bigblock *addrof(expptr), *call1(int, char *, expptr),
+       *call2(int, char *, expptr, expptr),
+       *call3(int, char *, expptr, expptr, expptr),
+       *call4(int, char *, expptr, expptr, expptr, expptr);
+struct bigblock *call0(int, char *), *mkexpr(int, bigptr, bigptr);
+struct bigblock *callk(int, char *, bigptr);
+
+struct bigblock *builtin(int, char *), *fmktemp(int, bigptr),
+       *mktmpn(int, int, bigptr), *nextdata(ftnint *, ftnint *),
+       *autovar(int, int, bigptr), *mklhs(struct bigblock *),
+       *mkaddr(struct bigblock *), *putconst(struct bigblock *),
+       *memversion(struct bigblock *);
+struct bigblock *mkscalar(struct bigblock *np);
+struct bigblock *realpart(struct bigblock *p);
+struct bigblock *imagpart(struct bigblock *p);
+
+struct bigblock *mkintcon(ftnint), *mkbitcon(int, int, char *),
+       *mklogcon(int), *mkaddcon(int), *mkrealcon(int, double),
+       *mkstrcon(int, char *), *mkcxcon(bigptr,bigptr);
+bigptr mkconst(int t);
+
+bigptr mklist(chainp p);
+bigptr mkiodo(chainp, chainp);
+
+
+bigptr mkconv(int, bigptr),
+       mkfunct(struct bigblock *), fixexpr(struct bigblock *),
+       fixtype(bigptr);
+
+
+bigptr cpexpr(bigptr), mkprim(bigptr, struct bigblock *, bigptr, bigptr);
+struct bigblock *mkarg(int, int);
+struct bigblock *errnode(void);
+void initkey(void), prtail(void), puteof(void), done(int);
+void fileinit(void), procinit(void), endproc(void), doext(void), preven(int);
+int inilex(char *), yyparse(void), newlabel(void), lengtype(int, int);
+void err(char *, ...), warn(char *, ...), fatal(char *, ...), enddcl(void);
+void p2pass(char *s), frexpr(bigptr), execerr(char *, ...);
+void setimpl(int, ftnint, int, int), setlog(void), newproc(void);
+void prdbginfo(void), impldcl(struct bigblock *p);
+void putbracket(void), enddcl(void), doequiv(void);
+void puthead(char *), startproc(struct extsym *, int);
+void dclerr(char *s, struct bigblock *v), putforce(int, bigptr);
+void entrypt(int, int, ftnint, struct extsym *, chainp);
+void settype(struct bigblock *, int, int), putlabel(int);
+void putbranch(struct bigblock *p), goret(int), putrbrack(int);
+void prolog(struct entrypoint *, struct bigblock *), prendproc(void);
+void prlocvar(char *, ftnint), prext(char *, ftnint, int);
+void vardcl(struct bigblock *v), frchain(chainp *p); 
+void frtemp(struct bigblock *p), incomm(struct extsym *, struct bigblock *);
+void setintr(struct bigblock * v), setext(struct bigblock * v);
+struct uux { expptr lb, ub; };
+void setbound(struct bigblock *, int, struct uux []);
+void setfmt(struct labelblock *lp), frdata(chainp), frrpl(void),
+       dataval(struct bigblock *, struct bigblock *),
+       consnegop(struct bigblock *p), exdo(int, chainp), exelse(void),
+       exendif(void), exif(bigptr), exelif(bigptr),
+       exequals(struct bigblock *, bigptr),
+       exassign(struct bigblock *, struct labelblock *),
+       exarif(bigptr, struct labelblock *, struct labelblock *,
+           struct labelblock *);
+
+
+
+int intrfunct(char s[VL]), eqn(int, char *, char *);
+int fmtstmt(struct labelblock *lp);
+int cktype(int, int, int);
+int yylex(void), inregister(struct bigblock *);
+int inilex(char *), iocname(void);
+int maxtype(int, int), flog2(ftnint), hextoi(int);
+int cmpstr(char *, char *, ftnint, ftnint);
+int enregister(struct bigblock *np);
+int conssgn(bigptr p);
+int fixargs(int, struct bigblock *);
+int addressable(bigptr p);
+
+void prlabel(int);
+void prconi(FILE *, int, ftnint);
+void prcona(ftnint);
+void prconr(FILE *, int, double);
+void prarif(bigptr, int, int, int);
+void putstr(char *, ftnint);
+NODE *putex1(bigptr p);
+void puteq(bigptr, bigptr);
+void popstack(chainp *p); 
+void consconv(int, union constant *, int, union constant *);
+void yyerror(char *s);
+void enddo(int);
+void doinclude(char *);
+void flline(void);
+void startioctl(void);
+void endioctl(void), endio(void), ioclause(int, bigptr), doio(chainp);
+void excall(struct bigblock *, struct bigblock *, int, struct labelblock *[]);
+void exreturn(expptr p);
+void exstop(int, expptr);
+void exgoto(struct labelblock *);
+void exasgoto(bigptr);
+void putcmgo(expptr, int, struct labelblock *[]);
+void putexpr(expptr p);
+void putif(expptr, int);
+void putgoto(int);
+void deregister(struct bigblock *np);
+NODE *putx(expptr p);
+void cpn(int, char *, char *);
+void prcmgoto(expptr, int, int, int);
+char *lexline(ftnint *n);
+bigptr suboffset(struct bigblock *p);
+struct bigblock *intraddr(struct bigblock *np);
+struct bigblock *intrcall(bigptr, bigptr, int);
+void setloc(int);
+void prnloc(char *name);
+void fprint(bigptr p, int indx);
+void ckfree(void *p);
+
+#undef expptr
+#undef tagptr
+
+#define        err1 err
+#define err2 err
+#define        warn1 warn
+#define        fatal1 fatal
diff --git a/lang/pcc/pcc/f77/fcom/equiv.c b/lang/pcc/pcc/f77/fcom/equiv.c
new file mode 100644 (file)
index 0000000..7e83d15
--- /dev/null
@@ -0,0 +1,309 @@
+/*     $Id: equiv.c,v 1.11 2008/05/11 15:28:03 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defines.h"
+#include "defs.h"
+
+
+/* ROUTINES RELATED TO EQUIVALENCE CLASS PROCESSING */
+LOCAL void eqvcommon(struct equivblock *, int, ftnint);
+LOCAL void eqveqv(int, int, ftnint);
+LOCAL void freqchain(struct equivblock *p);
+LOCAL int nsubs(struct bigblock *p);
+
+/* called at end of declarations section to process chains
+   created by EQUIVALENCE statements
+ */
+void
+doequiv()
+{
+register int i;
+int inequiv, comno, ovarno;
+ftnint comoffset, offset, leng;
+register struct equivblock *p;
+register chainp q;
+struct bigblock *itemp;
+register struct bigblock *np;
+bigptr offp;
+int ns;
+chainp cp;
+
+ovarno = comoffset = offset = 0; /* XXX gcc */
+for(i = 0 ; i < nequiv ; ++i)
+       {
+       p = &eqvclass[i];
+       p->eqvbottom = p->eqvtop = 0;
+       comno = -1;
+
+       for(q = p->equivs ; q ; q = q->eqvchain.nextp)
+               {
+               itemp = q->eqvchain.eqvitem;
+               vardcl(np = itemp->b_prim.namep);
+               if(itemp->b_prim.argsp || itemp->b_prim.fcharp)
+                       {
+                       if(np->b_name.vdim!=NULL && np->b_name.vdim->ndim>1 &&
+                          nsubs(itemp->b_prim.argsp)==1 )
+                               {
+                               if(! ftn66flag)
+                                       warn("1-dim subscript in EQUIVALENCE");
+                               cp = NULL;
+                               ns = np->b_name.vdim->ndim;
+                               while(--ns > 0)
+                                       cp = mkchain( MKICON(1), cp);
+                               itemp->b_prim.argsp->b_list.listp->chain.nextp = cp;
+                               }
+                       offp = suboffset(itemp);
+                       }
+               else    offp = MKICON(0);
+               if(ISICON(offp))
+                       offset = q->eqvchain.eqvoffset = offp->b_const.fconst.ci;
+               else    {
+                       dclerr("nonconstant subscript in equivalence ", np);
+                       np = NULL;
+                       goto endit;
+                       }
+               if( (leng = iarrlen(np)) < 0)
+                       {
+                       dclerr("adjustable in equivalence", np);
+                       np = NULL;
+                       goto endit;
+                       }
+               p->eqvbottom = lmin(p->eqvbottom, -offset);
+               p->eqvtop = lmax(p->eqvtop, leng-offset);
+
+               switch(np->vstg)
+                       {
+                       case STGUNKNOWN:
+                       case STGBSS:
+                       case STGEQUIV:
+                               break;
+
+                       case STGCOMMON:
+                               comno = np->b_name.vardesc.varno;
+                               comoffset = np->b_name.voffset + offset;
+                               break;
+
+                       default:
+                               dclerr("bad storage class in equivalence", np);
+                               np = NULL;
+                               goto endit;
+                       }
+       endit:
+               frexpr(offp);
+               q->eqvchain.eqvitem = np;
+               }
+
+       if(comno >= 0)
+               eqvcommon(p, comno, comoffset);
+       else  for(q = p->equivs ; q ; q = q->eqvchain.nextp)
+               {
+               if((np = q->eqvchain.eqvitem))
+                       {
+                       inequiv = NO;
+                       if(np->vstg==STGEQUIV) {
+                               if( (ovarno = np->b_name.vardesc.varno) == i)
+                                       {
+                                       if(np->b_name.voffset + q->eqvchain.eqvoffset != 0)
+                                               dclerr("inconsistent equivalence", np);
+                                       }
+                               else    {
+                                       offset = np->b_name.voffset;
+                                       inequiv = YES;
+                                       }
+                       }
+                       np->vstg = STGEQUIV;
+                       np->b_name.vardesc.varno = i;
+                       np->b_name.voffset = - q->eqvchain.eqvoffset;
+
+                       if(inequiv)
+                               eqveqv(i, ovarno, q->eqvchain.eqvoffset + offset);
+                       }
+               }
+       }
+
+for(i = 0 ; i < nequiv ; ++i)
+       {
+       p = & eqvclass[i];
+       if(p->eqvbottom!=0 || p->eqvtop!=0)
+               {
+               for(q = p->equivs ; q; q = q->eqvchain.nextp)
+                       {
+                       np = q->eqvchain.eqvitem;
+                       np->b_name.voffset -= p->eqvbottom;
+                       if(np->b_name.voffset % typealign[np->vtype] != 0)
+                               dclerr("bad alignment forced by equivalence", np);
+                       }
+               p->eqvtop -= p->eqvbottom;
+               p->eqvbottom = 0;
+               }
+       freqchain(p);
+       }
+}
+
+
+
+
+
+/* put equivalence chain p at common block comno + comoffset */
+
+LOCAL void eqvcommon(p, comno, comoffset)
+struct equivblock *p;
+int comno;
+ftnint comoffset;
+{
+int ovarno;
+ftnint k, offq;
+register struct bigblock *np;
+register chainp q;
+
+if(comoffset + p->eqvbottom < 0)
+       {
+       err1("attempt to extend common %s backward",
+               nounder(XL, extsymtab[comno].extname) );
+       freqchain(p);
+       return;
+       }
+
+if( (k = comoffset + p->eqvtop) > extsymtab[comno].extleng)
+       extsymtab[comno].extleng = k;
+
+for(q = p->equivs ; q ; q = q->eqvchain.nextp)
+       if((np = q->eqvchain.eqvitem))
+               {
+               switch(np->vstg)
+                       {
+                       case STGUNKNOWN:
+                       case STGBSS:
+                               np->vstg = STGCOMMON;
+                               np->b_name.vardesc.varno = comno;
+                               np->b_name.voffset = comoffset - q->eqvchain.eqvoffset;
+                               break;
+
+                       case STGEQUIV:
+                               ovarno = np->b_name.vardesc.varno;
+                               offq = comoffset - q->eqvchain.eqvoffset - np->b_name.voffset;
+                               np->vstg = STGCOMMON;
+                               np->b_name.vardesc.varno = comno;
+                               np->b_name.voffset = comoffset - q->eqvchain.eqvoffset;
+                               if(ovarno != (p - eqvclass))
+                                       eqvcommon(&eqvclass[ovarno], comno, offq);
+                               break;
+
+                       case STGCOMMON:
+                               if(comno != np->b_name.vardesc.varno ||
+                                  comoffset != np->b_name.voffset+q->eqvchain.eqvoffset)
+                                       dclerr("inconsistent common usage", np);
+                               break;
+
+
+                       default:
+                               fatal1("eqvcommon: impossible vstg %d", np->vstg);
+                       }
+               }
+
+freqchain(p);
+p->eqvbottom = p->eqvtop = 0;
+}
+
+
+/* put all items on ovarno chain on front of nvarno chain
+ * adjust offsets of ovarno elements and top and bottom of nvarno chain
+ */
+
+LOCAL void eqveqv(nvarno, ovarno, delta)
+int ovarno, nvarno;
+ftnint delta;
+{
+register struct equivblock *p0, *p;
+register struct nameblock *np;
+chainp q, q1;
+
+p0 = eqvclass + nvarno;
+p = eqvclass + ovarno;
+p0->eqvbottom = lmin(p0->eqvbottom, p->eqvbottom - delta);
+p0->eqvtop = lmax(p0->eqvtop, p->eqvtop - delta);
+p->eqvbottom = p->eqvtop = 0;
+
+for(q = p->equivs ; q ; q = q1)
+       {
+       q1 = q->eqvchain.nextp;
+       if( (np = q->eqvchain.eqvitem) && np->vardesc.varno==ovarno)
+               {
+               q->eqvchain.nextp = p0->equivs;
+               p0->equivs = q;
+               q->eqvchain.eqvoffset -= delta;
+               np->vardesc.varno = nvarno;
+               np->voffset -= delta;
+               }
+       else    ckfree(q);
+       }
+p->equivs = NULL;
+}
+
+
+
+
+LOCAL void
+freqchain(p)
+register struct equivblock *p;
+{
+register chainp q, oq;
+
+for(q = p->equivs ; q ; q = oq)
+       {
+       oq = q->eqvchain.nextp;
+       ckfree(q);
+       }
+p->equivs = NULL;
+}
+
+
+
+
+
+LOCAL int
+nsubs(p)
+register struct bigblock *p;
+{
+register int n;
+register chainp q;
+
+n = 0;
+if(p)
+       for(q = p->b_list.listp ; q ; q = q->chain.nextp)
+               ++n;
+
+return(n);
+}
diff --git a/lang/pcc/pcc/f77/fcom/error.c b/lang/pcc/pcc/f77/fcom/error.c
new file mode 100644 (file)
index 0000000..d2fbabd
--- /dev/null
@@ -0,0 +1,121 @@
+/*     $Id: error.c,v 1.8 2008/05/10 07:53:41 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void
+warn(char *s, ...)
+{
+       va_list ap;
+
+       if(nowarnflag)
+               return;
+
+       va_start(ap, s);
+       fprintf(diagfile, "Warning on line %d of %s: ", lineno, infname);
+       vfprintf(diagfile, s, ap);
+       fprintf(diagfile, "\n");
+       va_end(ap);
+       ++nwarn;
+}
+
+void
+err(char *s, ...)
+{
+       va_list ap;
+
+       va_start(ap, s);
+       fprintf(diagfile, "Error on line %d of %s: ", lineno, infname);
+       vfprintf(diagfile, s, ap);
+       fprintf(diagfile, "\n");
+       va_end(ap);
+       ++nerr;
+}
+
+void
+yyerror(s)
+char *s;
+{ err(s); }
+
+
+void
+dclerr(s, v)
+       char *s;
+       struct bigblock *v;
+{
+       char buff[100];
+
+       if(v) {
+               sprintf(buff, "Declaration error for %s: %s",
+                   varstr(VL, v->b_name.varname), s);
+               err( buff);
+       } else
+               err1("Declaration error %s", s);
+}
+
+
+void
+execerr(char *s, ...)
+{
+       va_list ap;
+
+       va_start(ap, s);
+       fprintf(diagfile, "Error on line %d of %s: Execution error ",
+           lineno, infname);
+       vfprintf(diagfile, s, ap);
+       fprintf(diagfile, "\n");
+       va_end(ap);
+       ++nerr;
+}
+
+void
+fatal(char *s, ...)
+{
+       va_list ap;
+
+       va_start(ap, s);
+       fprintf(diagfile, "Compiler error line %d of %s: ", lineno, infname);
+       vfprintf(diagfile, s, ap);
+       fprintf(diagfile, "\n");
+       va_end(ap);
+
+       if(debugflag)
+               abort();
+       done(3);
+       exit(3);
+}
diff --git a/lang/pcc/pcc/f77/fcom/exec.c b/lang/pcc/pcc/f77/fcom/exec.c
new file mode 100644 (file)
index 0000000..6584e8a
--- /dev/null
@@ -0,0 +1,591 @@
+/*     $Id: exec.c,v 1.14 2008/05/11 15:28:03 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+/*   Logical IF codes
+*/
+LOCAL void exar2(int, bigptr, int, int);
+LOCAL void pushctl(int code);
+LOCAL void popctl(void);
+LOCAL void poplab(void);
+LOCAL void mkstfunct(struct bigblock *, bigptr);
+
+void
+exif(p)
+bigptr p;
+{
+pushctl(CTLIF);
+ctlstack->elselabel = newlabel();
+putif(p, ctlstack->elselabel);
+}
+
+
+void
+exelif(p)
+bigptr p;
+{
+if(ctlstack->ctltype == CTLIF)
+       {
+       if(ctlstack->endlabel == 0)
+               ctlstack->endlabel = newlabel();
+       putgoto(ctlstack->endlabel);
+       putlabel(ctlstack->elselabel);
+       ctlstack->elselabel = newlabel();
+       putif(p, ctlstack->elselabel);
+       }
+
+else   execerr("elseif out of place", 0);
+}
+
+
+
+
+void
+exelse()
+{
+if(ctlstack->ctltype==CTLIF)
+       {
+       if(ctlstack->endlabel == 0)
+               ctlstack->endlabel = newlabel();
+       putgoto( ctlstack->endlabel );
+       putlabel(ctlstack->elselabel);
+       ctlstack->ctltype = CTLELSE;
+       }
+
+else   execerr("else out of place", 0);
+}
+
+void
+exendif()
+{
+if(ctlstack->ctltype == CTLIF)
+       {
+       putlabel(ctlstack->elselabel);
+       if(ctlstack->endlabel)
+               putlabel(ctlstack->endlabel);
+       popctl();
+       }
+else if(ctlstack->ctltype == CTLELSE)
+       {
+       putlabel(ctlstack->endlabel);
+       popctl();
+       }
+
+else   execerr("endif out of place", 0);
+}
+
+
+
+LOCAL void
+pushctl(code)
+int code;
+{
+register int i;
+
+if(++ctlstack >= lastctl)
+       fatal("nesting too deep");
+ctlstack->ctltype = code;
+for(i = 0 ; i < 4 ; ++i)
+       ctlstack->ctlabels[i] = 0;
+++blklevel;
+}
+
+
+LOCAL void
+popctl()
+{
+if( ctlstack-- < ctls )
+       fatal("control stack empty");
+--blklevel;
+poplab();
+}
+
+
+
+LOCAL void
+poplab()
+{
+register struct labelblock  *lp;
+
+for(lp = labeltab ; lp < highlabtab ; ++lp)
+       if(lp->labdefined)
+               {
+               /* mark all labels in inner blocks unreachable */
+               if(lp->blklevel > blklevel)
+                       lp->labinacc = YES;
+               }
+       else if(lp->blklevel > blklevel)
+               {
+               /* move all labels referred to in inner blocks out a level */
+               lp->blklevel = blklevel;
+               }
+}
+\f
+
+
+/*  BRANCHING CODE
+*/
+void
+exgoto(lab)
+struct labelblock *lab;
+{
+putgoto(lab->labelno);
+}
+
+
+
+
+/*
+ * Found an assignment expression.
+ */
+void
+exequals(struct bigblock *lp, bigptr rp)
+{
+       if(lp->tag != TPRIM) {
+               err("assignment to a non-variable");
+               frexpr(lp);
+               frexpr(rp);
+       } else if(lp->b_prim.namep->vclass!=CLVAR && lp->b_prim.argsp) {
+               if(parstate >= INEXEC)
+                       err("statement function amid executables");
+               else
+                       mkstfunct(lp, rp);
+       } else {
+               if(parstate < INDATA)
+                       enddcl();
+               puteq(mklhs(lp), rp);
+       }
+}
+
+/*
+ * Create a statement function; e.g. like "f(i)=i*i"
+ */
+void
+mkstfunct(struct bigblock *lp, bigptr rp)
+{
+       struct bigblock *p;
+       struct bigblock *np;
+       chainp args;
+
+       np = lp->b_prim.namep;
+       if(np->vclass == CLUNKNOWN)
+               np->vclass = CLPROC;
+       else {
+               dclerr("redeclaration of statement function", np);
+               return;
+       }
+
+       np->b_name.vprocclass = PSTFUNCT;
+       np->vstg = STGSTFUNCT;
+       impldcl(np);
+       args = (lp->b_prim.argsp ? lp->b_prim.argsp->b_list.listp : NULL);
+       np->b_name.vardesc.vstfdesc = mkchain((void *)args, (void *)rp);
+
+       for( ; args ; args = args->chain.nextp)
+               if( (p = args->chain.datap)->tag!=TPRIM ||
+                   p->b_prim.argsp || p->b_prim.fcharp || p->b_prim.lcharp)
+                       err("non-variable argument in statement function definition");
+               else {
+                       vardcl(args->chain.datap = p->b_prim.namep);
+                       ckfree(p);
+               }
+}
+
+
+void
+excall(name, args, nstars, labels)
+struct bigblock *name;
+struct bigblock *args;
+int nstars;
+struct labelblock *labels[ ];
+{
+register bigptr p;
+
+settype(name, TYSUBR, 0);
+p = mkfunct( mkprim(name, args, NULL, NULL) );
+p->vtype = p->b_expr.leftp->vtype = TYINT;
+if(nstars > 0)
+       putcmgo(p, nstars, labels);
+else putexpr(p);
+}
+
+
+void
+exstop(stop, p)
+int stop;
+register bigptr p;
+{
+char *q;
+int n;
+
+if(p)
+       {
+       if( ! ISCONST(p) )
+               {
+               execerr("pause/stop argument must be constant", 0);
+               frexpr(p);
+               p = mkstrcon(0, 0);
+               }
+       else if( ISINT(p->vtype) )
+               {
+               q = convic(p->b_const.fconst.ci);
+               n = strlen(q);
+               if(n > 0)
+                       {
+                       p->b_const.fconst.ccp = copyn(n, q);
+                       p->vtype = TYCHAR;
+                       p->vleng = MKICON(n);
+                       }
+               else
+                       p = mkstrcon(0, 0);
+               }
+       else if(p->vtype != TYCHAR)
+               {
+               execerr("pause/stop argument must be integer or string", 0);
+               p = mkstrcon(0, 0);
+               }
+       }
+else   p = mkstrcon(0, 0);
+
+putexpr( call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p) );
+}
+\f
+/* DO LOOP CODE */
+
+#define DOINIT par[0]
+#define DOLIMIT        par[1]
+#define DOINCR par[2]
+
+#define VARSTEP        0
+#define POSSTEP        1
+#define NEGSTEP        2
+
+void
+exdo(range, spec)
+int range;
+chainp spec;
+{
+register bigptr p, q;
+bigptr q1;
+register struct bigblock *np;
+chainp cp;
+register int i;
+int dotype, incsign = 0; /* XXX gcc */
+struct bigblock *dovarp, *dostgp;
+bigptr par[3];
+
+pushctl(CTLDO);
+dorange = ctlstack->dolabel = range;
+np = spec->chain.datap;
+ctlstack->donamep = NULL;
+if(np->b_name.vdovar)
+       {
+       err1("nested loops with variable %s", varstr(VL,np->b_name.varname));
+       ctlstack->donamep = NULL;
+       return;
+       }
+
+dovarp = mklhs( mkprim(np, 0,0,0) );
+if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) )
+       {
+       err("bad type on do variable");
+       return;
+       }
+ctlstack->donamep = np;
+
+np->b_name.vdovar = YES;
+if( enregister(np) )
+       {
+       /* stgp points to a storage version, varp to a register version */
+       dostgp = dovarp;
+       dovarp = mklhs( mkprim(np, 0,0,0) );
+       }
+else
+       dostgp = NULL;
+dotype = dovarp->vtype;
+
+for(i=0 , cp = spec->chain.nextp ; cp!=NULL && i<3 ; cp = cp->chain.nextp)
+       {
+       p = par[i++] = fixtype(cp->chain.datap);
+       if( ! ONEOF(p->vtype, MSKINT|MSKREAL) )
+               {
+               err("bad type on DO parameter");
+               return;
+               }
+       }
+
+frchain(&spec);
+switch(i)
+       {
+       case 0:
+       case 1:
+               err("too few DO parameters");
+               return;
+
+       default:
+               err("too many DO parameters");
+               return;
+
+       case 2:
+               DOINCR = MKICON(1);
+
+       case 3:
+               break;
+       }
+
+ctlstack->endlabel = newlabel();
+ctlstack->dobodylabel = newlabel();
+
+if( ISCONST(DOLIMIT) )
+       ctlstack->domax = mkconv(dotype, DOLIMIT);
+else
+       ctlstack->domax = fmktemp(dotype, NULL);
+
+if( ISCONST(DOINCR) )
+       {
+       ctlstack->dostep = mkconv(dotype, DOINCR);
+       if( (incsign = conssgn(ctlstack->dostep)) == 0)
+               err("zero DO increment");
+       ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP);
+       }
+else
+       {
+       ctlstack->dostep = fmktemp(dotype, NULL);
+       ctlstack->dostepsign = VARSTEP;
+       ctlstack->doposlabel = newlabel();
+       ctlstack->doneglabel = newlabel();
+       }
+
+if( ISCONST(ctlstack->domax) && ISCONST(DOINIT) && ctlstack->dostepsign!=VARSTEP)
+       {
+       puteq(cpexpr(dovarp), cpexpr(DOINIT));
+       if( onetripflag )
+               frexpr(DOINIT);
+       else
+               {
+               q = mkexpr(OPPLUS, MKICON(1),
+                       mkexpr(OPMINUS, cpexpr(ctlstack->domax), cpexpr(DOINIT)) );
+               if(incsign != conssgn(q))
+                       {
+                       warn("DO range never executed");
+                       putgoto(ctlstack->endlabel);
+                       }
+               frexpr(q);
+               }
+       }
+else if(ctlstack->dostepsign!=VARSTEP && !onetripflag)
+       {
+       if( ISCONST(ctlstack->domax) )
+               q = cpexpr(ctlstack->domax);
+       else
+               q = mkexpr(OPASSIGN, cpexpr(ctlstack->domax), DOLIMIT);
+
+       q1 = mkexpr(OPASSIGN, cpexpr(dovarp), DOINIT);
+       q = mkexpr( (ctlstack->dostepsign==POSSTEP ? OPLE : OPGE), q1, q);
+       putif(q, ctlstack->endlabel);
+       }
+else
+       {
+       if(! ISCONST(ctlstack->domax) )
+               puteq( cpexpr(ctlstack->domax), DOLIMIT);
+       q = DOINIT;
+       if( ! onetripflag )
+               q = mkexpr(OPMINUS, q,
+                       mkexpr(OPASSIGN, cpexpr(ctlstack->dostep), DOINCR) );
+       puteq( cpexpr(dovarp), q);
+       if(onetripflag && ctlstack->dostepsign==VARSTEP)
+               puteq( cpexpr(ctlstack->dostep), DOINCR);
+       }
+
+if(ctlstack->dostepsign == VARSTEP)
+       {
+       if(onetripflag)
+               putgoto(ctlstack->dobodylabel);
+       else
+               putif( mkexpr(OPGE, cpexpr(ctlstack->dostep), MKICON(0)),
+                       ctlstack->doneglabel );
+       putlabel(ctlstack->doposlabel);
+
+       p = cpexpr(dovarp);
+       putif( mkexpr(OPLE, mkexpr(OPASSIGN, p,
+           mkexpr(OPPLUS, cpexpr(dovarp), cpexpr(ctlstack->dostep))),
+           cpexpr(ctlstack->domax)), ctlstack->endlabel);
+       }
+putlabel(ctlstack->dobodylabel);
+if(dostgp)
+       puteq(dostgp, cpexpr(dovarp));
+frexpr(dovarp);
+}
+
+/*
+ * Reached the end of a DO statement.
+ */
+void
+enddo(int here)
+{
+       register struct ctlframe *q;
+       register bigptr t;
+       struct bigblock *np;
+       struct bigblock *ap;
+       register int i;
+
+       while(here == dorange) {
+               if((np = ctlstack->donamep)) {
+
+                       t = mklhs(mkprim(ctlstack->donamep, 0,0 ,0));
+                       t = mkexpr(OPASSIGN, cpexpr(t), 
+                           mkexpr(OPPLUS, t, cpexpr(ctlstack->dostep)));
+
+                       if(ctlstack->dostepsign == VARSTEP) {
+                               putif( mkexpr(OPLE, cpexpr(ctlstack->dostep),
+                                   MKICON(0)), ctlstack->doposlabel);
+                               putlabel(ctlstack->doneglabel);
+                               putif( mkexpr(OPLT, t, ctlstack->domax),
+                                   ctlstack->dobodylabel);
+                       } else
+                               putif( mkexpr( (ctlstack->dostepsign==POSSTEP ?
+                                       OPGT : OPLT), t, ctlstack->domax),
+                                       ctlstack->dobodylabel);
+                       putlabel(ctlstack->endlabel);
+                       if((ap = memversion(np)))
+                               puteq(ap, mklhs( mkprim(np,0,0,0)) );
+                       for(i = 0 ; i < 4 ; ++i)
+                               ctlstack->ctlabels[i] = 0;
+                       deregister(ctlstack->donamep);
+                       ctlstack->donamep->b_name.vdovar = NO;
+                       frexpr(ctlstack->dostep);
+               }
+
+               popctl();
+               dorange = 0;
+               for(q = ctlstack ; q>=ctls ; --q)
+                       if(q->ctltype == CTLDO) {
+                               dorange = q->dolabel;
+                               break;
+                       }
+       }
+}
+
+void
+exassign(vname, labelval)
+struct bigblock *vname;
+struct labelblock *labelval;
+{
+struct bigblock *p;
+
+p = mklhs(mkprim(vname,0,0,0));
+if( ! ONEOF(p->vtype, MSKINT|MSKADDR) )
+       err("noninteger assign variable");
+else
+       puteq(p, mkaddcon(labelval->labelno) );
+}
+
+
+void
+exarif(expr, neglab, zerlab, poslab)
+bigptr expr;
+struct labelblock *neglab, *zerlab, *poslab;
+{
+register int lm, lz, lp;
+
+lm = neglab->labelno;
+lz = zerlab->labelno;
+lp = poslab->labelno;
+expr = fixtype(expr);
+
+if( ! ONEOF(expr->vtype, MSKINT|MSKREAL) )
+       {
+       err("invalid type of arithmetic if expression");
+       frexpr(expr);
+       }
+else
+       {
+       if(lm == lz)
+               exar2(OPLE, expr, lm, lp);
+       else if(lm == lp)
+               exar2(OPNE, expr, lm, lz);
+       else if(lz == lp)
+               exar2(OPGE, expr, lz, lm);
+       else
+               prarif(expr, lm, lz, lp);
+       }
+}
+
+
+
+LOCAL void exar2(op, e, l1, l2)
+int op;
+bigptr e;
+int l1, l2;
+{
+putif( mkexpr(op, e, MKICON(0)), l2);
+putgoto(l1);
+}
+
+void
+exreturn(p)
+register bigptr p;
+{
+if(p && (proctype!=TYSUBR || procclass!=CLPROC) )
+       {
+       err("alternate return in nonsubroutine");
+       p = 0;
+       }
+
+if(p)
+       {
+       putforce(TYINT, p);
+       putgoto(retlabel);
+       }
+else
+       putgoto(procclass==TYSUBR ? ret0label : retlabel);
+}
+
+
+void
+exasgoto(labvar)
+bigptr labvar;
+{
+register struct bigblock *p;
+
+p = mklhs( mkprim(labvar,0,0,0) );
+if( ! ISINT(p->vtype) )
+       err("assigned goto variable must be integer");
+else
+       putbranch(p);
+}
diff --git a/lang/pcc/pcc/f77/fcom/expr.c b/lang/pcc/pcc/f77/fcom/expr.c
new file mode 100644 (file)
index 0000000..0f4d24b
--- /dev/null
@@ -0,0 +1,2179 @@
+/*     $Id: expr.c,v 1.20 2008/05/11 15:28:03 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+/* little routines to create constant blocks */
+LOCAL int letter(int c);
+LOCAL void conspower(union constant *, struct bigblock *, ftnint);
+LOCAL void consbinop(int, int, union constant *, union constant *,
+       union constant *);
+LOCAL void zdiv(struct dcomplex *, struct dcomplex *, struct dcomplex *);
+LOCAL struct bigblock *stfcall(struct bigblock *, struct bigblock *);
+LOCAL bigptr mkpower(struct bigblock *p);
+LOCAL bigptr fold(struct bigblock *e);
+LOCAL bigptr subcheck(struct bigblock *, bigptr);
+
+struct bigblock *mkconst(t)
+register int t;
+{
+register struct bigblock *p;
+
+p = BALLO();
+p->tag = TCONST;
+p->vtype = t;
+return(p);
+}
+
+
+struct bigblock *mklogcon(l)
+register int l;
+{
+register struct bigblock * p;
+
+p = mkconst(TYLOGICAL);
+p->b_const.fconst.ci = l;
+return(p);
+}
+
+
+
+struct bigblock *mkintcon(l)
+ftnint l;
+{
+register struct bigblock *p;
+
+p = mkconst(TYLONG);
+p->b_const.fconst.ci = l;
+#ifdef MAXSHORT
+       if(l >= -MAXSHORT   &&   l <= MAXSHORT)
+               p->vtype = TYSHORT;
+#endif
+return(p);
+}
+
+
+
+struct bigblock *mkaddcon(l)
+register int l;
+{
+register struct bigblock *p;
+
+p = mkconst(TYADDR);
+p->b_const.fconst.ci = l;
+return(p);
+}
+
+
+
+struct bigblock *mkrealcon(t, d)
+register int t;
+double d;
+{
+register struct bigblock *p;
+
+p = mkconst(t);
+p->b_const.fconst.cd[0] = d;
+return(p);
+}
+
+
+struct bigblock *mkbitcon(shift, leng, s)
+int shift;
+int leng;
+char *s;
+{
+register struct bigblock *p;
+
+p = mkconst(TYUNKNOWN);
+p->b_const.fconst.ci = 0;
+while(--leng >= 0)
+       if(*s != ' ')
+               p->b_const.fconst.ci = (p->b_const.fconst.ci << shift) | hextoi(*s++);
+return(p);
+}
+
+
+
+
+
+struct bigblock *mkstrcon(l,v)
+int l;
+register char *v;
+{
+register struct bigblock *p;
+register char *s;
+
+p = mkconst(TYCHAR);
+p->vleng = MKICON(l);
+p->b_const.fconst.ccp = s = (char *) ckalloc(l);
+while(--l >= 0)
+       *s++ = *v++;
+return(p);
+}
+
+
+struct bigblock *mkcxcon(realp,imagp)
+register bigptr realp, imagp;
+{
+int rtype, itype;
+register struct bigblock *p;
+
+rtype = realp->vtype;
+itype = imagp->vtype;
+
+if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) )
+       {
+       p = mkconst( (rtype==TYDREAL||itype==TYDREAL) ? TYDCOMPLEX : TYCOMPLEX );
+       if( ISINT(rtype) )
+               p->b_const.fconst.cd[0] = realp->b_const.fconst.ci;
+       else    p->b_const.fconst.cd[0] = realp->b_const.fconst.cd[0];
+       if( ISINT(itype) )
+               p->b_const.fconst.cd[1] = imagp->b_const.fconst.ci;
+       else    p->b_const.fconst.cd[1] = imagp->b_const.fconst.cd[0];
+       }
+else
+       {
+       err("invalid complex constant");
+       p = errnode();
+       }
+
+frexpr(realp);
+frexpr(imagp);
+return(p);
+}
+
+
+struct bigblock *errnode()
+{
+struct bigblock *p;
+p = BALLO();
+p->tag = TERROR;
+p->vtype = TYERROR;
+return(p);
+}
+
+
+
+
+
+bigptr mkconv(t, p)
+register int t;
+register bigptr p;
+{
+register bigptr q;
+
+if(t==TYUNKNOWN || t==TYERROR)
+       fatal1("mkconv of impossible type %d", t);
+if(t == p->vtype)
+       return(p);
+
+else if( ISCONST(p) && p->vtype!=TYADDR)
+       {
+       q = mkconst(t);
+       consconv(t, &(q->b_const.fconst), p->vtype, &(p->b_const.fconst));
+       frexpr(p);
+       }
+else
+       {
+       q = mkexpr(OPCONV, p, 0);
+       q->vtype = t;
+       }
+return(q);
+}
+
+
+
+struct bigblock *addrof(p)
+bigptr p;
+{
+return( mkexpr(OPADDR, p, NULL) );
+}
+
+
+
+bigptr
+cpexpr(p)
+register bigptr p;
+{
+register bigptr e;
+int tag;
+register chainp ep, pp;
+
+#if 0
+static int blksize[ ] = { 0, sizeof(struct nameblock), sizeof(struct constblock),
+                sizeof(struct exprblock), sizeof(struct addrblock),
+                sizeof(struct primblock), sizeof(struct listblock),
+                sizeof(struct errorblock)
+       };
+#endif
+
+if(p == NULL)
+       return(NULL);
+
+if( (tag = p->tag) == TNAME)
+       return(p);
+
+#if 0
+e = cpblock( blksize[p->tag] , p);
+#else
+e = cpblock( sizeof(struct bigblock) , p);
+#endif
+
+switch(tag)
+       {
+       case TCONST:
+               if(e->vtype == TYCHAR)
+                       {
+                       e->b_const.fconst.ccp = copyn(1+strlen(e->b_const.fconst.ccp), e->b_const.fconst.ccp);
+                       e->vleng = cpexpr(e->vleng);
+                       }
+       case TERROR:
+               break;
+
+       case TEXPR:
+               e->b_expr.leftp = cpexpr(p->b_expr.leftp);
+               e->b_expr.rightp = cpexpr(p->b_expr.rightp);
+               break;
+
+       case TLIST:
+               if((pp = p->b_list.listp))
+                       {
+                       ep = e->b_list.listp = mkchain( cpexpr(pp->chain.datap), NULL);
+                       for(pp = pp->chain.nextp ; pp ; pp = pp->chain.nextp)
+                               ep = ep->chain.nextp = mkchain( cpexpr(pp->chain.datap), NULL);
+                       }
+               break;
+
+       case TADDR:
+               e->vleng = cpexpr(e->vleng);
+               e->b_addr.memoffset = cpexpr(e->b_addr.memoffset);
+               e->b_addr.istemp = NO;
+               break;
+
+       case TPRIM:
+               e->b_prim.argsp = cpexpr(e->b_prim.argsp);
+               e->b_prim.fcharp = cpexpr(e->b_prim.fcharp);
+               e->b_prim.lcharp = cpexpr(e->b_prim.lcharp);
+               break;
+
+       default:
+               fatal1("cpexpr: impossible tag %d", tag);
+       }
+
+return(e);
+}
+
+void
+frexpr(p)
+register bigptr p;
+{
+register chainp q;
+
+if(p == NULL)
+       return;
+
+switch(p->tag)
+       {
+       case TCONST:
+               if( ISCHAR(p) )
+                       {
+                       ckfree(p->b_const.fconst.ccp);
+                       frexpr(p->vleng);
+                       }
+               break;
+
+       case TADDR:
+               if(p->b_addr.istemp)
+                       {
+                       frtemp(p);
+                       return;
+                       }
+               frexpr(p->vleng);
+               frexpr(p->b_addr.memoffset);
+               break;
+
+       case TERROR:
+               break;
+
+       case TNAME:
+               return;
+
+       case TPRIM:
+               frexpr(p->b_prim.argsp);
+               frexpr(p->b_prim.fcharp);
+               frexpr(p->b_prim.lcharp);
+               break;
+
+       case TEXPR:
+               frexpr(p->b_expr.leftp);
+               if(p->b_expr.rightp)
+                       frexpr(p->b_expr.rightp);
+               break;
+
+       case TLIST:
+               for(q = p->b_list.listp ; q ; q = q->chain.nextp)
+                       frexpr(q->chain.datap);
+               frchain( &(p->b_list.listp) );
+               break;
+
+       default:
+               fatal1("frexpr: impossible tag %d", p->tag);
+       }
+
+ckfree(p);
+}
+\f
+/* fix up types in expression; replace subtrees and convert
+   names to address blocks */
+
+bigptr fixtype(p)
+register bigptr p;
+{
+
+if(p == 0)
+       return(0);
+
+switch(p->tag)
+       {
+       case TCONST:
+               if( ! ONEOF(p->vtype, MSKINT|MSKLOGICAL|MSKADDR) )
+                       p = putconst(p);
+               return(p);
+
+       case TADDR:
+               p->b_addr.memoffset = fixtype(p->b_addr.memoffset);
+               return(p);
+
+       case TERROR:
+               return(p);
+
+       default:
+               fatal1("fixtype: impossible tag %d", p->tag);
+
+       case TEXPR:
+               return( fixexpr(p) );
+
+       case TLIST:
+               return( p );
+
+       case TPRIM:
+               if(p->b_prim.argsp && p->b_prim.namep->vclass!=CLVAR)
+                       return( mkfunct(p) );
+               else    return( mklhs(p) );
+       }
+}
+
+
+
+
+
+/* special case tree transformations and cleanups of expression trees */
+
+bigptr fixexpr(p)
+register struct bigblock *p;
+{
+bigptr lp;
+register bigptr rp;
+register bigptr q;
+int opcode, ltype, rtype, ptype, mtype;
+
+if(p->tag == TERROR)
+       return(p);
+else if(p->tag != TEXPR)
+       fatal1("fixexpr: invalid tag %d", p->tag);
+opcode = p->b_expr.opcode;
+lp = p->b_expr.leftp = fixtype(p->b_expr.leftp);
+ltype = lp->vtype;
+if(opcode==OPASSIGN && lp->tag!=TADDR)
+       {
+       err("left side of assignment must be variable");
+       frexpr(p);
+       return( errnode() );
+       }
+
+if(p->b_expr.rightp)
+       {
+       rp = p->b_expr.rightp = fixtype(p->b_expr.rightp);
+       rtype = rp->vtype;
+       }
+else
+       {
+       rp = NULL;
+       rtype = 0;
+       }
+
+/* force folding if possible */
+if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) )
+       {
+       q = mkexpr(opcode, lp, rp);
+       if( ISCONST(q) )
+               return(q);
+       ckfree(q);      /* constants did not fold */
+       }
+
+if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR)
+       {
+       frexpr(p);
+       return( errnode() );
+       }
+
+switch(opcode)
+       {
+       case OPCONCAT:
+               if(p->vleng == NULL)
+                       p->vleng = mkexpr(OPPLUS, cpexpr(lp->vleng),
+                               cpexpr(rp->vleng) );
+               break;
+
+       case OPASSIGN:
+               if(ltype == rtype)
+                       break;
+               if( ! ISCONST(rp) && ISREAL(ltype) && ISREAL(rtype) )
+                       break;
+               if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) )
+                       break;
+               if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT)
+                   && typesize[ltype]>=typesize[rtype] )
+                       break;
+               p->b_expr.rightp = fixtype( mkconv(ptype, rp) );
+               break;
+
+       case OPSLASH:
+               if( ISCOMPLEX(rtype) )
+                       {
+                       p = call2(ptype, ptype==TYCOMPLEX? "c_div" : "z_div",
+                               mkconv(ptype, lp), mkconv(ptype, rp) );
+                       break;
+                       }
+       case OPPLUS:
+       case OPMINUS:
+       case OPSTAR:
+       case OPMOD:
+               if(ptype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp) ) ||
+                   (rtype==TYREAL && ! ISCONST(rp) ) ))
+                       break;
+               if( ISCOMPLEX(ptype) )
+                       break;
+               if(ltype != ptype)
+                       p->b_expr.leftp = fixtype(mkconv(ptype,lp));
+               if(rtype != ptype)
+                       p->b_expr.rightp = fixtype(mkconv(ptype,rp));
+               break;
+
+       case OPPOWER:
+               return( mkpower(p) );
+
+       case OPLT:
+       case OPLE:
+       case OPGT:
+       case OPGE:
+       case OPEQ:
+       case OPNE:
+               if(ltype == rtype)
+                       break;
+               mtype = cktype(OPMINUS, ltype, rtype);
+               if(mtype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp)) ||
+                   (rtype==TYREAL && ! ISCONST(rp)) ))
+                       break;
+               if( ISCOMPLEX(mtype) )
+                       break;
+               if(ltype != mtype)
+                       p->b_expr.leftp = fixtype(mkconv(mtype,lp));
+               if(rtype != mtype)
+                       p->b_expr.rightp = fixtype(mkconv(mtype,rp));
+               break;
+
+
+       case OPCONV:
+               ptype = cktype(OPCONV, p->vtype, ltype);
+               if(lp->tag==TEXPR && lp->b_expr.opcode==OPCOMMA)
+                       {
+                       lp->b_expr.rightp = fixtype( mkconv(ptype, lp->b_expr.rightp) );
+                       ckfree(p);
+                       p = lp;
+                       }
+               break;
+
+       case OPADDR:
+               if(lp->tag==TEXPR && lp->b_expr.opcode==OPADDR)
+                       fatal("addr of addr");
+               break;
+
+       case OPCOMMA:
+               break;
+
+       case OPMIN:
+       case OPMAX:
+               ptype = p->vtype;
+               break;
+
+       default:
+               break;
+       }
+
+p->vtype = ptype;
+return(p);
+}
+\f
+#if SZINT < SZLONG
+/*
+   for efficient subscripting, replace long ints by shorts
+   in easy places
+*/
+
+bigptr shorten(p)
+register bigptr p;
+{
+register bigptr q;
+
+if(p->vtype != TYLONG)
+       return(p);
+
+switch(p->tag)
+       {
+       case TERROR:
+       case TLIST:
+               return(p);
+
+       case TCONST:
+       case TADDR:
+               return( mkconv(TYINT,p) );
+
+       case TEXPR:
+               break;
+
+       default:
+               fatal1("shorten: invalid tag %d", p->tag);
+       }
+
+switch(p->opcode)
+       {
+       case OPPLUS:
+       case OPMINUS:
+       case OPSTAR:
+               q = shorten( cpexpr(p->rightp) );
+               if(q->vtype == TYINT)
+                       {
+                       p->leftp = shorten(p->leftp);
+                       if(p->leftp->vtype == TYLONG)
+                               frexpr(q);
+                       else
+                               {
+                               frexpr(p->rightp);
+                               p->rightp = q;
+                               p->vtype = TYINT;
+                               }
+                       }
+               break;
+
+       case OPNEG:
+               p->leftp = shorten(p->leftp);
+               if(p->leftp->vtype == TYINT)
+                       p->vtype = TYINT;
+               break;
+
+       case OPCALL:
+       case OPCCALL:
+               p = mkconv(TYINT,p);
+               break;
+       default:
+               break;
+       }
+
+return(p);
+}
+#endif
+
+int
+fixargs(doput, p0)
+int doput;
+struct bigblock *p0;
+{
+register chainp p;
+register bigptr q, t;
+register int qtag;
+int nargs;
+
+nargs = 0;
+if(p0)
+    for(p = p0->b_list.listp ; p ; p = p->chain.nextp)
+       {
+       ++nargs;
+       q = p->chain.datap;
+       qtag = q->tag;
+       if(qtag == TCONST)
+               {
+               if(q->vtype == TYSHORT)
+                       q = mkconv(tyint, q);
+               if(doput)
+                       p->chain.datap = putconst(q);
+               else
+                       p->chain.datap = q;
+               }
+       else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->vclass==CLPROC)
+               p->chain.datap = mkaddr(q->b_prim.namep);
+       else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdim!=NULL)
+               p->chain.datap = mkscalar(q->b_prim.namep);
+       else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdovar && 
+               (t = memversion(q->b_prim.namep)) )
+                       p->chain.datap = fixtype(t);
+       else    p->chain.datap = fixtype(q);
+       }
+return(nargs);
+}
+
+struct bigblock *
+mkscalar(np)
+register struct bigblock *np;
+{
+register struct bigblock *ap;
+
+vardcl(np);
+ap = mkaddr(np);
+
+#ifdef __vax__
+       /* on the VAX, prolog causes array arguments
+          to point at the (0,...,0) element, except when
+          subscript checking is on
+       */
+       if( !checksubs && np->vstg==STGARG)
+               {
+               register struct dimblock *dp;
+               dp = np->vdim;
+               frexpr(ap->memoffset);
+               ap->memoffset = mkexpr(OPSTAR, MKICON(typesize[np->vtype]),
+                                       cpexpr(dp->baseoffset) );
+               }
+#endif
+return(ap);
+}
+
+
+
+
+
+bigptr mkfunct(p)
+register struct bigblock * p;
+{
+chainp ep;
+struct bigblock *ap;
+struct extsym *extp;
+register struct bigblock *np;
+register struct bigblock *q;
+int k, nargs;
+int class;
+
+np = p->b_prim.namep;
+class = np->vclass;
+
+if(class == CLUNKNOWN)
+       {
+       np->vclass = class = CLPROC;
+       if(np->vstg == STGUNKNOWN)
+               {
+               if((k = intrfunct(np->b_name.varname)))
+                       {
+                       np->vstg = STGINTR;
+                       np->b_name.vardesc.varno = k;
+                       np->b_name.vprocclass = PINTRINSIC;
+                       }
+               else
+                       {
+                       extp = mkext( varunder(VL,np->b_name.varname) );
+                       extp->extstg = STGEXT;
+                       np->vstg = STGEXT;
+                       np->b_name.vardesc.varno = extp - extsymtab;
+                       np->b_name.vprocclass = PEXTERNAL;
+                       }
+               }
+       else if(np->vstg==STGARG)
+               {
+               if(np->vtype!=TYCHAR && !ftn66flag)
+                   warn("Dummy procedure not declared EXTERNAL. Code may be wrong.");
+               np->b_name.vprocclass = PEXTERNAL;
+               }
+       }
+
+if(class != CLPROC)
+       fatal1("invalid class code for function", class);
+if(p->b_prim.fcharp || p->b_prim.lcharp)
+       {
+       err("no substring of function call");
+       goto error;
+       }
+impldcl(np);
+nargs = fixargs( np->b_name.vprocclass!=PINTRINSIC,  p->b_prim.argsp);
+
+switch(np->b_name.vprocclass)
+       {
+       case PEXTERNAL:
+               ap = mkaddr(np);
+       call:
+               q = mkexpr(OPCALL, ap, p->b_prim.argsp);
+               q->vtype = np->vtype;
+               if(np->vleng)
+                       q->vleng = cpexpr(np->vleng);
+               break;
+
+       case PINTRINSIC:
+               q = intrcall(np, p->b_prim.argsp, nargs);
+               break;
+
+       case PSTFUNCT:
+               q = stfcall(np, p->b_prim.argsp);
+               break;
+
+       case PTHISPROC:
+               warn("recursive call");
+               for(ep = entries ; ep ; ep = ep->entrypoint.nextp)
+                       if(ep->entrypoint.enamep == np)
+                               break;
+               if(ep == NULL)
+                       fatal("mkfunct: impossible recursion");
+               ap = builtin(np->vtype, varstr(XL, ep->entrypoint.entryname->extname) );
+               goto call;
+
+       default:
+               fatal1("mkfunct: impossible vprocclass %d", np->b_name.vprocclass);
+               q = 0; /* XXX gcc */
+       }
+ckfree(p);
+return(q);
+
+error:
+       frexpr(p);
+       return( errnode() );
+}
+
+
+
+LOCAL struct bigblock *
+stfcall(struct bigblock *np, struct bigblock *actlist)
+{
+       register chainp actuals;
+       int nargs;
+       chainp oactp, formals;
+       int type;
+       struct bigblock *q, *rhs;
+       bigptr ap;
+       register chainp rp;
+       chainp tlist;
+
+       if(actlist) {
+               actuals = actlist->b_list.listp;
+               ckfree(actlist);
+       } else
+               actuals = NULL;
+       oactp = actuals;
+
+       nargs = 0;
+       tlist = NULL;
+       type = np->vtype;
+
+       formals = (chainp)np->b_name.vardesc.vstfdesc->chain.datap;
+       rhs = (bigptr)np->b_name.vardesc.vstfdesc->chain.nextp;
+
+       /* copy actual arguments into temporaries */
+       while(actuals!=NULL && formals!=NULL) {
+               rp = ALLOC(rplblock);
+               rp->rplblock.rplnp = q = formals->chain.datap;
+               ap = fixtype(actuals->chain.datap);
+               if(q->vtype==ap->vtype && q->vtype!=TYCHAR
+                  && (ap->tag==TCONST || ap->tag==TADDR) ) {
+                       rp->rplblock.rplvp = ap;
+                       rp->rplblock.rplxp = NULL;
+                       rp->rplblock.rpltag = ap->tag;
+               } else  {
+                       rp->rplblock.rplvp = fmktemp(q->vtype, q->vleng);
+                       rp->rplblock.rplxp = fixtype( mkexpr(OPASSIGN,
+                           cpexpr(rp->rplblock.rplvp), ap) );
+                       if( (rp->rplblock.rpltag =
+                           rp->rplblock.rplxp->tag) == TERROR)
+                               err("disagreement of argument types in statement function call");
+               }
+               rp->rplblock.nextp = tlist;
+               tlist = rp;
+               actuals = actuals->chain.nextp;
+               formals = formals->chain.nextp;
+               ++nargs;
+       }
+
+       if(actuals!=NULL || formals!=NULL)
+               err("statement function definition and argument list differ");
+
+       /*
+          now push down names involved in formal argument list, then
+          evaluate rhs of statement function definition in this environment
+       */
+       rpllist = hookup(tlist, rpllist);
+       q = mkconv(type, fixtype(cpexpr(rhs)) );
+
+       /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */
+       while(--nargs >= 0) {
+               if(rpllist->rplblock.rplxp)
+                       q = mkexpr(OPCOMMA, rpllist->rplblock.rplxp, q);
+               rp = rpllist->rplblock.nextp;
+               frexpr(rpllist->rplblock.rplvp);
+               ckfree(rpllist);
+               rpllist = rp;
+       }
+
+       frchain( &oactp );
+       return(q);
+}
+
+
+
+
+struct bigblock *
+mklhs(struct bigblock *p)
+{
+       struct bigblock *s;
+       struct bigblock *np;
+       chainp rp;
+       int regn;
+
+       /* first fixup name */
+
+       if(p->tag != TPRIM)
+               return(p);
+
+       np = p->b_prim.namep;
+
+       /* is name on the replace list? */
+
+       for(rp = rpllist ; rp ; rp = rp->rplblock.nextp) {
+               if(np == rp->rplblock.rplnp) {
+                       if(rp->rplblock.rpltag == TNAME) {
+                               np = p->b_prim.namep = rp->rplblock.rplvp;
+                               break;
+                       } else
+                               return( cpexpr(rp->rplblock.rplvp) );
+               }
+       }
+
+       /* is variable a DO index in a register ? */
+
+       if(np->b_name.vdovar && ( (regn = inregister(np)) >= 0) ) {
+               if(np->vtype == TYERROR)
+                       return( errnode() );
+               else {
+                       s = BALLO();
+                       s->tag = TADDR;
+                       s->vstg = STGREG;
+                       s->vtype = TYIREG;
+                       s->b_addr.memno = regn;
+                       s->b_addr.memoffset = MKICON(0);
+                       return(s);
+               }
+       }
+
+       vardcl(np);
+       s = mkaddr(np);
+       s->b_addr.memoffset = mkexpr(OPPLUS, s->b_addr.memoffset, suboffset(p) );
+       frexpr(p->b_prim.argsp);
+       p->b_prim.argsp = NULL;
+
+       /* now do substring part */
+
+       if(p->b_prim.fcharp || p->b_prim.lcharp) {
+               if(np->vtype != TYCHAR)
+                       err1("substring of noncharacter %s",
+                           varstr(VL,np->b_name.varname));
+               else    {
+                       if(p->b_prim.lcharp == NULL)
+                               p->b_prim.lcharp = cpexpr(s->vleng);
+                       if(p->b_prim.fcharp)
+                               s->vleng = mkexpr(OPMINUS, p->b_prim.lcharp,
+                                       mkexpr(OPMINUS, p->b_prim.fcharp, MKICON(1) ));
+                       else    {
+                               frexpr(s->vleng);
+                               s->vleng = p->b_prim.lcharp;
+                       }
+               }
+       }
+
+       s->vleng = fixtype( s->vleng );
+       s->b_addr.memoffset = fixtype( s->b_addr.memoffset );
+       ckfree(p);
+       return(s);
+}
+
+
+
+
+void
+deregister(np)
+struct bigblock *np;
+{
+}
+
+
+
+
+struct bigblock *memversion(np)
+register struct bigblock *np;
+{
+register struct bigblock *s;
+
+if(np->b_name.vdovar==NO || (inregister(np)<0) )
+       return(NULL);
+np->b_name.vdovar = NO;
+s = mklhs( mkprim(np, 0,0,0) );
+np->b_name.vdovar = YES;
+return(s);
+}
+
+
+int
+inregister(np)
+register struct bigblock *np;
+{
+return(-1);
+}
+
+
+
+int
+enregister(np)
+struct bigblock *np;
+{
+       return(NO);
+}
+
+
+
+
+bigptr suboffset(p)
+register struct bigblock *p;
+{
+int n;
+bigptr size;
+chainp cp;
+bigptr offp, prod;
+struct dimblock *dimp;
+bigptr sub[8];
+register struct bigblock *np;
+
+np = p->b_prim.namep;
+offp = MKICON(0);
+n = 0;
+if(p->b_prim.argsp)
+       for(cp = p->b_prim.argsp->b_list.listp ; cp ; cp = cp->chain.nextp)
+               {
+               sub[n++] = fixtype(cpexpr(cp->chain.datap));
+               if(n > 7)
+                       {
+                       err("more than 7 subscripts");
+                       break;
+                       }
+               }
+
+dimp = np->b_name.vdim;
+if(n>0 && dimp==NULL)
+       err("subscripts on scalar variable");
+else if(dimp && dimp->ndim!=n)
+       err1("wrong number of subscripts on %s",
+               varstr(VL, np->b_name.varname) );
+else if(n > 0)
+       {
+       prod = sub[--n];
+       while( --n >= 0)
+               prod = mkexpr(OPPLUS, sub[n],
+                       mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) );
+#ifdef __vax__
+       if(checksubs || np->vstg!=STGARG)
+               prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset));
+#else
+       prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset));
+#endif
+       if(checksubs)
+               prod = subcheck(np, prod);
+       if(np->vtype == TYCHAR)
+               size = cpexpr(np->vleng);
+       else    size = MKICON( typesize[np->vtype] );
+       prod = mkexpr(OPSTAR, prod, size);
+       offp = mkexpr(OPPLUS, offp, prod);
+       }
+
+if(p->b_prim.fcharp && np->vtype==TYCHAR)
+       offp = mkexpr(OPPLUS, offp, mkexpr(OPMINUS, cpexpr(p->b_prim.fcharp), MKICON(1) ));
+
+return(offp);
+}
+
+
+/*
+ * Check if an array is addressed out of bounds.
+ */
+bigptr
+subcheck(struct bigblock *np, bigptr p)
+{
+       struct dimblock *dimp;
+       bigptr t, badcall;
+       int l1, l2;
+
+       dimp = np->b_name.vdim;
+       if(dimp->nelt == NULL)
+               return(p);      /* don't check arrays with * bounds */
+       if( ISICON(p) ) {
+               if(p->b_const.fconst.ci < 0)
+                       goto badsub;
+               if( ISICON(dimp->nelt) ) {
+                       if(p->b_const.fconst.ci < dimp->nelt->b_const.fconst.ci)
+                               return(p);
+                       else
+                               goto badsub;
+               }
+       }
+
+       if (p->tag==TADDR && p->vstg==STGREG) {
+               t = p;
+       } else {
+               t = fmktemp(p->vtype, NULL);
+               putexpr(mkexpr(OPASSIGN, cpexpr(t), p));
+       }
+       /* t now cotains evaluated expression */
+
+       l1 = newlabel();
+       l2 = newlabel();
+       putif(mkexpr(OPLT, cpexpr(t), cpexpr(dimp->nelt)), l1);
+       putif(mkexpr(OPGE, cpexpr(t), MKICON(0)), l1);
+       putgoto(l2);
+       putlabel(l1);
+       
+       badcall = call4(t->vtype, "s_rnge", mkstrcon(VL, np->b_name.varname),
+               mkconv(TYLONG,  cpexpr(t)),
+               mkstrcon(XL, procname), MKICON(lineno));
+       badcall->b_expr.opcode = OPCCALL;
+
+       putexpr(badcall);
+       putlabel(l2);
+       return t;
+
+badsub:
+       frexpr(p);
+       err1("subscript on variable %s out of range",
+           varstr(VL,np->b_name.varname));
+       return ( MKICON(0) );
+}
+
+
+
+
+struct bigblock *mkaddr(p)
+register struct bigblock *p;
+{
+struct extsym *extp;
+register struct bigblock *t;
+
+switch( p->vstg)
+       {
+       case STGUNKNOWN:
+               if(p->vclass != CLPROC)
+                       break;
+               extp = mkext( varunder(VL, p->b_name.varname) );
+               extp->extstg = STGEXT;
+               p->vstg = STGEXT;
+               p->b_name.vardesc.varno = extp - extsymtab;
+               p->b_name.vprocclass = PEXTERNAL;
+
+       case STGCOMMON:
+       case STGEXT:
+       case STGBSS:
+       case STGINIT:
+       case STGEQUIV:
+       case STGARG:
+       case STGLENG:
+       case STGAUTO:
+               t = BALLO();
+               t->tag = TADDR;
+               t->vclass = p->vclass;
+               t->vtype = p->vtype;
+               t->vstg = p->vstg;
+               t->b_addr.memno = p->b_name.vardesc.varno;
+               t->b_addr.memoffset = MKICON(p->b_name.voffset);
+               if(p->vleng)
+                       t->vleng = cpexpr(p->vleng);
+               return(t);
+
+       case STGINTR:
+               return( intraddr(p) );
+
+       }
+/*debug*/ fprintf(diagfile, "mkaddr. vtype=%d, vclass=%d\n", p->vtype, p->vclass);
+fatal1("mkaddr: impossible storage tag %d", p->vstg);
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+
+
+struct bigblock *
+mkarg(type, argno)
+int type, argno;
+{
+register struct bigblock *p;
+
+p = BALLO();
+p->tag = TADDR;
+p->vtype = type;
+p->vclass = CLVAR;
+p->vstg = (type==TYLENG ? STGLENG : STGARG);
+p->b_addr.memno = argno;
+return(p);
+}
+
+
+
+
+bigptr mkprim(v, args, lstr, rstr)
+register bigptr v;
+struct bigblock *args;
+bigptr lstr, rstr;
+{
+register struct bigblock *p;
+
+if(v->vclass == CLPARAM)
+       {
+       if(args || lstr || rstr)
+               {
+               err1("no qualifiers on parameter name", varstr(VL,v->b_name.varname));
+               frexpr(args);
+               frexpr(lstr);
+               frexpr(rstr);
+               frexpr(v);
+               return( errnode() );
+               }
+       return( cpexpr(v->b_param.paramval) );
+       }
+
+p = BALLO();
+p->tag = TPRIM;
+p->vtype = v->vtype;
+p->b_prim.namep = v;
+p->b_prim.argsp = args;
+p->b_prim.fcharp = lstr;
+p->b_prim.lcharp = rstr;
+return(p);
+}
+
+
+void
+vardcl(v)
+register struct bigblock *v;
+{
+int nelt;
+struct dimblock *t;
+struct bigblock *p;
+bigptr neltp;
+
+if(v->b_name.vdcldone) return;
+
+if(v->vtype == TYUNKNOWN)
+       impldcl(v);
+if(v->vclass == CLUNKNOWN)
+       v->vclass = CLVAR;
+else if(v->vclass!=CLVAR && v->b_name.vprocclass!=PTHISPROC)
+       {
+       dclerr("used as variable", v);
+       return;
+       }
+if(v->vstg==STGUNKNOWN)
+       v->vstg = implstg[ letter(v->b_name.varname[0]) ];
+
+switch(v->vstg)
+       {
+       case STGBSS:
+               v->b_name.vardesc.varno = ++lastvarno;
+               break;
+       case STGAUTO:
+               if(v->vclass==CLPROC && v->b_name.vprocclass==PTHISPROC)
+                       break;
+               nelt = 1;
+               if((t = v->b_name.vdim)) {
+                       if( (neltp = t->nelt) && ISCONST(neltp) )
+                               nelt = neltp->b_const.fconst.ci;
+                       else
+                               dclerr("adjustable automatic array", v);
+               }
+               p = autovar(nelt, v->vtype, v->vleng);
+               v->b_name.voffset = p->b_addr.memoffset->b_const.fconst.ci;
+               frexpr(p);
+               break;
+
+       default:
+               break;
+       }
+v->b_name.vdcldone = YES;
+}
+
+
+
+void
+impldcl(p)
+register struct bigblock *p;
+{
+register int k;
+int type, leng;
+
+if(p->b_name.vdcldone || (p->vclass==CLPROC && p->b_name.vprocclass==PINTRINSIC) )
+       return;
+if(p->vtype == TYUNKNOWN)
+       {
+       k = letter(p->b_name.varname[0]);
+       type = impltype[ k ];
+       leng = implleng[ k ];
+       if(type == TYUNKNOWN)
+               {
+               if(p->vclass == CLPROC)
+                       return;
+               dclerr("attempt to use undefined variable", p);
+               type = TYERROR;
+               leng = 1;
+               }
+       settype(p, type, leng);
+       }
+}
+
+
+
+
+LOCAL int
+letter(c)
+register int c;
+{
+if( isupper(c) )
+       c = tolower(c);
+return(c - 'a');
+}
+\f
+#define ICONEQ(z, c)  (ISICON(z) && z->b_const.fconst.ci==c)
+#define COMMUTE        { e = lp;  lp = rp;  rp = e; }
+
+
+struct bigblock * 
+mkexpr(opcode, lp, rp)
+int opcode;
+register bigptr lp, rp;
+{
+register struct bigblock *e, *e1;
+int etype;
+int ltype, rtype;
+int ltag, rtag;
+
+ltype = lp->vtype;
+ltag = lp->tag;
+if(rp && opcode!=OPCALL && opcode!=OPCCALL)
+       {
+       rtype = rp->vtype;
+       rtag = rp->tag;
+       }
+else  rtype = rtag = 0;
+
+etype = cktype(opcode, ltype, rtype);
+if(etype == TYERROR)
+       goto error;
+
+switch(opcode)
+       {
+       /* check for multiplication by 0 and 1 and addition to 0 */
+
+       case OPSTAR:
+               if( ISCONST(lp) )
+                       COMMUTE
+
+               if( ISICON(rp) )
+                       {
+                       if(rp->b_const.fconst.ci == 0)
+                               goto retright;
+                       goto mulop;
+                       }
+               break;
+
+       case OPSLASH:
+       case OPMOD:
+               if( ICONEQ(rp, 0) )
+                       {
+                       err("attempted division by zero");
+                       rp = MKICON(1);
+                       break;
+                       }
+               if(opcode == OPMOD)
+                       break;
+
+
+       mulop:
+               if( ISICON(rp) )
+                       {
+                       if(rp->b_const.fconst.ci == 1)
+                               goto retleft;
+
+                       if(rp->b_const.fconst.ci == -1)
+                               {
+                               frexpr(rp);
+                               return( mkexpr(OPNEG, lp, 0) );
+                               }
+                       }
+
+               if( ISSTAROP(lp) && ISICON(lp->b_expr.rightp) )
+                       {
+                       if(opcode == OPSTAR)
+                               e = mkexpr(OPSTAR, lp->b_expr.rightp, rp);
+                       else  if(ISICON(rp) && lp->b_expr.rightp->b_const.fconst.ci % rp->b_const.fconst.ci == 0)
+                               e = mkexpr(OPSLASH, lp->b_expr.rightp, rp);
+                       else    break;
+
+                       e1 = lp->b_expr.leftp;
+                       ckfree(lp);
+                       return( mkexpr(OPSTAR, e1, e) );
+                       }
+               break;
+
+
+       case OPPLUS:
+               if( ISCONST(lp) )
+                       COMMUTE
+               goto addop;
+
+       case OPMINUS:
+               if( ICONEQ(lp, 0) )
+                       {
+                       frexpr(lp);
+                       return( mkexpr(OPNEG, rp, 0) );
+                       }
+
+               if( ISCONST(rp) )
+                       {
+                       opcode = OPPLUS;
+                       consnegop(rp);
+                       }
+
+       addop:
+               if( ISICON(rp) )
+                       {
+                       if(rp->b_const.fconst.ci == 0)
+                               goto retleft;
+                       if( ISPLUSOP(lp) && ISICON(lp->b_expr.rightp) )
+                               {
+                               e = mkexpr(OPPLUS, lp->b_expr.rightp, rp);
+                               e1 = lp->b_expr.leftp;
+                               ckfree(lp);
+                               return( mkexpr(OPPLUS, e1, e) );
+                               }
+                       }
+               break;
+
+
+       case OPPOWER:
+               break;
+
+       case OPNEG:
+               if(ltag==TEXPR && lp->b_expr.opcode==OPNEG)
+                       {
+                       e = lp->b_expr.leftp;
+                       ckfree(lp);
+                       return(e);
+                       }
+               break;
+
+       case OPNOT:
+               if(ltag==TEXPR && lp->b_expr.opcode==OPNOT)
+                       {
+                       e = lp->b_expr.leftp;
+                       ckfree(lp);
+                       return(e);
+                       }
+               break;
+
+       case OPCALL:
+       case OPCCALL:
+               etype = ltype;
+               if(rp!=NULL && rp->b_list.listp==NULL)
+                       {
+                       ckfree(rp);
+                       rp = NULL;
+                       }
+               break;
+
+       case OPAND:
+       case OPOR:
+               if( ISCONST(lp) )
+                       COMMUTE
+
+               if( ISCONST(rp) )
+                       {
+                       if(rp->b_const.fconst.ci == 0)
+                               if(opcode == OPOR)
+                                       goto retleft;
+                               else
+                                       goto retright;
+                       else if(opcode == OPOR)
+                               goto retright;
+                       else
+                               goto retleft;
+                       }
+       case OPEQV:
+       case OPNEQV:
+
+       case OPBITAND:
+       case OPBITOR:
+       case OPBITXOR:
+       case OPBITNOT:
+       case OPLSHIFT:
+       case OPRSHIFT:
+
+       case OPLT:
+       case OPGT:
+       case OPLE:
+       case OPGE:
+       case OPEQ:
+       case OPNE:
+
+       case OPCONCAT:
+               break;
+       case OPMIN:
+       case OPMAX:
+
+       case OPASSIGN:
+
+       case OPCONV:
+       case OPADDR:
+
+       case OPCOMMA:
+               break;
+
+       default:
+               fatal1("mkexpr: impossible opcode %d", opcode);
+       }
+
+e = BALLO();
+e->tag = TEXPR;
+e->b_expr.opcode = opcode;
+e->vtype = etype;
+e->b_expr.leftp = lp;
+e->b_expr.rightp = rp;
+if(ltag==TCONST && (rp==0 || rtag==TCONST) )
+       e = fold(e);
+return(e);
+
+retleft:
+       frexpr(rp);
+       return(lp);
+
+retright:
+       frexpr(lp);
+       return(rp);
+
+error:
+       frexpr(lp);
+       if(rp && opcode!=OPCALL && opcode!=OPCCALL)
+               frexpr(rp);
+       return( errnode() );
+}
+\f
+#define ERR(s)   { errs = s; goto error; }
+
+int
+cktype(op, lt, rt)
+register int op, lt, rt;
+{
+char *errs = NULL; /* XXX gcc */
+
+if(lt==TYERROR || rt==TYERROR)
+       goto error1;
+
+if(lt==TYUNKNOWN)
+       return(TYUNKNOWN);
+if(rt==TYUNKNOWN)
+       if(op!=OPNOT && op!=OPBITNOT && op!=OPNEG && op!=OPCALL && op!=OPCCALL && op!=OPADDR)
+               return(TYUNKNOWN);
+
+switch(op)
+       {
+       case OPPLUS:
+       case OPMINUS:
+       case OPSTAR:
+       case OPSLASH:
+       case OPPOWER:
+       case OPMOD:
+               if( ISNUMERIC(lt) && ISNUMERIC(rt) )
+                       return( maxtype(lt, rt) );
+               ERR("nonarithmetic operand of arithmetic operator")
+
+       case OPNEG:
+               if( ISNUMERIC(lt) )
+                       return(lt);
+               ERR("nonarithmetic operand of negation")
+
+       case OPNOT:
+               if(lt == TYLOGICAL)
+                       return(TYLOGICAL);
+               ERR("NOT of nonlogical")
+
+       case OPAND:
+       case OPOR:
+       case OPEQV:
+       case OPNEQV:
+               if(lt==TYLOGICAL && rt==TYLOGICAL)
+                       return(TYLOGICAL);
+               ERR("nonlogical operand of logical operator")
+
+       case OPLT:
+       case OPGT:
+       case OPLE:
+       case OPGE:
+       case OPEQ:
+       case OPNE:
+               if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL)
+                       {
+                       if(lt != rt)
+                               ERR("illegal comparison")
+                       }
+
+               else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) )
+                       {
+                       if(op!=OPEQ && op!=OPNE)
+                               ERR("order comparison of complex data")
+                       }
+
+               else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) )
+                       ERR("comparison of nonarithmetic data")
+               return(TYLOGICAL);
+
+       case OPCONCAT:
+               if(lt==TYCHAR && rt==TYCHAR)
+                       return(TYCHAR);
+               ERR("concatenation of nonchar data")
+
+       case OPCALL:
+       case OPCCALL:
+               return(lt);
+
+       case OPADDR:
+               return(TYADDR);
+
+       case OPCONV:
+               if(rt == 0)
+                       return(0);
+       case OPASSIGN:
+               if( ISINT(lt) && rt==TYCHAR)
+                       return(lt);
+               if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL)
+                       if(op!=OPASSIGN || lt!=rt)
+                               {
+/* debug fprintf(diagfile, " lt=%d, rt=%d, op=%d\n", lt, rt, op); */
+/* debug fatal("impossible conversion.  possible compiler bug"); */
+                               ERR("impossible conversion")
+                               }
+               return(lt);
+
+       case OPMIN:
+       case OPMAX:
+       case OPBITOR:
+       case OPBITAND:
+       case OPBITXOR:
+       case OPBITNOT:
+       case OPLSHIFT:
+       case OPRSHIFT:
+               return(lt);
+
+       case OPCOMMA:
+               return(rt);
+
+       default:
+               fatal1("cktype: impossible opcode %d", op);
+       }
+error: err(errs);
+error1:        return(TYERROR);
+}
+\f
+LOCAL bigptr fold(e)
+register struct bigblock *e;
+{
+struct bigblock *p;
+register bigptr lp, rp;
+int etype, mtype, ltype, rtype, opcode;
+int i, ll, lr;
+char *q, *s;
+union constant lcon, rcon;
+
+opcode = e->b_expr.opcode;
+etype = e->vtype;
+
+lp = e->b_expr.leftp;
+ltype = lp->vtype;
+rp = e->b_expr.rightp;
+
+if(rp == 0)
+       switch(opcode)
+               {
+               case OPNOT:
+                       lp->b_const.fconst.ci = ! lp->b_const.fconst.ci;
+                       return(lp);
+
+               case OPBITNOT:
+                       lp->b_const.fconst.ci = ~ lp->b_const.fconst.ci;
+                       return(lp);
+
+               case OPNEG:
+                       consnegop(lp);
+                       return(lp);
+
+               case OPCONV:
+               case OPADDR:
+                       return(e);
+
+               default:
+                       fatal1("fold: invalid unary operator %d", opcode);
+               }
+
+rtype = rp->vtype;
+
+p = BALLO();
+p->tag = TCONST;
+p->vtype = etype;
+p->vleng = e->vleng;
+
+switch(opcode)
+       {
+       case OPCOMMA:
+               return(e);
+
+       case OPAND:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci && rp->b_const.fconst.ci;
+               break;
+
+       case OPOR:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci || rp->b_const.fconst.ci;
+               break;
+
+       case OPEQV:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci == rp->b_const.fconst.ci;
+               break;
+
+       case OPNEQV:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci != rp->b_const.fconst.ci;
+               break;
+
+       case OPBITAND:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci & rp->b_const.fconst.ci;
+               break;
+
+       case OPBITOR:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci | rp->b_const.fconst.ci;
+               break;
+
+       case OPBITXOR:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci ^ rp->b_const.fconst.ci;
+               break;
+
+       case OPLSHIFT:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci << rp->b_const.fconst.ci;
+               break;
+
+       case OPRSHIFT:
+               p->b_const.fconst.ci = lp->b_const.fconst.ci >> rp->b_const.fconst.ci;
+               break;
+
+       case OPCONCAT:
+               ll = lp->vleng->b_const.fconst.ci;
+               lr = rp->vleng->b_const.fconst.ci;
+               p->b_const.fconst.ccp = q = (char *) ckalloc(ll+lr);
+               p->vleng = MKICON(ll+lr);
+               s = lp->b_const.fconst.ccp;
+               for(i = 0 ; i < ll ; ++i)
+                       *q++ = *s++;
+               s = rp->b_const.fconst.ccp;
+               for(i = 0; i < lr; ++i)
+                       *q++ = *s++;
+               break;
+
+
+       case OPPOWER:
+               if( ! ISINT(rtype) )
+                       return(e);
+               conspower(&(p->b_const.fconst), lp, rp->b_const.fconst.ci);
+               break;
+
+
+       default:
+               if(ltype == TYCHAR)
+                       {
+                       lcon.ci = cmpstr(lp->b_const.fconst.ccp, rp->b_const.fconst.ccp,
+                                       lp->vleng->b_const.fconst.ci, rp->vleng->b_const.fconst.ci);
+                       rcon.ci = 0;
+                       mtype = tyint;
+                       }
+               else    {
+                       mtype = maxtype(ltype, rtype);
+                       consconv(mtype, &lcon, ltype, &(lp->b_const.fconst) );
+                       consconv(mtype, &rcon, rtype, &(rp->b_const.fconst) );
+                       }
+               consbinop(opcode, mtype, &(p->b_const.fconst), &lcon, &rcon);
+               break;
+       }
+
+frexpr(e);
+return(p);
+}
+
+
+
+/* assign constant l = r , doing coercion */
+void
+consconv(lt, lv, rt, rv)
+int lt, rt;
+register union constant *lv, *rv;
+{
+switch(lt)
+       {
+       case TYSHORT:
+       case TYLONG:
+               if( ISINT(rt) )
+                       lv->ci = rv->ci;
+               else    lv->ci = rv->cd[0];
+               break;
+
+       case TYCOMPLEX:
+       case TYDCOMPLEX:
+               switch(rt)
+                       {
+                       case TYSHORT:
+                       case TYLONG:
+                               /* fall through and do real assignment of
+                                  first element
+                               */
+                       case TYREAL:
+                       case TYDREAL:
+                               lv->cd[1] = 0; break;
+                       case TYCOMPLEX:
+                       case TYDCOMPLEX:
+                               lv->cd[1] = rv->cd[1]; break;
+                       }
+
+       case TYREAL:
+       case TYDREAL:
+               if( ISINT(rt) )
+                       lv->cd[0] = rv->ci;
+               else    lv->cd[0] = rv->cd[0];
+               break;
+
+       case TYLOGICAL:
+               lv->ci = rv->ci;
+               break;
+       }
+}
+
+
+void
+consnegop(p)
+register struct bigblock *p;
+{
+switch(p->vtype)
+       {
+       case TYSHORT:
+       case TYLONG:
+               p->b_const.fconst.ci = - p->b_const.fconst.ci;
+               break;
+
+       case TYCOMPLEX:
+       case TYDCOMPLEX:
+               p->b_const.fconst.cd[1] = - p->b_const.fconst.cd[1];
+               /* fall through and do the real parts */
+       case TYREAL:
+       case TYDREAL:
+               p->b_const.fconst.cd[0] = - p->b_const.fconst.cd[0];
+               break;
+       default:
+               fatal1("consnegop: impossible type %d", p->vtype);
+       }
+}
+
+
+
+LOCAL void
+conspower(powp, ap, n)
+register union constant *powp;
+struct bigblock *ap;
+ftnint n;
+{
+register int type;
+union constant x;
+
+switch(type = ap->vtype)       /* pow = 1 */ 
+       {
+       case TYSHORT:
+       case TYLONG:
+               powp->ci = 1;
+               break;
+       case TYCOMPLEX:
+       case TYDCOMPLEX:
+               powp->cd[1] = 0;
+       case TYREAL:
+       case TYDREAL:
+               powp->cd[0] = 1;
+               break;
+       default:
+               fatal1("conspower: invalid type %d", type);
+       }
+
+if(n == 0)
+       return;
+if(n < 0)
+       {
+       if( ISINT(type) )
+               {
+               err("integer ** negative power ");
+               return;
+               }
+       n = - n;
+       consbinop(OPSLASH, type, &x, powp, &(ap->b_const.fconst));
+       }
+else
+       consbinop(OPSTAR, type, &x, powp, &(ap->b_const.fconst));
+
+for( ; ; )
+       {
+       if(n & 01)
+               consbinop(OPSTAR, type, powp, powp, &x);
+       if(n >>= 1)
+               consbinop(OPSTAR, type, &x, &x, &x);
+       else
+               break;
+       }
+}
+
+
+
+/* do constant operation cp = a op b */
+
+
+LOCAL void
+consbinop(opcode, type, cp, ap, bp)
+int opcode, type;
+register union constant *ap, *bp, *cp;
+{
+int k;
+double temp;
+
+switch(opcode)
+       {
+       case OPPLUS:
+               switch(type)
+                       {
+                       case TYSHORT:
+                       case TYLONG:
+                               cp->ci = ap->ci + bp->ci;
+                               break;
+                       case TYCOMPLEX:
+                       case TYDCOMPLEX:
+                               cp->cd[1] = ap->cd[1] + bp->cd[1];
+                       case TYREAL:
+                       case TYDREAL:
+                               cp->cd[0] = ap->cd[0] + bp->cd[0];
+                               break;
+                       }
+               break;
+
+       case OPMINUS:
+               switch(type)
+                       {
+                       case TYSHORT:
+                       case TYLONG:
+                               cp->ci = ap->ci - bp->ci;
+                               break;
+                       case TYCOMPLEX:
+                       case TYDCOMPLEX:
+                               cp->cd[1] = ap->cd[1] - bp->cd[1];
+                       case TYREAL:
+                       case TYDREAL:
+                               cp->cd[0] = ap->cd[0] - bp->cd[0];
+                               break;
+                       }
+               break;
+
+       case OPSTAR:
+               switch(type)
+                       {
+                       case TYSHORT:
+                       case TYLONG:
+                               cp->ci = ap->ci * bp->ci;
+                               break;
+                       case TYREAL:
+                       case TYDREAL:
+                               cp->cd[0] = ap->cd[0] * bp->cd[0];
+                               break;
+                       case TYCOMPLEX:
+                       case TYDCOMPLEX:
+                               temp = ap->cd[0] * bp->cd[0] -
+                                           ap->cd[1] * bp->cd[1] ;
+                               cp->cd[1] = ap->cd[0] * bp->cd[1] +
+                                           ap->cd[1] * bp->cd[0] ;
+                               cp->cd[0] = temp;
+                               break;
+                       }
+               break;
+       case OPSLASH:
+               switch(type)
+                       {
+                       case TYSHORT:
+                       case TYLONG:
+                               cp->ci = ap->ci / bp->ci;
+                               break;
+                       case TYREAL:
+                       case TYDREAL:
+                               cp->cd[0] = ap->cd[0] / bp->cd[0];
+                               break;
+                       case TYCOMPLEX:
+                       case TYDCOMPLEX:
+                               zdiv(&cp->dc, &ap->dc, &bp->dc);
+                               break;
+                       }
+               break;
+
+       case OPMOD:
+               if( ISINT(type) )
+                       {
+                       cp->ci = ap->ci % bp->ci;
+                       break;
+                       }
+               else
+                       fatal("inline mod of noninteger");
+
+       default:          /* relational ops */
+               switch(type)
+                       {
+                       case TYSHORT:
+                       case TYLONG:
+                               if(ap->ci < bp->ci)
+                                       k = -1;
+                               else if(ap->ci == bp->ci)
+                                       k = 0;
+                               else    k = 1;
+                               break;
+                       case TYREAL:
+                       case TYDREAL:
+                               if(ap->cd[0] < bp->cd[0])
+                                       k = -1;
+                               else if(ap->cd[0] == bp->cd[0])
+                                       k = 0;
+                               else    k = 1;
+                               break;
+                       case TYCOMPLEX:
+                       case TYDCOMPLEX:
+                               if(ap->cd[0] == bp->cd[0] &&
+                                  ap->cd[1] == bp->cd[1] )
+                                       k = 0;
+                               else    k = 1;
+                               break;
+                       default: /* XXX gcc */
+                               k = 0;
+                               break;
+                       }
+
+               switch(opcode)
+                       {
+                       case OPEQ:
+                               cp->ci = (k == 0);
+                               break;
+                       case OPNE:
+                               cp->ci = (k != 0);
+                               break;
+                       case OPGT:
+                               cp->ci = (k == 1);
+                               break;
+                       case OPLT:
+                               cp->ci = (k == -1);
+                               break;
+                       case OPGE:
+                               cp->ci = (k >= 0);
+                               break;
+                       case OPLE:
+                               cp->ci = (k <= 0);
+                               break;
+                       }
+               break;
+       }
+}
+
+
+
+int
+conssgn(p)
+register bigptr p;
+{
+if( ! ISCONST(p) )
+       fatal( "sgn(nonconstant)" );
+
+switch(p->vtype)
+       {
+       case TYSHORT:
+       case TYLONG:
+               if(p->b_const.fconst.ci > 0) return(1);
+               if(p->b_const.fconst.ci < 0) return(-1);
+               return(0);
+
+       case TYREAL:
+       case TYDREAL:
+               if(p->b_const.fconst.cd[0] > 0) return(1);
+               if(p->b_const.fconst.cd[0] < 0) return(-1);
+               return(0);
+
+       case TYCOMPLEX:
+       case TYDCOMPLEX:
+               return(p->b_const.fconst.cd[0]!=0 || p->b_const.fconst.cd[1]!=0);
+
+       default:
+               fatal1( "conssgn(type %d)", p->vtype);
+       }
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+\f
+char *powint[ ] = { "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" };
+
+
+LOCAL bigptr mkpower(p)
+register struct bigblock *p;
+{
+register bigptr q, lp, rp;
+int ltype, rtype, mtype;
+
+lp = p->b_expr.leftp;
+rp = p->b_expr.rightp;
+ltype = lp->vtype;
+rtype = rp->vtype;
+
+if(ISICON(rp))
+       {
+       if(rp->b_const.fconst.ci == 0)
+               {
+               frexpr(p);
+               if( ISINT(ltype) )
+                       return( MKICON(1) );
+               else
+                       return( putconst( mkconv(ltype, MKICON(1))) );
+               }
+       if(rp->b_const.fconst.ci < 0)
+               {
+               if( ISINT(ltype) )
+                       {
+                       frexpr(p);
+                       err("integer**negative");
+                       return( errnode() );
+                       }
+               rp->b_const.fconst.ci = - rp->b_const.fconst.ci;
+               p->b_expr.leftp = lp = fixexpr(mkexpr(OPSLASH, MKICON(1), lp));
+               }
+       if(rp->b_const.fconst.ci == 1)
+               {
+               frexpr(rp);
+               ckfree(p);
+               return(lp);
+               }
+
+       if( ONEOF(ltype, MSKINT|MSKREAL) )
+               {
+               p->vtype = ltype;
+               return(p);
+               }
+       }
+if( ISINT(rtype) )
+       {
+       if(ltype==TYSHORT && rtype==TYSHORT)
+               q = call2(TYSHORT, "pow_hh", lp, rp);
+       else    {
+               if(ltype == TYSHORT)
+                       {
+                       ltype = TYLONG;
+                       lp = mkconv(TYLONG,lp);
+                       }
+               q = call2(ltype, powint[ltype-TYLONG], lp, mkconv(TYLONG, rp));
+               }
+       }
+else if( ISREAL( (mtype = maxtype(ltype,rtype)) ))
+       q = call2(mtype, "pow_dd",
+               mkconv(TYDREAL,lp), mkconv(TYDREAL,rp));
+else   {
+       q = call2(TYDCOMPLEX, "pow_zz",
+               mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp));
+       if(mtype == TYCOMPLEX)
+               q = mkconv(TYCOMPLEX, q);
+       }
+ckfree(p);
+return(q);
+}
+\f
+
+
+/* Complex Division.  Same code as in Runtime Library
+*/
+
+
+
+LOCAL void
+zdiv(c, a, b)
+register struct dcomplex *a, *b, *c;
+{
+double ratio, den;
+double abr, abi;
+
+if( (abr = b->dreal) < 0.)
+       abr = - abr;
+if( (abi = b->dimag) < 0.)
+       abi = - abi;
+if( abr <= abi )
+       {
+       if(abi == 0)
+               fatal("complex division by zero");
+       ratio = b->dreal / b->dimag ;
+       den = b->dimag * (1 + ratio*ratio);
+       c->dreal = (a->dreal*ratio + a->dimag) / den;
+       c->dimag = (a->dimag*ratio - a->dreal) / den;
+       }
+
+else
+       {
+       ratio = b->dimag / b->dreal ;
+       den = b->dreal * (1 + ratio*ratio);
+       c->dreal = (a->dreal + a->dimag*ratio) / den;
+       c->dimag = (a->dimag - a->dreal*ratio) / den;
+       }
+
+}
diff --git a/lang/pcc/pcc/f77/fcom/ftypes.h b/lang/pcc/pcc/f77/fcom/ftypes.h
new file mode 100644 (file)
index 0000000..81468ab
--- /dev/null
@@ -0,0 +1,82 @@
+/*     $Id: ftypes.h,v 1.5 2008/12/19 08:08:48 ragge Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* variable types
+ * numeric assumptions:
+ *     int < reals < complexes
+ *     TYDREAL-TYREAL = TYDCOMPLEX-TYCOMPLEX
+ */
+
+#ifndef _FTYPES_H_
+#define _FTYPES_H_
+
+
+#define TYUNKNOWN 0
+#define TYADDR 1
+#define TYSHORT 2
+#define TYLONG 3
+#define TYREAL 4
+#define TYDREAL 5
+#define TYCOMPLEX 6
+#define TYDCOMPLEX 7
+#define TYLOGICAL 8
+#define TYCHAR 9
+#define TYSUBR 10
+#define TYERROR 11
+
+#define NTYPES (TYERROR+1)
+
+/*
+ * Type conversion from pcc to f77 internal format.
+ */
+#define        FSZADDR         (SZPOINT(0)/SZCHAR) /* XXX - typecheck? */
+#define        FSZSHORT        (SZSHORT/SZCHAR)
+#define        FSZINT          (SZINT/SZCHAR)
+#define        FSZLONG         (SZLONG/SZCHAR)
+#define        ALIADDR         (ALPOINT/ALCHAR)
+#define        ALISHORT        (ALSHORT/ALCHAR)
+#define        ALILONG         (ALLONG/ALCHAR)
+#define        ALIDOUBLE       (ALDOUBLE/ALCHAR)
+
+#ifndef SZINT
+#include "macdefs.h"
+#endif
+#if SZINT == SZSHORT
+#define TYINT  TYSHORT
+#else /* SZLONG >= SZINT */
+#define        TYINT   TYLONG
+#endif
+
+#define TYLENG  TYLONG
+#endif /* !_FTYPES_H_ */
diff --git a/lang/pcc/pcc/f77/fcom/gram.dcl b/lang/pcc/pcc/f77/fcom/gram.dcl
new file mode 100644 (file)
index 0000000..493f7a9
--- /dev/null
@@ -0,0 +1,318 @@
+spec:    dcl
+       | common
+       | external
+       | intrinsic
+       | equivalence
+       | data
+       | implicit
+       | SSAVE
+               { saveall = YES; }
+       | SSAVE savelist
+       | SFORMAT
+               { fmtstmt(thislabel); setfmt(thislabel); }
+       | SPARAM in_dcl SLPAR paramlist SRPAR
+       ;
+
+dcl:     type name in_dcl dims lengspec
+               { settype($2, $1, $5);
+                 if(ndim>0) setbound($2,ndim,dims);
+               }
+       | dcl SCOMMA name dims lengspec
+               { settype($3, $1, $5);
+                 if(ndim>0) setbound($3,ndim,dims);
+               }
+       ;
+
+type:    typespec lengspec
+               { varleng = $2; }
+       ;
+
+typespec:  typename
+               { varleng = ($1<0 || $1==TYLONG ? 0 : typesize[$1]); }
+       ;
+
+typename:    SINTEGER  { $$ = TYLONG; }
+       | SREAL         { $$ = TYREAL; }
+       | SCOMPLEX      { $$ = TYCOMPLEX; }
+       | SDOUBLE       { $$ = TYDREAL; }
+       | SDCOMPLEX     { $$ = TYDCOMPLEX; }
+       | SLOGICAL      { $$ = TYLOGICAL; }
+       | SCHARACTER    { $$ = TYCHAR; }
+       | SUNDEFINED    { $$ = TYUNKNOWN; }
+       | SDIMENSION    { $$ = TYUNKNOWN; }
+       | SAUTOMATIC    { $$ = - STGAUTO; }
+       | SSTATIC       { $$ = - STGBSS; }
+       ;
+
+lengspec:
+               { $$ = varleng; }
+       | SSTAR expr
+               {
+                 if( ! ISICON($2) )
+                       {
+                       $$ = 0;
+                       dclerr("length must be an integer constant", 0);
+                       }
+                 else $$ = $2->b_const.fconst.ci;
+               }
+       | SSTAR SLPAR SSTAR SRPAR
+               { $$ = 0; }
+       ;
+
+common:          SCOMMON in_dcl var
+               { incomm( $$ = comblock(0, 0) , $3 ); }
+       | SCOMMON in_dcl comblock var
+               { $$ = $3;  incomm($3, $4); }
+       | common opt_comma comblock opt_comma var
+               { $$ = $3;  incomm($3, $5); }
+       | common SCOMMA var
+               { incomm($1, $3); }
+       ;
+
+comblock:  SCONCAT
+               { $$ = comblock(0, 0); }
+       | SSLASH SFNAME SSLASH
+               { $$ = comblock(toklen, token); }
+       ;
+
+external: SEXTERNAL in_dcl name
+               { setext($3); }
+       | external SCOMMA name
+               { setext($3); }
+       ;
+
+intrinsic:  SINTRINSIC in_dcl name
+               { setintr($3); }
+       | intrinsic SCOMMA name
+               { setintr($3); }
+       ;
+
+equivalence:  SEQUIV in_dcl equivset
+       | equivalence SCOMMA equivset
+       ;
+
+equivset:  SLPAR equivlist SRPAR
+               {
+               struct equivblock *p;
+               if(nequiv >= MAXEQUIV)
+                       fatal("too many equivalences");
+               p  =  & eqvclass[nequiv++];
+               p->eqvinit = 0;
+               p->eqvbottom = 0;
+               p->eqvtop = 0;
+               p->equivs = $2;
+               }
+       ;
+
+equivlist:  lhs
+               { $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $1; }
+       | equivlist SCOMMA lhs
+               { $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $3; $$->eqvchain.nextp = $1; }
+       ;
+
+data:    SDATA in_data datalist
+       | data opt_comma datalist
+       ;
+
+in_data:
+               { if(parstate == OUTSIDE)
+                       {
+                       newproc();
+                       startproc(0, CLMAIN);
+                       }
+                 if(parstate < INDATA)
+                       {
+                       enddcl();
+                       parstate = INDATA;
+                       }
+               }
+       ;
+
+datalist:  datavarlist SSLASH vallist SSLASH
+               { ftnint junk;
+                 if(nextdata(&junk,&junk) != NULL)
+                       {
+                       err("too few initializers");
+                       curdtp = NULL;
+                       }
+                 frdata($1);
+                 frrpl();
+               }
+       ;
+
+vallist:  { toomanyinit = NO; }  val
+       | vallist SCOMMA val
+       ;
+
+val:     value
+               { dataval(NULL, $1); }
+       | simple SSTAR value
+               { dataval($1, $3); }
+       ;
+
+value:   simple
+       | addop simple
+               { if( $1==OPMINUS && ISCONST($2) )
+                       consnegop($2);
+                 $$ = $2;
+               }
+       | complex_const
+       | bit_const
+       ;
+
+savelist: saveitem
+       | savelist SCOMMA saveitem
+       ;
+
+saveitem: name
+               { int k;
+                 $1->b_name.vsave = 1;
+                 k = $1->vstg;
+               if( ! ONEOF(k, M(STGUNKNOWN)|M(STGBSS)|M(STGINIT)) )
+                       dclerr("can only save static variables", $1);
+               }
+       | comblock
+               { $1->extsave = 1; }
+       ;
+
+paramlist:  paramitem
+       | paramlist SCOMMA paramitem
+       ;
+
+paramitem:  name SEQUALS expr
+               { if($1->vclass == CLUNKNOWN)
+                       { $1->vclass = CLPARAM;
+                         $1->b_param.paramval = $3;
+                       }
+                 else dclerr("cannot make %s parameter", $1);
+               }
+       ;
+
+var:     name dims
+               { if(ndim>0) setbound($1, ndim, dims); }
+       ;
+
+datavar:         lhs
+               { struct bigblock *np;
+                 vardcl(np = $1->b_prim.namep);
+                 if(np->vstg == STGBSS)
+                       np->vstg = STGINIT;
+                 else if(np->vstg == STGCOMMON)
+                       extsymtab[np->b_name.vardesc.varno].extinit = YES;
+                 else if(np->vstg==STGEQUIV)
+                       eqvclass[np->b_name.vardesc.varno].eqvinit = YES;
+                 else if(np->vstg != STGINIT)
+                       dclerr("inconsistent storage classes", np);
+                 $$ = mkchain($1, 0);
+               }
+       | SLPAR datavarlist SCOMMA dospec SRPAR
+               { chainp p; struct bigblock *q;
+               q = BALLO();
+               q->tag = TIMPLDO;
+               q->b_impldo.varnp = $4->chain.datap;
+               p = $4->chain.nextp;
+               if(p)  { q->b_impldo.implb = p->chain.datap; p = p->chain.nextp; }
+               if(p)  { q->b_impldo.impub = p->chain.datap; p = p->chain.nextp; }
+               if(p)  { q->b_impldo.impstep = p->chain.datap; p = p->chain.nextp; }
+               frchain( & ($4) );
+               $$ = mkchain(q, 0);
+               q->b_impldo.datalist = hookup($2, $$);
+               }
+       ;
+
+datavarlist: datavar
+               { curdtp = $1; curdtelt = 0; }
+       | datavarlist SCOMMA datavar
+               { $$ = hookup($1, $3); }
+       ;
+
+dims:
+               { ndim = 0; }
+       | SLPAR dimlist SRPAR
+       ;
+
+dimlist:   { ndim = 0; }   dim
+       | dimlist SCOMMA dim
+       ;
+
+dim:     ubound
+               { dims[ndim].lb = 0;
+                 dims[ndim].ub = $1;
+                 ++ndim;
+               }
+       | expr SCOLON ubound
+               { dims[ndim].lb = $1;
+                 dims[ndim].ub = $3;
+                 ++ndim;
+               }
+       ;
+
+ubound:          SSTAR
+               { $$ = 0; }
+       | expr
+       ;
+
+labellist: label
+               { nstars = 1; labarray[0] = $1; }
+       | labellist SCOMMA label
+               { labarray[nstars++] = $3; }
+       ;
+
+label:   labelval
+               { if($1->labinacc)
+                       warn1("illegal branch to inner block, statement %s",
+                               convic( (ftnint) ($1->stateno) ));
+                 else if($1->labdefined == NO)
+                       $1->blklevel = blklevel;
+                 $1->labused = YES;
+               }
+       ;
+
+labelval:   SICON
+               { $$ = mklabel( convci(toklen, token) ); }
+       ;
+
+implicit:  SIMPLICIT in_dcl implist
+       | implicit SCOMMA implist
+       ;
+
+implist:  imptype SLPAR letgroups SRPAR
+       ;
+
+imptype:   { needkwd = 1; } type
+               { vartype = $2; }
+       ;
+
+letgroups: letgroup
+       | letgroups SCOMMA letgroup
+       ;
+
+letgroup:  letter
+               { setimpl(vartype, varleng, $1, $1); }
+       | letter SMINUS letter
+               { setimpl(vartype, varleng, $1, $3); }
+       ;
+
+letter:  SFNAME
+               { if(toklen!=1 || token[0]<'a' || token[0]>'z')
+                       {
+                       dclerr("implicit item must be single letter", 0);
+                       $$ = 0;
+                       }
+                 else $$ = token[0];
+               }
+       ;
+
+in_dcl:
+               { switch(parstate)      
+                       {
+                       case OUTSIDE:   newproc();
+                                       startproc(0, CLMAIN);
+                       case INSIDE:    parstate = INDCL;
+                       case INDCL:     break;
+
+                       default:
+                               dclerr("declaration among executables", 0);
+                       }
+               }
+       ;
diff --git a/lang/pcc/pcc/f77/fcom/gram.exec b/lang/pcc/pcc/f77/fcom/gram.exec
new file mode 100644 (file)
index 0000000..546f4b9
--- /dev/null
@@ -0,0 +1,112 @@
+exec:    iffable
+       | SDO end_spec label opt_comma dospec
+               {
+               if($3->labdefined)
+                       execerr("no backward DO loops");
+               $3->blklevel = blklevel+1;
+               exdo($3->labelno, $5);
+               }
+       | logif iffable
+               { exendif();  thiswasbranch = NO; }
+       | logif STHEN
+       | SELSEIF end_spec SLPAR expr SRPAR STHEN
+               { exelif($4); lastwasbranch = NO; }
+       | SELSE end_spec
+               { exelse(); lastwasbranch = NO; }
+       | SENDIF end_spec
+               { exendif(); lastwasbranch = NO; }
+       ;
+
+logif:   SLOGIF end_spec SLPAR expr SRPAR
+               { exif($4); }
+       ;
+
+dospec:          name SEQUALS exprlist
+               { $$ = mkchain($1, $3); }
+       ;
+
+iffable:  let lhs SEQUALS expr
+               { exequals($2, $4); }
+       | SASSIGN end_spec labelval STO name
+               { exassign($5, $3); }
+       | SCONTINUE end_spec
+       | goto
+       | io
+               { inioctl = NO; }
+       | SARITHIF end_spec SLPAR expr SRPAR label SCOMMA label SCOMMA label
+               { exarif($4, $6, $8, $10);  thiswasbranch = YES; }
+       | call
+               { excall($1, 0, 0, labarray); }
+       | call SLPAR SRPAR
+               { excall($1, 0, 0, labarray); }
+       | call SLPAR callarglist SRPAR
+               { excall($1, mklist($3), nstars, labarray); }
+       | SRETURN end_spec opt_expr
+               { exreturn($3);  thiswasbranch = YES; }
+       | stop end_spec opt_expr
+               { exstop($1, $3);  thiswasbranch = $1; }
+       ;
+
+let:     SLET
+               { if(parstate == OUTSIDE)
+                       {
+                       newproc();
+                       startproc(0, CLMAIN);
+                       }
+               }
+       ;
+
+goto:    SGOTO end_spec label
+               { exgoto($3);  thiswasbranch = YES; }
+       | SASGOTO end_spec name
+               { exasgoto($3);  thiswasbranch = YES; }
+       | SASGOTO end_spec name opt_comma SLPAR labellist SRPAR
+               { exasgoto($3);  thiswasbranch = YES; }
+       | SCOMPGOTO end_spec SLPAR labellist SRPAR opt_comma expr
+               { putcmgo(fixtype($7), nstars, labarray); }
+       ;
+
+opt_comma:
+       | SCOMMA
+       ;
+
+call:    SCALL end_spec name
+               { nstars = 0; $$ = $3; }
+       ;
+
+callarglist:  callarg
+               { $$ = ($1 ? mkchain($1,0) : 0); }
+       | callarglist SCOMMA callarg
+               { if($3) {
+                       if($1) $$ = hookup($1, mkchain($3,0));
+                       else $$ = mkchain($3,0);
+               }
+               }
+       ;
+
+callarg:  expr
+       | SSTAR label
+               { labarray[nstars++] = $2; $$ = 0; }
+       ;
+
+stop:    SPAUSE
+               { $$ = 0; }
+       | SSTOP
+               { $$ = 1; }
+       ;
+
+exprlist:  expr
+               { $$ = mkchain($1, 0); }
+       | exprlist SCOMMA expr
+               { $$ = hookup($1, mkchain($3,0) ); }
+       ;
+
+end_spec:
+               { if(parstate == OUTSIDE)
+                       {
+                       newproc();
+                       startproc(0, CLMAIN);
+                       }
+                 if(parstate < INDATA) enddcl();
+               }
+       ;
diff --git a/lang/pcc/pcc/f77/fcom/gram.expr b/lang/pcc/pcc/f77/fcom/gram.expr
new file mode 100644 (file)
index 0000000..e8977a7
--- /dev/null
@@ -0,0 +1,125 @@
+funarglist:
+               { $$ = 0; }
+       | funargs
+       ;
+
+funargs:  expr
+               { $$ = mkchain($1, 0); }
+       | funargs SCOMMA expr
+               { $$ = hookup($1, mkchain($3,0) ); }
+       ;
+
+
+expr:    uexpr
+       | SLPAR expr SRPAR      { $$ = $2; }
+       | complex_const
+       ;
+
+uexpr:   lhs
+       | simple_const
+       | expr addop expr   %prec SPLUS
+               { $$ = mkexpr($2, $1, $3); }
+       | expr SSTAR expr
+               { $$ = mkexpr(OPSTAR, $1, $3); }
+       | expr SSLASH expr
+               { $$ = mkexpr(OPSLASH, $1, $3); }
+       | expr SPOWER expr
+               { $$ = mkexpr(OPPOWER, $1, $3); }
+       | addop expr  %prec SSTAR
+               { if($1 == OPMINUS)
+                       $$ = mkexpr(OPNEG, $2, 0);
+                 else  $$ = $2;
+               }
+       | expr relop expr  %prec SEQ
+               { $$ = mkexpr($2, $1, $3); }
+       | expr SEQV expr
+               { $$ = mkexpr(OPEQV, $1,$3); }
+       | expr SNEQV expr
+               { $$ = mkexpr(OPNEQV, $1, $3); }
+       | expr SOR expr
+               { $$ = mkexpr(OPOR, $1, $3); }
+       | expr SAND expr
+               { $$ = mkexpr(OPAND, $1, $3); }
+       | SNOT expr
+               { $$ = mkexpr(OPNOT, $2, 0); }
+       | expr SCONCAT expr
+               { $$ = mkexpr(OPCONCAT, $1, $3); }
+       ;
+
+addop:   SPLUS         { $$ = OPPLUS; }
+       | SMINUS        { $$ = OPMINUS; }
+       ;
+
+relop:   SEQ   { $$ = OPEQ; }
+       | SGT   { $$ = OPGT; }
+       | SLT   { $$ = OPLT; }
+       | SGE   { $$ = OPGE; }
+       | SLE   { $$ = OPLE; }
+       | SNE   { $$ = OPNE; }
+       ;
+
+lhs:    name
+               { $$ = mkprim($1, 0, 0, 0); }
+       | name SLPAR opt_expr SCOLON opt_expr SRPAR
+               { $$ = mkprim($1, 0, $3, $5); }
+       | name SLPAR funarglist SRPAR
+               { $$ = mkprim($1, mklist($3), 0, 0); }
+       | name SLPAR funarglist SRPAR SLPAR opt_expr SCOLON opt_expr SRPAR
+               { $$ = mkprim($1, mklist($3), $6, $8); }
+       ;
+
+opt_expr:
+               { $$ = 0; }
+       | expr
+       ;
+
+simple:          name
+               { if($1->vclass == CLPARAM)
+                       $$ = cpexpr($1->b_param.paramval);
+               }
+       | simple_const
+       ;
+
+simple_const:   STRUE  { $$ = mklogcon(1); }
+       | SFALSE        { $$ = mklogcon(0); }
+       | SHOLLERITH  { $$ = mkstrcon(toklen, token); }
+       | SICON { $$ = mkintcon( convci(toklen, token) ); }
+       | SRCON { $$ = mkrealcon(TYREAL, convcd(toklen, token)); }
+       | SDCON { $$ = mkrealcon(TYDREAL, convcd(toklen, token)); }
+       ;
+
+complex_const:  SLPAR uexpr SCOMMA uexpr SRPAR
+               { $$ = mkcxcon($2,$4); }
+       ;
+
+bit_const:  SHEXCON
+               { $$ = mkbitcon(4, toklen, token); }
+       | SOCTCON
+               { $$ = mkbitcon(3, toklen, token); }
+       | SBITCON
+               { $$ = mkbitcon(1, toklen, token); }
+       ;
+
+fexpr:   unpar_fexpr
+       | SLPAR fexpr SRPAR
+               { $$ = $2; }
+       ;
+
+unpar_fexpr:     lhs
+       | simple_const
+       | fexpr addop fexpr   %prec SPLUS
+               { $$ = mkexpr($2, $1, $3); }
+       | fexpr SSTAR fexpr
+               { $$ = mkexpr(OPSTAR, $1, $3); }
+       | fexpr SSLASH fexpr
+               { $$ = mkexpr(OPSLASH, $1, $3); }
+       | fexpr SPOWER fexpr
+               { $$ = mkexpr(OPPOWER, $1, $3); }
+       | addop fexpr  %prec SSTAR
+               { if($1 == OPMINUS)
+                       $$ = mkexpr(OPNEG, $2, 0);
+                 else  $$ = $2;
+               }
+       | fexpr SCONCAT fexpr
+               { $$ = mkexpr(OPCONCAT, $1, $3); }
+       ;
diff --git a/lang/pcc/pcc/f77/fcom/gram.head b/lang/pcc/pcc/f77/fcom/gram.head
new file mode 100644 (file)
index 0000000..07d5d30
--- /dev/null
@@ -0,0 +1,174 @@
+%{
+
+#include "defines.h"
+#include "defs.h"
+
+static int nstars;
+static int ndim;
+static int vartype;
+static ftnint varleng;
+struct uux dims[8];
+static struct labelblock *labarray[100];
+static int lastwasbranch = NO;
+static int thiswasbranch = NO;
+
+%}
+
+/* Specify precedences and associativies. */
+
+%left SCOMMA
+%nonassoc SCOLON
+%right SEQUALS
+%left SEQV SNEQV
+%left SOR
+%left SAND
+%left SNOT
+%nonassoc SLT SGT SLE SGE SEQ SNE
+%left SCONCAT
+%left SPLUS SMINUS
+%left SSTAR SSLASH
+%right SPOWER
+
+%union {
+       struct labelblock *label;
+       struct extsym *extsym;
+
+       bigptr bigptr;
+       chainp chainp;
+
+       ftnint fint;
+       char *str;
+       char token;
+       int num;
+}
+
+%type <label>  thislabel label labelval
+%type <str>    filename
+%type <num>    SLABEL type dcl typename addop relop
+               stop nameeq
+%type <extsym> progname entryname common comblock
+%type <bigptr> name var call lhs simple inelt other bit_const
+               value simple_const complex_const arg
+%type <chainp> args datavarlist datavar dospec funarglist funargs exprlist
+               callarglist inlist outlist out2 equivlist arglist
+%type <fint>   lengspec
+%type <token>  letter
+%type <bigptr> uexpr callarg opt_expr unpar_fexpr ubound expr fexpr
+
+%%
+
+program:
+       | program stat SEOS
+       ;
+
+stat:    thislabel entry
+               { lastwasbranch = NO; }
+       | thislabel  spec
+       | thislabel  exec
+               { if($1 && ($1->labelno==dorange))
+                       enddo($1->labelno);
+                 if(lastwasbranch && thislabel==NULL)
+                       warn1("statement cannot be reached");
+                 lastwasbranch = thiswasbranch;
+                 thiswasbranch = NO;
+               }
+       | thislabel SINCLUDE filename
+               { doinclude( $3 ); }
+       | thislabel  SEND  end_spec
+               { lastwasbranch = NO;  endproc(); }
+       | thislabel SUNKNOWN
+               { execerr("unclassifiable statement", 0);  flline(); }
+       | error
+               { flline();  needkwd = NO;  inioctl = NO; 
+                 yyerrok; yyclearin; }
+       ;
+
+thislabel:  SLABEL
+               {
+               if($1)
+                       {
+                       $$ = thislabel =  mklabel( (ftnint) $1);
+                       if( ! headerdone )
+                               puthead(NULL);
+                       if(thislabel->labdefined)
+                               execerr("label %s already defined",
+                                       convic(thislabel->stateno) );
+                       else    {
+                               if(thislabel->blklevel!=0 && thislabel->blklevel<blklevel
+                                   && thislabel->labtype!=LABFORMAT)
+                                       warn1("there is a branch to label %s from outside block",
+                                             convic( (ftnint) (thislabel->stateno) ) );
+                               thislabel->blklevel = blklevel;
+                               thislabel->labdefined = YES;
+                               if(thislabel->labtype != LABFORMAT)
+                                       putlabel(thislabel->labelno);
+                               }
+                       }
+               else    $$ = thislabel = NULL;
+               }
+       ;
+
+entry:   SPROGRAM new_proc progname
+               { startproc($3, CLMAIN); }
+       | SBLOCK new_proc progname
+               { startproc($3, CLBLOCK); }
+       | SSUBROUTINE new_proc entryname arglist
+               { entrypt(CLPROC, TYSUBR, (ftnint) 0,  $3, $4); }
+       | SFUNCTION new_proc entryname arglist
+               { entrypt(CLPROC, TYUNKNOWN, (ftnint) 0, $3, $4); }
+       | type SFUNCTION new_proc entryname arglist
+               { entrypt(CLPROC, $1, varleng, $4, $5); }
+       | SENTRY entryname arglist
+               { if(parstate==OUTSIDE || procclass==CLMAIN
+                       || procclass==CLBLOCK)
+                               execerr("misplaced entry statement", 0);
+                 entrypt(CLENTRY, 0, (ftnint) 0, $2, $3);
+               }
+       ;
+
+new_proc:
+               { newproc(); }
+       ;
+
+entryname:  name
+               { $$ = newentry($1); }
+       ;
+
+name:    SFNAME
+               { $$ = mkname(toklen, token); }
+       ;
+
+progname:              { $$ = NULL; }
+       | entryname
+       ;
+
+arglist:
+               { $$ = 0; }
+       | SLPAR SRPAR
+               { $$ = 0; }
+       | SLPAR args SRPAR
+               {$$ = $2; }
+       ;
+
+args:    arg
+               { $$ = ($1 ? mkchain($1,0) : 0 ); }
+       | args SCOMMA arg
+               { if($3) $1 = $$ = hookup($1, mkchain($3,0)); }
+       ;
+
+arg:     name
+               { $1->vstg = STGARG; }
+       | SSTAR
+               { $$ = 0;  substars = YES; }
+       ;
+
+
+
+filename:   SHOLLERITH
+               {
+               char *s;
+               s = copyn(toklen+1, token);
+               s[toklen] = '\0';
+               $$ = s;
+               }
+       ;
diff --git a/lang/pcc/pcc/f77/fcom/gram.io b/lang/pcc/pcc/f77/fcom/gram.io
new file mode 100644 (file)
index 0000000..469214c
--- /dev/null
@@ -0,0 +1,156 @@
+  /*  Input/Output Statements */
+
+io:      io1
+               { endio(); }
+       ;
+
+io1:     iofmove ioctl
+       | iofmove unpar_fexpr
+               { ioclause(IOSUNIT, $2); endioctl(); }
+       | iofctl ioctl
+       | read ioctl
+               { doio(NULL); }
+       | read ioctl inlist
+               { doio($3); }
+       | read infmt SCOMMA inlist
+               { doio($4); }
+       | read ioctl SCOMMA inlist
+               { doio($4); }
+       | write ioctl
+               { doio(NULL); }
+       | write ioctl outlist
+               { doio($3); }
+       | print
+               { doio(NULL); }
+       | print SCOMMA outlist
+               { doio($3); }
+       ;
+
+iofmove:   fmkwd end_spec in_ioctl
+       ;
+
+fmkwd:   SBACKSPACE
+               { iostmt = IOREWIND; }
+       | SREWIND
+               { iostmt = IOREWIND; }
+       | SENDFILE
+               { iostmt = IOENDFILE; }
+       ;
+
+iofctl:  ctlkwd end_spec in_ioctl
+       ;
+
+ctlkwd:          SINQUIRE
+               { iostmt = IOINQUIRE; }
+       | SOPEN
+               { iostmt = IOOPEN; }
+       | SCLOSE
+               { iostmt = IOCLOSE; }
+       ;
+
+infmt:   unpar_fexpr
+               {
+               ioclause(IOSUNIT, NULL);
+               ioclause(IOSFMT, $1);
+               endioctl();
+               }
+       | SSTAR
+               {
+               ioclause(IOSUNIT, NULL);
+               ioclause(IOSFMT, NULL);
+               endioctl();
+               }
+       ;
+
+ioctl:   SLPAR fexpr SRPAR
+               { ioclause(IOSUNIT, $2); endioctl(); }
+       | SLPAR ctllist SRPAR
+               { endioctl(); }
+       ;
+
+ctllist:  ioclause SCOMMA ioclause
+       | ctllist SCOMMA ioclause
+       ;
+
+ioclause:  fexpr
+               { ioclause(IOSPOSITIONAL, $1); }
+       | SSTAR
+               { ioclause(IOSPOSITIONAL, NULL); }
+       | nameeq expr
+               { ioclause($1, $2); }
+       | nameeq SSTAR
+               { ioclause($1, NULL); }
+       ;
+
+nameeq:  SNAMEEQ
+               { $$ = iocname(); }
+       ;
+
+read:    SREAD end_spec in_ioctl
+               { iostmt = IOREAD; }
+       ;
+
+write:   SWRITE end_spec in_ioctl
+               { iostmt = IOWRITE; }
+       ;
+
+print:   SPRINT end_spec fexpr in_ioctl
+               {
+               iostmt = IOWRITE;
+               ioclause(IOSUNIT, NULL);
+               ioclause(IOSFMT, $3);
+               endioctl();
+               }
+       | SPRINT end_spec SSTAR in_ioctl
+               {
+               iostmt = IOWRITE;
+               ioclause(IOSUNIT, NULL);
+               ioclause(IOSFMT, NULL);
+               endioctl();
+               }
+       ;
+
+inlist:          inelt
+               { $$ = mkchain($1,0); }
+       | inlist SCOMMA inelt
+               { $$ = hookup($1, mkchain($3,0)); }
+       ;
+
+inelt:   lhs
+       | SLPAR inlist SCOMMA dospec SRPAR
+               { $$ = mkiodo($4,$2); }
+       ;
+
+outlist:  uexpr
+               { $$ = mkchain($1, 0); }
+       | other
+               { $$ = mkchain($1, 0); }
+       | out2
+       ;
+
+out2:    uexpr SCOMMA uexpr
+               { $$ = mkchain($1, mkchain($3, 0) ); }
+       | uexpr SCOMMA other
+               { $$ = mkchain($1, mkchain($3, 0) ); }
+       | other SCOMMA uexpr
+               { $$ = mkchain($1, mkchain($3, 0) ); }
+       | other SCOMMA other
+               { $$ = mkchain($1, mkchain($3, 0) ); }
+       | out2  SCOMMA uexpr
+               { $$ = hookup($1, mkchain($3, 0) ); }
+       | out2  SCOMMA other
+               { $$ = hookup($1, mkchain($3, 0) ); }
+       ;
+
+other:   complex_const
+       | SLPAR uexpr SCOMMA dospec SRPAR
+               { $$ = mkiodo($4, mkchain($2, 0) ); }
+       | SLPAR other SCOMMA dospec SRPAR
+               { $$ = mkiodo($4, mkchain($2, 0) ); }
+       | SLPAR out2  SCOMMA dospec SRPAR
+               { $$ = mkiodo($4, $2); }
+       ;
+
+in_ioctl:
+               { startioctl(); }
+       ;
diff --git a/lang/pcc/pcc/f77/fcom/init.c b/lang/pcc/pcc/f77/fcom/init.c
new file mode 100644 (file)
index 0000000..d76001e
--- /dev/null
@@ -0,0 +1,292 @@
+/*     $Id: init.c,v 1.16 2008/12/24 17:40:41 sgk Exp $        */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "defines.h"
+#include "defs.h"
+
+
+FILEP infile;
+FILEP diagfile;
+
+long int headoffset;
+
+char token[100];
+int toklen;
+int lineno;
+char *infname;
+int needkwd;
+struct labelblock *thislabel   = NULL;
+flag nowarnflag        = NO;
+flag ftn66flag = NO;
+flag profileflag       = NO;
+flag optimflag = NO;
+flag quietflag = NO;
+flag shiftcase = YES;
+flag undeftype = NO;
+flag shortsubs = YES;
+flag onetripflag       = NO;
+flag checksubs = NO;
+flag debugflag = NO;
+int nerr;
+int nwarn;
+int ndata;
+
+flag saveall;
+flag substars;
+int parstate   = OUTSIDE;
+flag headerdone        = NO;
+int blklevel;
+int impltype[26];
+int implleng[26];
+int implstg[26];
+
+int tyint      = TYLONG ;
+int tylogical  = TYLONG;
+ftnint typesize[NTYPES]
+       = { 1, FSZADDR, FSZSHORT, FSZLONG, FSZLONG, 2*FSZLONG,
+           2*FSZLONG, 4*FSZLONG, FSZLONG, 1, 1, 1};
+int typealign[NTYPES]
+       = { 1, ALIADDR, ALISHORT, ALILONG, ALILONG, ALIDOUBLE,
+           ALILONG, ALIDOUBLE, ALILONG, 1, 1, 1};
+int procno;
+int proctype   = TYUNKNOWN;
+char *procname;
+int rtvlabel[NTYPES];
+int fudgelabel;
+struct bigblock *typeaddr;
+struct bigblock *retslot;
+int cxslot     = -1;
+int chslot     = -1;
+int chlgslot   = -1;
+int procclass  = CLUNKNOWN;
+int nentry;
+flag multitype;
+ftnint procleng;
+int lastlabno  = 10;
+int lastvarno;
+int lastargslot;
+int argloc;
+ftnint autoleng;
+ftnint bssleng = 0;
+int retlabel;
+int ret0label;
+struct ctlframe ctls[MAXCTL];
+struct ctlframe *ctlstack      = ctls-1;
+struct ctlframe *lastctl       = ctls+MAXCTL ;
+
+bigptr regnamep[10]; /* XXX MAXREGVAR */
+int highregvar;
+
+struct extsym extsymtab[MAXEXT];
+struct extsym *nextext = extsymtab;
+struct extsym *lastext = extsymtab+MAXEXT;
+
+struct equivblock eqvclass[MAXEQUIV];
+struct hashentry hashtab[MAXHASH];
+struct hashentry *lasthash     = hashtab+MAXHASH;
+
+struct labelblock labeltab[MAXSTNO];
+struct labelblock *labtabend   = labeltab+MAXSTNO;
+struct labelblock *highlabtab =        labeltab;
+chainp rpllist = NULL;
+chainp curdtp  = NULL;
+flag toomanyinit;
+ftnint curdtelt;
+chainp templist        = NULL;
+chainp holdtemps       = NULL;
+int dorange    = 0;
+chainp entries = NULL;
+chainp chains  = NULL;
+
+flag inioctl;
+struct bigblock *ioblkp;
+int iostmt;
+int nioctl;
+int nequiv     = 0;
+int nintnames  = 0;
+int nextnames  = 0;
+
+struct literal litpool[MAXLITERALS];
+int nliterals;
+
+/*
+ * Return a number for internal labels.
+ */
+int getlab(void);
+
+int crslab = 10;
+int
+getlab(void)
+{
+       return crslab++;
+}
+
+
+void
+fileinit()
+{
+procno = 0;
+lastlabno = 10;
+lastvarno = 0;
+nextext = extsymtab;
+nliterals = 0;
+nerr = 0;
+ndata = 0;
+}
+
+
+
+
+void
+procinit()
+{
+register struct bigblock *p;
+register struct dimblock *q;
+register struct hashentry *hp;
+register struct labelblock *lp;
+chainp cp;
+int i;
+
+       setloc(RDATA);
+parstate = OUTSIDE;
+headerdone = NO;
+blklevel = 1;
+saveall = NO;
+substars = NO;
+nwarn = 0;
+thislabel = NULL;
+needkwd = 0;
+
+++procno;
+proctype = TYUNKNOWN;
+procname = "MAIN_    ";
+procclass = CLUNKNOWN;
+nentry = 0;
+multitype = NO;
+typeaddr = NULL;
+retslot = NULL;
+cxslot = -1;
+chslot = -1;
+chlgslot = -1;
+procleng = 0;
+blklevel = 1;
+lastargslot = 0;
+       autoleng = AUTOINIT;
+
+for(lp = labeltab ; lp < labtabend ; ++lp)
+       lp->stateno = 0;
+
+for(hp = hashtab ; hp < lasthash ; ++hp)
+       if((p = hp->varp))
+               {
+               frexpr(p->vleng);
+               if((q = p->b_name.vdim))
+                       {
+                       for(i = 0 ; i < q->ndim ; ++i)
+                               {
+                               frexpr(q->dims[i].dimsize);
+                               frexpr(q->dims[i].dimexpr);
+                               }
+                       frexpr(q->nelt);
+                       frexpr(q->baseoffset);
+                       frexpr(q->basexpr);
+                       ckfree(q);
+                       }
+               ckfree(p);
+               hp->varp = NULL;
+               }
+nintnames = 0;
+highlabtab = labeltab;
+
+ctlstack = ctls - 1;
+for(cp = templist ; cp ; cp = cp->chain.nextp)
+       ckfree(cp->chain.datap);
+frchain(&templist);
+holdtemps = NULL;
+dorange = 0;
+highregvar = 0;
+entries = NULL;
+rpllist = NULL;
+inioctl = NO;
+ioblkp = NULL;
+nequiv = 0;
+
+for(i = 0 ; i<NTYPES ; ++i)
+       rtvlabel[i] = 0;
+fudgelabel = 0;
+
+if(undeftype)
+       setimpl(TYUNKNOWN, (ftnint) 0, 'a', 'z');
+else
+       {
+       setimpl(TYREAL, (ftnint) 0, 'a', 'z');
+       setimpl(tyint,  (ftnint) 0, 'i', 'n');
+       }
+setimpl(-STGBSS, (ftnint) 0, 'a', 'z');        /* set class */
+setlog();
+}
+
+
+
+void
+setimpl(type, length, c1, c2)
+int type;
+ftnint length;
+int c1, c2;
+{
+int i;
+char buff[100];
+
+if(c1==0 || c2==0)
+       return;
+
+if(c1 > c2) {
+       sprintf(buff, "characters out of order in implicit:%c-%c", c1, c2);
+       err(buff);
+} else
+       if(type < 0)
+               for(i = c1 ; i<=c2 ; ++i)
+                       implstg[i-'a'] = - type;
+       else
+               {
+               type = lengtype(type, (int) length);
+               if(type != TYCHAR)
+                       length = 0;
+               for(i = c1 ; i<=c2 ; ++i)
+                       {
+                       impltype[i-'a'] = type;
+                       implleng[i-'a'] = length;
+                       }
+               }
+}
diff --git a/lang/pcc/pcc/f77/fcom/intr.c b/lang/pcc/pcc/f77/fcom/intr.c
new file mode 100644 (file)
index 0000000..3bc45b5
--- /dev/null
@@ -0,0 +1,606 @@
+/*     $Id: intr.c,v 1.13 2008/05/11 15:28:03 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defines.h"
+#include "defs.h"
+
+
+static struct bigblock *finline(int, int, chainp);
+
+union
+       {
+       int ijunk;
+       struct intrpacked bits;
+       } packed;
+
+struct intrbits
+       {
+       int intrgroup /* :3 */;
+       int intrstuff /* result type or number of generics */;
+       int intrno /* :7 */;
+       };
+
+LOCAL struct intrblock
+       {
+       char intrfname[VL];
+       struct intrbits intrval;
+       } intrtab[ ] =
+{
+{ "int",               { INTRCONV, TYLONG }, },
+{ "real",      { INTRCONV, TYREAL }, },
+{ "dble",      { INTRCONV, TYDREAL }, },
+{ "cmplx",     { INTRCONV, TYCOMPLEX }, },
+{ "dcmplx",    { INTRCONV, TYDCOMPLEX }, },
+{ "ifix",      { INTRCONV, TYLONG }, },
+{ "idint",     { INTRCONV, TYLONG }, },
+{ "float",     { INTRCONV, TYREAL }, },
+{ "dfloat",    { INTRCONV, TYDREAL }, },
+{ "sngl",      { INTRCONV, TYREAL }, },
+{ "ichar",     { INTRCONV, TYLONG }, },
+{ "char",      { INTRCONV, TYCHAR }, },
+
+{ "max",               { INTRMAX, TYUNKNOWN }, },
+{ "max0",      { INTRMAX, TYLONG }, },
+{ "amax0",     { INTRMAX, TYREAL }, },
+{ "max1",      { INTRMAX, TYLONG }, },
+{ "amax1",     { INTRMAX, TYREAL }, },
+{ "dmax1",     { INTRMAX, TYDREAL }, },
+
+{ "and",               { INTRBOOL, TYUNKNOWN, OPBITAND }, },
+{ "or",                { INTRBOOL, TYUNKNOWN, OPBITOR }, },
+{ "xor",               { INTRBOOL, TYUNKNOWN, OPBITXOR }, },
+{ "not",               { INTRBOOL, TYUNKNOWN, OPBITNOT }, },
+{ "lshift",    { INTRBOOL, TYUNKNOWN, OPLSHIFT }, },
+{ "rshift",    { INTRBOOL, TYUNKNOWN, OPRSHIFT }, },
+
+{ "min",               { INTRMIN, TYUNKNOWN }, },
+{ "min0",      { INTRMIN, TYLONG }, },
+{ "amin0",     { INTRMIN, TYREAL }, },
+{ "min1",      { INTRMIN, TYLONG }, },
+{ "amin1",     { INTRMIN, TYREAL }, },
+{ "dmin1",     { INTRMIN, TYDREAL }, },
+
+{ "aint",      { INTRGEN, 2, 0 }, },
+{ "dint",      { INTRSPEC, TYDREAL, 1 }, },
+
+{ "anint",     { INTRGEN, 2, 2 }, },
+{ "dnint",     { INTRSPEC, TYDREAL, 3 }, },
+
+{ "nint",      { INTRGEN, 4, 4 }, },
+{ "idnint",    { INTRGEN, 2, 6 }, },
+
+{ "abs",               { INTRGEN, 6, 8 }, },
+{ "iabs",      { INTRGEN, 2, 9 }, },
+{ "dabs",      { INTRSPEC, TYDREAL, 11 }, },
+{ "cabs",      { INTRSPEC, TYREAL, 12 }, },
+{ "zabs",      { INTRSPEC, TYDREAL, 13 }, },
+
+{ "mod",               { INTRGEN, 4, 14 }, },
+{ "amod",      { INTRSPEC, TYREAL, 16 }, },
+{ "dmod",      { INTRSPEC, TYDREAL, 17 }, },
+
+{ "sign",      { INTRGEN, 4, 18 }, },
+{ "isign",     { INTRGEN, 2, 19 }, },
+{ "dsign",     { INTRSPEC, TYDREAL, 21 }, },
+
+{ "dim",               { INTRGEN, 4, 22 }, },
+{ "idim",      { INTRGEN, 2, 23 }, },
+{ "ddim",      { INTRSPEC, TYDREAL, 25 }, },
+
+{ "dprod",     { INTRSPEC, TYDREAL, 26 }, },
+
+{ "len",               { INTRSPEC, TYLONG, 27 }, },
+{ "index",     { INTRSPEC, TYLONG, 29 }, },
+
+{ "imag",      { INTRGEN, 2, 31 }, },
+{ "aimag",     { INTRSPEC, TYREAL, 31 }, },
+{ "dimag",     { INTRSPEC, TYDREAL, 32 }, },
+
+{ "conjg",     { INTRGEN, 2, 33 }, },
+{ "dconjg",    { INTRSPEC, TYDCOMPLEX, 34 }, },
+
+{ "sqrt",      { INTRGEN, 4, 35 }, },
+{ "dsqrt",     { INTRSPEC, TYDREAL, 36 }, },
+{ "csqrt",     { INTRSPEC, TYCOMPLEX, 37 }, },
+{ "zsqrt",     { INTRSPEC, TYDCOMPLEX, 38 }, },
+
+{ "exp",               { INTRGEN, 4, 39 }, },
+{ "dexp",      { INTRSPEC, TYDREAL, 40 }, },
+{ "cexp",      { INTRSPEC, TYCOMPLEX, 41 }, },
+{ "zexp",      { INTRSPEC, TYDCOMPLEX, 42 }, },
+
+{ "log",               { INTRGEN, 4, 43 }, },
+{ "alog",      { INTRSPEC, TYREAL, 43 }, },
+{ "dlog",      { INTRSPEC, TYDREAL, 44 }, },
+{ "clog",      { INTRSPEC, TYCOMPLEX, 45 }, },
+{ "zlog",      { INTRSPEC, TYDCOMPLEX, 46 }, },
+
+{ "log10",     { INTRGEN, 2, 47 }, },
+{ "alog10",    { INTRSPEC, TYREAL, 47 }, },
+{ "dlog10",    { INTRSPEC, TYDREAL, 48 }, },
+
+{ "sin",               { INTRGEN, 4, 49 }, },
+{ "dsin",      { INTRSPEC, TYDREAL, 50 }, },
+{ "csin",      { INTRSPEC, TYCOMPLEX, 51 }, },
+{ "zsin",      { INTRSPEC, TYDCOMPLEX, 52 }, },
+
+{ "cos",               { INTRGEN, 4, 53 }, },
+{ "dcos",      { INTRSPEC, TYDREAL, 54 }, },
+{ "ccos",      { INTRSPEC, TYCOMPLEX, 55 }, },
+{ "zcos",      { INTRSPEC, TYDCOMPLEX, 56 }, },
+
+{ "tan",               { INTRGEN, 2, 57 }, },
+{ "dtan",      { INTRSPEC, TYDREAL, 58 }, },
+
+{ "asin",      { INTRGEN, 2, 59 }, },
+{ "dasin",     { INTRSPEC, TYDREAL, 60 }, },
+
+{ "acos",      { INTRGEN, 2, 61 }, },
+{ "dacos",     { INTRSPEC, TYDREAL, 62 }, },
+
+{ "atan",      { INTRGEN, 2, 63 }, },
+{ "datan",     { INTRSPEC, TYDREAL, 64 }, },
+
+{ "atan2",     { INTRGEN, 2, 65 }, },
+{ "datan2",    { INTRSPEC, TYDREAL, 66 }, },
+
+{ "sinh",      { INTRGEN, 2, 67 }, },
+{ "dsinh",     { INTRSPEC, TYDREAL, 68 }, },
+
+{ "cosh",      { INTRGEN, 2, 69 }, },
+{ "dcosh",     { INTRSPEC, TYDREAL, 70 }, },
+
+{ "tanh",      { INTRGEN, 2, 71 }, },
+{ "dtanh",     { INTRSPEC, TYDREAL, 72 }, },
+
+{ "lge",               { INTRSPEC, TYLOGICAL, 73}, },
+{ "lgt",               { INTRSPEC, TYLOGICAL, 75}, },
+{ "lle",               { INTRSPEC, TYLOGICAL, 77}, },
+{ "llt",               { INTRSPEC, TYLOGICAL, 79}, },
+
+{ "" }, };
+\f
+
+LOCAL struct specblock
+       {
+       char atype;
+       char rtype;
+       char nargs;
+       char spxname[XL];
+       char othername; /* index into callbyvalue table */
+       } spectab[ ] =
+{
+       { TYREAL,TYREAL,1,"r_int" },
+       { TYDREAL,TYDREAL,1,"d_int" },
+
+       { TYREAL,TYREAL,1,"r_nint" },
+       { TYDREAL,TYDREAL,1,"d_nint" },
+
+       { TYREAL,TYSHORT,1,"h_nint" },
+       { TYREAL,TYLONG,1,"i_nint" },
+
+       { TYDREAL,TYSHORT,1,"h_dnnt" },
+       { TYDREAL,TYLONG,1,"i_dnnt" },
+
+       { TYREAL,TYREAL,1,"r_abs" },
+       { TYSHORT,TYSHORT,1,"h_abs" },
+       { TYLONG,TYLONG,1,"i_abs" },
+       { TYDREAL,TYDREAL,1,"d_abs" },
+       { TYCOMPLEX,TYREAL,1,"c_abs" },
+       { TYDCOMPLEX,TYDREAL,1,"z_abs" },
+
+       { TYSHORT,TYSHORT,2,"h_mod" },
+       { TYLONG,TYLONG,2,"i_mod" },
+       { TYREAL,TYREAL,2,"r_mod" },
+       { TYDREAL,TYDREAL,2,"d_mod" },
+
+       { TYREAL,TYREAL,2,"r_sign" },
+       { TYSHORT,TYSHORT,2,"h_sign" },
+       { TYLONG,TYLONG,2,"i_sign" },
+       { TYDREAL,TYDREAL,2,"d_sign" },
+
+       { TYREAL,TYREAL,2,"r_dim" },
+       { TYSHORT,TYSHORT,2,"h_dim" },
+       { TYLONG,TYLONG,2,"i_dim" },
+       { TYDREAL,TYDREAL,2,"d_dim" },
+
+       { TYREAL,TYDREAL,2,"d_prod" },
+
+       { TYCHAR,TYSHORT,1,"h_len" },
+       { TYCHAR,TYLONG,1,"i_len" },
+
+       { TYCHAR,TYSHORT,2,"h_indx" },
+       { TYCHAR,TYLONG,2,"i_indx" },
+
+       { TYCOMPLEX,TYREAL,1,"r_imag" },
+       { TYDCOMPLEX,TYDREAL,1,"d_imag" },
+       { TYCOMPLEX,TYCOMPLEX,1,"r_cnjg" },
+       { TYDCOMPLEX,TYDCOMPLEX,1,"d_cnjg" },
+
+       { TYREAL,TYREAL,1,"r_sqrt", 1 },
+       { TYDREAL,TYDREAL,1,"d_sqrt", 1 },
+       { TYCOMPLEX,TYCOMPLEX,1,"c_sqrt" },
+       { TYDCOMPLEX,TYDCOMPLEX,1,"z_sqrt" },
+
+       { TYREAL,TYREAL,1,"r_exp", 2 },
+       { TYDREAL,TYDREAL,1,"d_exp", 2 },
+       { TYCOMPLEX,TYCOMPLEX,1,"c_exp" },
+       { TYDCOMPLEX,TYDCOMPLEX,1,"z_exp" },
+
+       { TYREAL,TYREAL,1,"r_log", 3 },
+       { TYDREAL,TYDREAL,1,"d_log", 3 },
+       { TYCOMPLEX,TYCOMPLEX,1,"c_log" },
+       { TYDCOMPLEX,TYDCOMPLEX,1,"z_log" },
+
+       { TYREAL,TYREAL,1,"r_lg10" },
+       { TYDREAL,TYDREAL,1,"d_lg10" },
+
+       { TYREAL,TYREAL,1,"r_sin", 4 },
+       { TYDREAL,TYDREAL,1,"d_sin", 4 },
+       { TYCOMPLEX,TYCOMPLEX,1,"c_sin" },
+       { TYDCOMPLEX,TYDCOMPLEX,1,"z_sin" },
+
+       { TYREAL,TYREAL,1,"r_cos", 5 },
+       { TYDREAL,TYDREAL,1,"d_cos", 5 },
+       { TYCOMPLEX,TYCOMPLEX,1,"c_cos" },
+       { TYDCOMPLEX,TYDCOMPLEX,1,"z_cos" },
+
+       { TYREAL,TYREAL,1,"r_tan", 6 },
+       { TYDREAL,TYDREAL,1,"d_tan", 6 },
+
+       { TYREAL,TYREAL,1,"r_asin", 7 },
+       { TYDREAL,TYDREAL,1,"d_asin", 7 },
+
+       { TYREAL,TYREAL,1,"r_acos", 8 },
+       { TYDREAL,TYDREAL,1,"d_acos", 8 },
+
+       { TYREAL,TYREAL,1,"r_atan", 9 },
+       { TYDREAL,TYDREAL,1,"d_atan", 9 },
+
+       { TYREAL,TYREAL,2,"r_atn2", 10 },
+       { TYDREAL,TYDREAL,2,"d_atn2", 10 },
+
+       { TYREAL,TYREAL,1,"r_sinh", 11 },
+       { TYDREAL,TYDREAL,1,"d_sinh", 11 },
+
+       { TYREAL,TYREAL,1,"r_cosh", 12 },
+       { TYDREAL,TYDREAL,1,"d_cosh", 12 },
+
+       { TYREAL,TYREAL,1,"r_tanh", 13 },
+       { TYDREAL,TYDREAL,1,"d_tanh", 13 },
+
+       { TYCHAR,TYLOGICAL,2,"hl_ge" },
+       { TYCHAR,TYLOGICAL,2,"l_ge" },
+
+       { TYCHAR,TYLOGICAL,2,"hl_gt" },
+       { TYCHAR,TYLOGICAL,2,"l_gt" },
+
+       { TYCHAR,TYLOGICAL,2,"hl_le" },
+       { TYCHAR,TYLOGICAL,2,"l_le" },
+
+       { TYCHAR,TYLOGICAL,2,"hl_lt" },
+       { TYCHAR,TYLOGICAL,2,"l_lt" }
+} ;
+
+
+
+
+
+
+char callbyvalue[ ][XL] =
+       {
+       "sqrt",
+       "exp",
+       "log",
+       "sin",
+       "cos",
+       "tan",
+       "asin",
+       "acos",
+       "atan",
+       "atan2",
+       "sinh",
+       "cosh",
+       "tanh"
+       };
+\f
+struct bigblock *
+intrcall(np, argsp, nargs)
+struct bigblock *np;
+struct bigblock *argsp;
+int nargs;
+{
+int i, rettype;
+struct bigblock *ap;
+register struct specblock *sp;
+struct bigblock *q;
+register chainp cp;
+bigptr ep;
+int mtype;
+int op;
+
+packed.ijunk = np->b_name.vardesc.varno;
+if(nargs == 0)
+       goto badnargs;
+
+mtype = 0;
+for(cp = argsp->b_list.listp ; cp ; cp = cp->chain.nextp)
+       {
+/* TEMPORARY */ ep = cp->chain.datap;
+/* TEMPORARY */        if( ISCONST(ep) && ep->vtype==TYSHORT )
+/* TEMPORARY */                cp->chain.datap = mkconv(tyint, ep);
+       mtype = maxtype(mtype, ep->vtype);
+       }
+
+switch(packed.bits.f1)
+       {
+       case INTRBOOL:
+               op = packed.bits.f3;
+               if( ! ONEOF(mtype, MSKINT|MSKLOGICAL) )
+                       goto badtype;
+               if(op == OPBITNOT)
+                       {
+                       if(nargs != 1)
+                               goto badnargs;
+                       q = mkexpr(OPBITNOT, argsp->b_list.listp->chain.datap, NULL);
+                       }
+               else
+                       {
+                       if(nargs != 2)
+                               goto badnargs;
+                       q = mkexpr(op, argsp->b_list.listp->chain.datap,
+                               argsp->b_list.listp->chain.nextp->chain.datap);
+                       }
+               frchain( &(argsp->b_list.listp) );
+               ckfree(argsp);
+               return(q);
+
+       case INTRCONV:
+               rettype = packed.bits.f2;
+               if(rettype == TYLONG)
+                       rettype = tyint;
+               if( ISCOMPLEX(rettype) && nargs==2)
+                       {
+                       bigptr qr, qi;
+                       qr = argsp->b_list.listp->chain.datap;
+                       qi = argsp->b_list.listp->chain.nextp->chain.datap;
+                       if(ISCONST(qr) && ISCONST(qi))
+                               q = mkcxcon(qr,qi);
+                       else    q = mkexpr(OPCONV,mkconv(rettype-2,qr),
+                                       mkconv(rettype-2,qi));
+                       }
+               else if(nargs == 1)
+                       q = mkconv(rettype, argsp->b_list.listp->chain.datap);
+               else goto badnargs;
+
+               q->vtype = rettype;
+               frchain(&(argsp->b_list.listp));
+               ckfree(argsp);
+               return(q);
+
+
+       case INTRGEN:
+               sp = spectab + packed.bits.f3;
+               for(i=0; i<packed.bits.f2 ; ++i)
+                       if(sp->atype == mtype) {
+                               if (tyint == TYLONG &&
+                                   sp->rtype == TYSHORT && 
+                                   sp[1].atype == mtype)
+                                       sp++; /* use long int */
+                               goto specfunct;
+                       } else
+                               ++sp;
+               goto badtype;
+
+       case INTRSPEC:
+               sp = spectab + packed.bits.f3;
+               if(tyint==TYLONG && sp->rtype==TYSHORT)
+                       ++sp;
+
+       specfunct:
+               if(nargs != sp->nargs)
+                       goto badnargs;
+               if(mtype != sp->atype)
+                       goto badtype;
+               fixargs(YES, argsp);
+               if((q = finline(sp-spectab, mtype, argsp->b_list.listp)))
+                       {
+                       frchain( &(argsp->b_list.listp) );
+                       ckfree(argsp);
+                       }
+               else if(sp->othername)
+                       {
+                       ap = builtin(sp->rtype,
+                               varstr(XL, callbyvalue[sp->othername-1]) );
+                       q = fixexpr( mkexpr(OPCCALL, ap, argsp) );
+                       }
+               else
+                       {
+                       ap = builtin(sp->rtype, varstr(XL, sp->spxname) );
+                       q = fixexpr( mkexpr(OPCALL, ap, argsp) );
+                       }
+               return(q);
+
+       case INTRMIN:
+       case INTRMAX:
+               if(nargs < 2)
+                       goto badnargs;
+               if( ! ONEOF(mtype, MSKINT|MSKREAL) )
+                       goto badtype;
+               argsp->vtype = mtype;
+               q = mkexpr( (packed.bits.f1==INTRMIN ? OPMIN : OPMAX), argsp, NULL);
+
+               q->vtype = mtype;
+               rettype = packed.bits.f2;
+               if(rettype == TYLONG)
+                       rettype = tyint;
+               else if(rettype == TYUNKNOWN)
+                       rettype = mtype;
+               return( mkconv(rettype, q) );
+
+       default:
+               fatal1("intrcall: bad intrgroup %d", packed.bits.f1);
+       }
+badnargs:
+       err1("bad number of arguments to intrinsic %s",
+               varstr(VL,np->b_name.varname) );
+       goto bad;
+
+badtype:
+       err1("bad argument type to intrinsic %s", varstr(VL, np->b_name.varname) );
+
+bad:
+       return( errnode() );
+}
+
+
+
+int
+intrfunct(s)
+char s[VL];
+{
+register struct intrblock *p;
+char nm[VL];
+register int i;
+
+for(i = 0 ; i<VL ; ++s)
+       nm[i++] = (*s==' ' ? '\0' : *s);
+
+for(p = intrtab; p->intrval.intrgroup!=INTREND ; ++p)
+       {
+       if( eqn(VL, nm, p->intrfname) )
+               {
+               packed.bits.f1 = p->intrval.intrgroup;
+               packed.bits.f2 = p->intrval.intrstuff;
+               packed.bits.f3 = p->intrval.intrno;
+               return(packed.ijunk);
+               }
+       }
+
+return(0);
+}
+
+
+
+
+
+struct bigblock *
+intraddr(np)
+struct bigblock *np;
+{
+struct bigblock *q;
+struct specblock *sp;
+
+if(np->vclass!=CLPROC || np->b_name.vprocclass!=PINTRINSIC)
+       fatal1("intraddr: %s is not intrinsic", varstr(VL,np->b_name.varname));
+packed.ijunk = np->b_name.vardesc.varno;
+
+switch(packed.bits.f1)
+       {
+       case INTRGEN:
+               /* imag, log, and log10 arent specific functions */
+               if(packed.bits.f3==31 || packed.bits.f3==43 || packed.bits.f3==47)
+                       goto bad;
+
+       case INTRSPEC:
+               sp = spectab + packed.bits.f3;
+               if(tyint==TYLONG && sp->rtype==TYSHORT)
+                       ++sp;
+               q = builtin(sp->rtype, varstr(XL,sp->spxname) );
+               return(q);
+
+       case INTRCONV:
+       case INTRMIN:
+       case INTRMAX:
+       case INTRBOOL:
+       bad:
+               err1("cannot pass %s as actual",
+                       varstr(VL,np->b_name.varname));
+               return( errnode() );
+       }
+fatal1("intraddr: impossible f1=%d\n", packed.bits.f1);
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+
+
+
+/*
+ * Try to inline simple function calls.
+ */
+struct bigblock *
+finline(int fno, int type, chainp args)
+{
+       register struct bigblock *q, *t;
+       struct bigblock *x1;
+       int l1;
+
+       switch(fno) {
+       case 8: /* real abs */
+       case 9: /* short int abs */
+       case 10:        /* long int abs */
+       case 11:        /* double precision abs */
+               t = fmktemp(type, NULL);
+               putexpr(mkexpr(OPASSIGN, cpexpr(t), args->chain.datap));
+               /* value now in t */
+
+               /* if greater, jump to return */
+               x1 = mkexpr(OPLE, cpexpr(t), mkconv(type,MKICON(0)));
+               l1 = newlabel();
+               putif(x1, l1);
+
+               /* negate */
+               putexpr(mkexpr(OPASSIGN, cpexpr(t),
+                   mkexpr(OPNEG, cpexpr(t), NULL)));
+               putlabel(l1);
+               return(t);
+               
+       case 26:        /* dprod */
+               q = mkexpr(OPSTAR, args->chain.datap, args->chain.nextp->chain.datap);
+               q->vtype = TYDREAL;
+               return(q);
+
+       case 27:        /* len of character string */
+               q = cpexpr(args->chain.datap->vleng);
+               frexpr(args->chain.datap);
+               return(q);
+
+       case 14:        /* half-integer mod */
+       case 15:        /* mod */
+               return( mkexpr(OPMOD, args->chain.datap, args->chain.nextp->chain.datap) );
+       }
+return(NULL);
+}
diff --git a/lang/pcc/pcc/f77/fcom/io.c b/lang/pcc/pcc/f77/fcom/io.c
new file mode 100644 (file)
index 0000000..9c69142
--- /dev/null
@@ -0,0 +1,797 @@
+/*     $Id: io.c,v 1.15 2008/12/19 08:08:48 ragge Exp $        */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* TEMPORARY */
+#define TYIOINT TYLONG
+#define FSZIOINT FSZLONG
+
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+LOCAL void doiolist(chainp);
+LOCAL void dofopen(void);
+LOCAL void dofclose(void);
+LOCAL void dofinquire(void);
+LOCAL void dofmove(char *);
+LOCAL void ioset(int, int, bigptr);
+LOCAL void iosetc(int, bigptr);
+LOCAL void iosetip(int, int);
+LOCAL void iosetlc(int, int, int);
+LOCAL void putiocall(struct bigblock *q);
+LOCAL void putio(bigptr, bigptr);
+LOCAL void startrw(void);
+
+
+LOCAL char ioroutine[XL+1];
+
+LOCAL int ioendlab;
+LOCAL int ioerrlab;
+LOCAL int endbit;
+LOCAL int jumplab;
+LOCAL int skiplab;
+LOCAL int ioformatted;
+
+#define UNFORMATTED 0
+#define FORMATTED 1
+#define LISTDIRECTED 2
+
+#define V(z)   ioc[z].iocval
+
+#define IOALL 07777
+
+LOCAL struct ioclist
+       {
+       char *iocname;
+       int iotype;
+       bigptr iocval;
+       } ioc[ ] =
+       {
+               { "", 0 },
+               { "unit", IOALL },
+               { "fmt", M(IOREAD) | M(IOWRITE) },
+               { "err", IOALL },
+               { "end", M(IOREAD) },
+               { "iostat", IOALL },
+               { "rec", M(IOREAD) | M(IOWRITE) },
+               { "recl", M(IOOPEN) | M(IOINQUIRE) },
+               { "file", M(IOOPEN) | M(IOINQUIRE) },
+               { "status", M(IOOPEN) | M(IOCLOSE) },
+               { "access", M(IOOPEN) | M(IOINQUIRE) },
+               { "form", M(IOOPEN) | M(IOINQUIRE) },
+               { "blank", M(IOOPEN) | M(IOINQUIRE) },
+               { "exist", M(IOINQUIRE) },
+               { "opened", M(IOINQUIRE) },
+               { "number", M(IOINQUIRE) },
+               { "named", M(IOINQUIRE) },
+               { "name", M(IOINQUIRE) },
+               { "sequential", M(IOINQUIRE) },
+               { "direct", M(IOINQUIRE) },
+               { "formatted", M(IOINQUIRE) },
+               { "unformatted", M(IOINQUIRE) },
+               { "nextrec", M(IOINQUIRE) }
+       } ;
+
+#define NIOS (sizeof(ioc)/sizeof(struct ioclist) - 1)
+#define MAXIO  FSZFLAG + 10*FSZIOINT + 15*FSZADDR
+
+#define IOSUNIT 1
+#define IOSFMT 2
+#define IOSERR 3
+#define IOSEND 4
+#define IOSIOSTAT 5
+#define IOSREC 6
+#define IOSRECL 7
+#define IOSFILE 8
+#define IOSSTATUS 9
+#define IOSACCESS 10
+#define IOSFORM 11
+#define IOSBLANK 12
+#define IOSEXISTS 13
+#define IOSOPENED 14
+#define IOSNUMBER 15
+#define IOSNAMED 16
+#define IOSNAME 17
+#define IOSSEQUENTIAL 18
+#define IOSDIRECT 19
+#define IOSFORMATTED 20
+#define IOSUNFORMATTED 21
+#define IOSNEXTREC 22
+
+#define IOSTP V(IOSIOSTAT)
+
+
+/* offsets in generated structures */
+
+#define FSZFLAG FSZIOINT
+
+#define XERR 0
+#define XUNIT  FSZFLAG
+#define XEND   FSZFLAG + FSZIOINT
+#define XFMT   2*FSZFLAG + FSZIOINT
+#define XREC   2*FSZFLAG + FSZIOINT + FSZADDR
+#define XRLEN  2*FSZFLAG + 2*FSZADDR
+#define XRNUM  2*FSZFLAG + 2*FSZADDR + FSZIOINT
+
+#define XIFMT  2*FSZFLAG + FSZADDR
+#define XIEND  FSZFLAG + FSZADDR
+#define XIUNIT FSZFLAG
+
+#define XFNAME FSZFLAG + FSZIOINT
+#define XFNAMELEN      FSZFLAG + FSZIOINT + FSZADDR
+#define XSTATUS        FSZFLAG + 2*FSZIOINT + FSZADDR
+#define XACCESS        FSZFLAG + 2*FSZIOINT + 2*FSZADDR
+#define XFORMATTED     FSZFLAG + 2*FSZIOINT + 3*FSZADDR
+#define XRECLEN        FSZFLAG + 2*FSZIOINT + 4*FSZADDR
+#define XBLANK FSZFLAG + 3*FSZIOINT + 4*FSZADDR
+
+#define XCLSTATUS      FSZFLAG + FSZIOINT
+
+#define XFILE  FSZFLAG + FSZIOINT
+#define XFILELEN       FSZFLAG + FSZIOINT + FSZADDR
+#define XEXISTS        FSZFLAG + 2*FSZIOINT + FSZADDR
+#define XOPEN  FSZFLAG + 2*FSZIOINT + 2*FSZADDR
+#define XNUMBER        FSZFLAG + 2*FSZIOINT + 3*FSZADDR
+#define XNAMED FSZFLAG + 2*FSZIOINT + 4*FSZADDR
+#define XNAME  FSZFLAG + 2*FSZIOINT + 5*FSZADDR
+#define XNAMELEN       FSZFLAG + 2*FSZIOINT + 6*FSZADDR
+#define XQACCESS       FSZFLAG + 3*FSZIOINT + 6*FSZADDR
+#define XQACCLEN       FSZFLAG + 3*FSZIOINT + 7*FSZADDR
+#define XSEQ   FSZFLAG + 4*FSZIOINT + 7*FSZADDR
+#define XSEQLEN        FSZFLAG + 4*FSZIOINT + 8*FSZADDR
+#define XDIRECT        FSZFLAG + 5*FSZIOINT + 8*FSZADDR
+#define XDIRLEN        FSZFLAG + 5*FSZIOINT + 9*FSZADDR
+#define XFORM  FSZFLAG + 6*FSZIOINT + 9*FSZADDR
+#define XFORMLEN       FSZFLAG + 6*FSZIOINT + 10*FSZADDR
+#define XFMTED FSZFLAG + 7*FSZIOINT + 10*FSZADDR
+#define XFMTEDLEN      FSZFLAG + 7*FSZIOINT + 11*FSZADDR
+#define XUNFMT FSZFLAG + 8*FSZIOINT + 11*FSZADDR
+#define XUNFMTLEN      FSZFLAG + 8*FSZIOINT + 12*FSZADDR
+#define XQRECL FSZFLAG + 9*FSZIOINT + 12*FSZADDR
+#define XNEXTREC       FSZFLAG + 9*FSZIOINT + 13*FSZADDR
+#define XQBLANK        FSZFLAG + 9*FSZIOINT + 14*FSZADDR
+#define XQBLANKLEN     FSZFLAG + 9*FSZIOINT + 15*FSZADDR
+\f
+int
+fmtstmt(lp)
+register struct labelblock *lp;
+{
+if(lp == NULL)
+       {
+       execerr("unlabeled format statement" , 0);
+       return(-1);
+       }
+if(lp->labtype == LABUNKNOWN)
+       {
+       lp->labtype = LABFORMAT;
+       lp->labelno = newlabel();
+       }
+else if(lp->labtype != LABFORMAT)
+       {
+       execerr("bad format number", 0);
+       return(-1);
+       }
+return(lp->labelno);
+}
+
+
+void
+setfmt(struct labelblock *lp)
+{
+       ftnint n;
+       char *s;
+
+       s = lexline(&n);
+       preven(ALILONG);
+       prlabel(lp->labelno);
+       putstr(s, n);
+       flline();
+}
+
+
+void
+startioctl()
+{
+unsigned int i;
+
+inioctl = YES;
+nioctl = 0;
+ioerrlab = 0;
+ioformatted = UNFORMATTED;
+for(i = 1 ; i<=NIOS ; ++i)
+       V(i) = NULL;
+}
+
+
+void
+endioctl()
+{
+unsigned int i;
+bigptr p;
+
+inioctl = NO;
+if(ioblkp == NULL)
+       ioblkp = autovar( (MAXIO+FSZIOINT-1)/FSZIOINT , TYIOINT, NULL);
+
+/* set up for error recovery */
+
+ioerrlab = ioendlab = skiplab = jumplab = 0;
+
+if((p = V(IOSEND))) {
+       if(ISICON(p))
+               ioendlab = mklabel(p->b_const.fconst.ci)->labelno;
+       else
+               err("bad end= clause");
+}
+
+if((p = V(IOSERR))) {
+       if(ISICON(p))
+               ioerrlab = mklabel(p->b_const.fconst.ci)->labelno;
+       else
+               err("bad err= clause");
+}
+
+if(IOSTP==NULL && ioerrlab!=0 && ioendlab!=0 && ioerrlab!=ioendlab)
+       IOSTP = fmktemp(TYINT, NULL);
+
+if(IOSTP != NULL) {
+       if(IOSTP->tag!=TADDR || ! ISINT(IOSTP->vtype) )
+               {
+               err("iostat must be an integer variable");
+               frexpr(IOSTP);
+               IOSTP = NULL;
+               }
+}
+
+if(IOSTP)
+       {
+       if( (iostmt==IOREAD || iostmt==IOWRITE) &&
+           (ioerrlab!=ioendlab || ioerrlab==0) )
+               jumplab = skiplab = newlabel();
+       else
+               jumplab = ioerrlab;
+       }
+else
+       {
+       jumplab = ioerrlab;
+       if(ioendlab)
+               jumplab = ioendlab;
+       }
+
+ioset(TYIOINT, XERR, MKICON(IOSTP!=NULL || ioerrlab!=0) );
+endbit = IOSTP!=NULL || ioendlab!=0;   /* for use in startrw() */
+
+switch(iostmt)
+       {
+       case IOOPEN:
+               dofopen();  break;
+
+       case IOCLOSE:
+               dofclose();  break;
+
+       case IOINQUIRE:
+               dofinquire();  break;
+
+       case IOBACKSPACE:
+               dofmove("f_back"); break;
+
+       case IOREWIND:
+               dofmove("f_rew");  break;
+
+       case IOENDFILE:
+               dofmove("f_end");  break;
+
+       case IOREAD:
+       case IOWRITE:
+               startrw();  break;
+
+       default:
+               fatal1("impossible iostmt %d", iostmt);
+       }
+for(i = 1 ; i<=NIOS ; ++i)
+       if(i!=IOSIOSTAT || (iostmt!=IOREAD && iostmt!=IOWRITE) )
+               frexpr(V(i));
+}
+
+
+int
+iocname()
+{
+unsigned int i;
+int found, mask;
+
+found = 0;
+mask = M(iostmt);
+for(i = 1 ; i <= NIOS ; ++i) {
+       if(toklen==(int)strlen(ioc[i].iocname) && eqn(toklen, token, ioc[i].iocname)) {
+               if(ioc[i].iotype & mask)
+                       return(i);
+               else    found = i;
+       }
+}
+
+if(found)
+       err1("invalid control %s for statement", ioc[found].iocname);
+else
+       err1("unknown iocontrol %s", varstr(toklen, token) );
+return(IOSBAD);
+}
+
+void
+ioclause(n, p)
+register int n;
+register bigptr p;
+{
+struct ioclist *iocp;
+
+++nioctl;
+if(n == IOSBAD)
+       return;
+if(n == IOSPOSITIONAL)
+       {
+       if(nioctl > IOSFMT)
+               {
+               err("illegal positional iocontrol");
+               return;
+               }
+       n = nioctl;
+       }
+
+if(p == NULL)
+       {
+       if(n == IOSUNIT)
+               p = (iostmt==IOREAD ? IOSTDIN : IOSTDOUT);
+       else if(n != IOSFMT)
+               {
+               err("illegal * iocontrol");
+               return;
+               }
+       }
+if(n == IOSFMT)
+       ioformatted = (p==NULL ? LISTDIRECTED : FORMATTED);
+
+iocp = & ioc[n];
+if(iocp->iocval == NULL)
+       {
+       p = cpexpr(p);
+       if(n!=IOSFMT && ( n!=IOSUNIT || (p!=NULL && p->vtype!=TYCHAR) ) )
+               p = fixtype(p);
+       iocp->iocval = p;
+}
+else
+       err1("iocontrol %s repeated", iocp->iocname);
+}
+
+/* io list item */
+void
+doio(list)
+chainp list;
+{
+doiolist(list);
+ioroutine[0] = 'e';
+putiocall( call0(TYINT, ioroutine) );
+frexpr(IOSTP);
+}
+
+
+
+
+
+LOCAL void doiolist(p0)
+chainp p0;
+{
+chainp p;
+register bigptr q;
+register bigptr qe;
+register struct bigblock *qn;
+struct bigblock *tp;
+int range;
+
+for (p = p0 ; p ; p = p->chain.nextp)
+       {
+       q = p->chain.datap;
+       if(q->tag == TIMPLDO)
+               {
+               exdo(range=newlabel(), (chainp)q->b_impldo.varnp);
+               doiolist(q->b_impldo.datalist);
+               enddo(range);
+               ckfree(q);
+               }
+       else    {
+               if(q->tag==TPRIM && q->b_prim.argsp==NULL && q->b_prim.namep->b_name.vdim!=NULL)
+                       {
+                       vardcl(qn = q->b_prim.namep);
+                       if(qn->b_name.vdim->nelt)
+                               putio( fixtype(cpexpr(qn->b_name.vdim->nelt)),
+                                       mkscalar(qn) );
+                       else
+                               err("attempt to i/o array of unknown size");
+                       }
+               else if(q->tag==TPRIM && q->b_prim.argsp==NULL && (qe = memversion(q->b_prim.namep)) )
+                       putio(MKICON(1),qe);
+               else if( (qe = fixtype(cpexpr(q)))->tag==TADDR)
+                       putio(MKICON(1), qe);
+               else if(qe->vtype != TYERROR)
+                       {
+                       if(iostmt == IOWRITE)
+                               {
+                               tp = fmktemp(qe->vtype, qe->vleng);
+                               puteq( cpexpr(tp), qe);
+                               putio(MKICON(1), tp);
+                               }
+                       else
+                               err("non-left side in READ list");
+                       }
+               frexpr(q);
+               }
+       }
+frchain( &p0 );
+}
+
+
+
+
+
+LOCAL void
+putio(nelt, addr)
+bigptr nelt;
+register bigptr addr;
+{
+int type;
+register struct bigblock *q;
+
+type = addr->vtype;
+if(ioformatted!=LISTDIRECTED && ISCOMPLEX(type) )
+       {
+       nelt = mkexpr(OPSTAR, MKICON(2), nelt);
+       type -= (TYCOMPLEX-TYREAL);
+       }
+
+/* pass a length with every item.  for noncharacter data, fake one */
+if(type != TYCHAR)
+       {
+       if( ISCONST(addr) )
+               addr = putconst(addr);
+       addr->vtype = TYCHAR;
+       addr->vleng = MKICON( typesize[type] );
+       }
+
+nelt = fixtype( mkconv(TYLENG,nelt) );
+if(ioformatted == LISTDIRECTED)
+       q = call3(TYINT, "do_lio", mkconv(TYLONG, MKICON(type)), nelt, addr);
+else
+       q = call2(TYINT, (ioformatted==FORMATTED ? "do_fio" : "do_uio"),
+               nelt, addr);
+putiocall(q);
+}
+
+
+
+void
+endio()
+{
+if(skiplab)
+       {
+       putlabel(skiplab);
+       if(ioendlab)
+               putif( mkexpr(OPGE, cpexpr(IOSTP), MKICON(0)), ioendlab);
+       if(ioerrlab)
+               putif( mkexpr( ( (iostmt==IOREAD||iostmt==IOWRITE) ? OPLE : OPEQ),
+                       cpexpr(IOSTP), MKICON(0)) , ioerrlab);
+       }
+if(IOSTP)
+       frexpr(IOSTP);
+}
+
+
+
+LOCAL void
+putiocall(q)
+register struct bigblock *q;
+{
+if(IOSTP)
+       {
+       q->vtype = TYINT;
+       q = fixexpr( mkexpr(OPASSIGN, cpexpr(IOSTP), q));
+       }
+
+if(jumplab)
+       putif( mkexpr(OPEQ, q, MKICON(0) ), jumplab);
+else
+       putexpr(q);
+}
+\f
+
+void
+startrw()
+{
+register bigptr p;
+register struct bigblock *np;
+register struct bigblock *unitp, *nump;
+int k, fmtoff;
+int intfile, sequential;
+
+
+sequential = YES;
+if((p = V(IOSREC))) {
+       if( ISINT(p->vtype) )
+               {
+               ioset(TYIOINT, XREC, cpexpr(p) );
+               sequential = NO;
+               }
+       else
+               err("bad REC= clause");
+}
+
+intfile = NO;
+if((p = V(IOSUNIT)))
+       {
+       if( ISINT(p->vtype) )
+               ioset(TYIOINT, XUNIT, cpexpr(p) );
+       else if(p->vtype == TYCHAR)
+               {
+               intfile = YES;
+               if(p->tag==TPRIM && p->b_prim.argsp==NULL && (np = p->b_prim.namep)->b_name.vdim!=NULL)
+                       {
+                       vardcl(np);
+                       if(np->b_name.vdim->nelt)
+                               nump = cpexpr(np->b_name.vdim->nelt);
+                       else
+                               {
+                               err("attempt to use internal unit array of unknown size");
+                               nump = MKICON(1);
+                               }
+                       unitp = mkscalar(np);
+                       }
+               else    {
+                       nump = MKICON(1);
+                       unitp = fixtype(cpexpr(p));
+                       }
+               ioset(TYIOINT, XRNUM, nump);
+               ioset(TYIOINT, XRLEN, cpexpr(unitp->vleng) );
+               ioset(TYADDR, XUNIT, addrof(unitp) );
+               }
+       }
+else
+       err("bad unit specifier");
+
+if(iostmt == IOREAD)
+       ioset(TYIOINT, (intfile ? XIEND : XEND), MKICON(endbit) );
+
+fmtoff = (intfile ? XIFMT : XFMT);
+
+if((p = V(IOSFMT)))
+       {
+       if(p->tag==TPRIM && p->b_prim.argsp==NULL)
+               {
+               vardcl(np = p->b_prim.namep);
+               if(np->b_name.vdim)
+                       {
+                       ioset(TYADDR, fmtoff, addrof(mkscalar(np)) );
+                       goto endfmt;
+                       }
+               if( ISINT(np->vtype) )
+                       {
+                       ioset(TYADDR, fmtoff, cpexpr(p));
+                       goto endfmt;
+                       }
+               }
+       p = V(IOSFMT) = fixtype(p);
+       if(p->vtype == TYCHAR)
+               ioset(TYADDR, fmtoff, addrof(cpexpr(p)) );
+       else if( ISICON(p) )
+               {
+               if( (k = fmtstmt( mklabel(p->b_const.fconst.ci) )) > 0 )
+                       ioset(TYADDR, fmtoff, mkaddcon(k) );
+               else
+                       ioformatted = UNFORMATTED;
+               }
+       else    {
+               err("bad format descriptor");
+               ioformatted = UNFORMATTED;
+               }
+       }
+else
+       ioset(TYADDR, fmtoff, MKICON(0) );
+
+endfmt:
+
+
+ioroutine[0] = 's';
+ioroutine[1] = '_';
+ioroutine[2] = (iostmt==IOREAD ? 'r' : 'w');
+ioroutine[3] = (sequential ? 's' : 'd');
+ioroutine[4] = "ufl" [ioformatted];
+ioroutine[5] = (intfile ? 'i' : 'e');
+ioroutine[6] = '\0';
+putiocall( call1(TYINT, ioroutine, cpexpr(ioblkp) ));
+}
+
+
+
+LOCAL void dofopen()
+{
+register bigptr p;
+
+if( (p = V(IOSUNIT)) && ISINT(p->vtype) )
+       ioset(TYIOINT, XUNIT, cpexpr(p) );
+else
+       err("bad unit in open");
+if( (p = V(IOSFILE)) && p->vtype==TYCHAR)
+       {
+       ioset(TYIOINT, XFNAMELEN, cpexpr(p->vleng) );
+       iosetc(XFNAME, p);
+       }
+else
+       err("bad file in open");
+
+if((p = V(IOSRECL)))
+       if( ISINT(p->vtype) )
+               ioset(TYIOINT, XRECLEN, cpexpr(p) );
+       else
+               err("bad recl");
+else
+       ioset(TYIOINT, XRECLEN, MKICON(0) );
+
+iosetc(XSTATUS, V(IOSSTATUS));
+iosetc(XACCESS, V(IOSACCESS));
+iosetc(XFORMATTED, V(IOSFORM));
+iosetc(XBLANK, V(IOSBLANK));
+
+putiocall( call1(TYINT, "f_open", cpexpr(ioblkp) ));
+}
+
+
+LOCAL void
+dofclose()
+{
+register bigptr p;
+
+if( (p = V(IOSUNIT)) && ISINT(p->vtype) )
+       {
+       ioset(TYIOINT, XUNIT, cpexpr(p) );
+       iosetc(XCLSTATUS, V(IOSSTATUS));
+       putiocall( call1(TYINT, "f_clos", cpexpr(ioblkp)) );
+       }
+else
+       err("bad unit in close statement");
+}
+
+
+LOCAL void dofinquire()
+{
+register bigptr p;
+if((p = V(IOSUNIT)))
+       {
+       if( V(IOSFILE) )
+               err("inquire by unit or by file, not both");
+       ioset(TYIOINT, XUNIT, cpexpr(p) );
+       }
+else if( ! V(IOSFILE) )
+       err("must inquire by unit or by file");
+iosetlc(IOSFILE, XFILE, XFILELEN);
+iosetip(IOSEXISTS, XEXISTS);
+iosetip(IOSOPENED, XOPEN);
+iosetip(IOSNUMBER, XNUMBER);
+iosetip(IOSNAMED, XNAMED);
+iosetlc(IOSNAME, XNAME, XNAMELEN);
+iosetlc(IOSACCESS, XQACCESS, XQACCLEN);
+iosetlc(IOSSEQUENTIAL, XSEQ, XSEQLEN);
+iosetlc(IOSDIRECT, XDIRECT, XDIRLEN);
+iosetlc(IOSFORM, XFORM, XFORMLEN);
+iosetlc(IOSFORMATTED, XFMTED, XFMTEDLEN);
+iosetlc(IOSUNFORMATTED, XUNFMT, XUNFMTLEN);
+iosetip(IOSRECL, XQRECL);
+iosetip(IOSNEXTREC, XNEXTREC);
+
+putiocall( call1(TYINT,  "f_inqu", cpexpr(ioblkp) ));
+}
+
+
+
+LOCAL void
+dofmove(subname)
+char *subname;
+{
+register bigptr p;
+
+if( (p = V(IOSUNIT)) && ISINT(p->vtype) )
+       {
+       ioset(TYIOINT, XUNIT, cpexpr(p) );
+       putiocall( call1(TYINT, subname, cpexpr(ioblkp) ));
+       }
+else
+       err("bad unit in move statement");
+}
+
+
+
+LOCAL void
+ioset(type, offset, p)
+int type, offset;
+bigptr p;
+{
+register struct bigblock *q;
+
+q = cpexpr(ioblkp);
+q->vtype = type;
+q->b_addr.memoffset = fixtype( mkexpr(OPPLUS, q->b_addr.memoffset, MKICON(offset)) );
+puteq(q, p);
+}
+
+
+
+
+LOCAL void
+iosetc(offset, p)
+int offset;
+register bigptr p;
+{
+if(p == NULL)
+       ioset(TYADDR, offset, MKICON(0) );
+else if(p->vtype == TYCHAR)
+       ioset(TYADDR, offset, addrof(cpexpr(p) ));
+else
+       err("non-character control clause");
+}
+
+
+
+LOCAL void
+iosetip(i, offset)
+int i, offset;
+{
+register bigptr p;
+
+if((p = V(i))) {
+       if(p->tag==TADDR && ONEOF(p->vtype, M(TYLONG)|M(TYLOGICAL)) )
+               ioset(TYADDR, offset, addrof(cpexpr(p)) );
+       else
+               err1("impossible inquire parameter %s", ioc[i].iocname);
+} else
+       ioset(TYADDR, offset, MKICON(0) );
+}
+
+
+
+LOCAL void
+iosetlc(i, offp, offl)
+int i, offp, offl;
+{
+register bigptr p;
+if( (p = V(i)) && p->vtype==TYCHAR)
+       ioset(TYIOINT, offl, cpexpr(p->vleng) );
+iosetc(offp, p);
+}
diff --git a/lang/pcc/pcc/f77/fcom/lex.c b/lang/pcc/pcc/f77/fcom/lex.c
new file mode 100644 (file)
index 0000000..daa5312
--- /dev/null
@@ -0,0 +1,955 @@
+/*     $Id: lex.c,v 1.12 2008/05/11 15:28:03 ragge Exp $       */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "defines.h"
+#include "defs.h"
+
+#include "gram.h"
+
+# define BLANK ' '
+# define MYQUOTE (2)
+# define SEOF 0
+
+/* card types */
+
+# define STEOF 1
+# define STINITIAL 2
+# define STCONTINUE 3
+
+/* lex states */
+
+#define NEWSTMT        1
+#define FIRSTTOKEN     2
+#define OTHERTOKEN     3
+#define RETEOS 4
+
+
+LOCAL int stkey;
+LOCAL int stno;
+LOCAL long int nxtstno;
+LOCAL int parlev;
+LOCAL int expcom;
+LOCAL int expeql;
+LOCAL char *nextch;
+LOCAL char *lastch;
+LOCAL char *nextcd     = NULL;
+LOCAL char *endcd;
+LOCAL int prevlin;
+LOCAL int thislin;
+LOCAL int code;
+LOCAL int lexstate     = NEWSTMT;
+LOCAL char s[1390];
+LOCAL char *send       = s+20*66;
+LOCAL int nincl        = 0;
+
+struct inclfile
+       {
+       struct inclfile *inclnext;
+       FILEP inclfp;
+       char *inclname;
+       int incllno;
+       char *incllinp;
+       int incllen;
+       int inclcode;
+       ftnint inclstno;
+       } ;
+
+LOCAL struct inclfile *inclp   =  NULL;
+struct keylist { char *keyname; int keyval; } ;
+struct punctlist { char punchar; int punval; };
+struct fmtlist { char fmtchar; int fmtval; };
+struct dotlist { char *dotname; int dotval; };
+LOCAL struct dotlist  dots[];
+LOCAL struct keylist *keystart[26], *keyend[26];
+LOCAL struct keylist  keys[];
+
+LOCAL int getcds(void);
+LOCAL void crunch(void);
+LOCAL void analyz(void);
+LOCAL int gettok(void);
+LOCAL int getcd(char *b);
+LOCAL int getkwd(void);
+LOCAL int popinclude(void);
+
+/*
+ * called from main() to start parsing.
+ * name[0] may be \0 if stdin.
+ */
+int
+inilex(char *name)
+{
+       nincl = 0;
+       inclp = NULL;
+       doinclude(name);
+       lexstate = NEWSTMT;
+       return(NO);
+}
+
+
+
+/* throw away the rest of the current line */
+void
+flline()
+{
+lexstate = RETEOS;
+}
+
+
+
+char *lexline(n)
+ftnint *n;
+{
+*n = (lastch - nextch) + 1;
+return(nextch);
+}
+
+
+
+
+void
+doinclude(char *name)
+{
+       FILEP fp;
+       struct inclfile *t;
+
+       if(inclp) {
+               inclp->incllno = thislin;
+               inclp->inclcode = code;
+               inclp->inclstno = nxtstno;
+               if(nextcd)
+                       inclp->incllinp =
+                           copyn(inclp->incllen = endcd-nextcd , nextcd);
+               else
+                       inclp->incllinp = 0;
+       }
+       nextcd = NULL;
+
+       if(++nincl >= MAXINCLUDES)
+               fatal("includes nested too deep");
+       if(name[0] == '\0')
+               fp = stdin;
+       else
+               fp = fopen(name, "r");
+       if( fp ) {
+               t = inclp;
+               inclp = ALLOC(inclfile);
+               inclp->inclnext = t;
+               prevlin = thislin = 0;
+               infname = inclp->inclname = name;
+               infile = inclp->inclfp = fp;
+       } else {
+               fprintf(diagfile, "Cannot open file %s", name);
+               done(1);
+       }
+}
+
+
+
+
+LOCAL int
+popinclude()
+{
+       struct inclfile *t;
+       register char *p;
+       register int k;
+
+       if(infile != stdin)
+               fclose(infile);
+       ckfree(infname);
+
+       --nincl;
+       t = inclp->inclnext;
+       ckfree(inclp);
+       inclp = t;
+       if(inclp == NULL)
+               return(NO);
+
+       infile = inclp->inclfp;
+       infname = inclp->inclname;
+       prevlin = thislin = inclp->incllno;
+       code = inclp->inclcode;
+       stno = nxtstno = inclp->inclstno;
+       if(inclp->incllinp) {
+               endcd = nextcd = s;
+               k = inclp->incllen;
+               p = inclp->incllinp;
+               while(--k >= 0)
+                       *endcd++ = *p++;
+               ckfree(inclp->incllinp);
+       } else
+               nextcd = NULL;
+       return(YES);
+}
+
+
+
+int
+yylex()
+{
+static int  tokno;
+
+       switch(lexstate)
+       {
+case NEWSTMT : /* need a new statement */
+       if(getcds() == STEOF)
+               return(SEOF);
+       crunch();
+       tokno = 0;
+       lexstate = FIRSTTOKEN;
+       yylval.num = stno;
+       stno = nxtstno;
+       toklen = 0;
+       return(SLABEL);
+
+first:
+case FIRSTTOKEN :      /* first step on a statement */
+       analyz();
+       lexstate = OTHERTOKEN;
+       tokno = 1;
+       return(stkey);
+
+case OTHERTOKEN :      /* return next token */
+       if(nextch > lastch)
+               goto reteos;
+       ++tokno;
+       if((stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3) goto first;
+       if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
+               nextch[0]=='t' && nextch[1]=='o')
+                       {
+                       nextch+=2;
+                       return(STO);
+                       }
+       return(gettok());
+
+reteos:
+case RETEOS:
+       lexstate = NEWSTMT;
+       return(SEOS);
+       }
+fatal1("impossible lexstate %d", lexstate);
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+LOCAL int
+getcds()
+{
+register char *p, *q;
+
+top:
+       if(nextcd == NULL)
+               {
+               code = getcd( nextcd = s );
+               stno = nxtstno;
+               prevlin = thislin;
+               }
+       if(code == STEOF) {
+               if( popinclude() )
+                       goto top;
+               else
+                       return(STEOF);
+       }
+       if(code == STCONTINUE)
+               {
+               lineno = thislin;
+               err("illegal continuation card ignored");
+               nextcd = NULL;
+               goto top;
+               }
+
+       if(nextcd > s)
+               {
+               q = nextcd;
+               p = s;
+               while(q < endcd)
+                       *p++ = *q++;
+               endcd = p;
+               }
+       for(nextcd = endcd ;
+               nextcd+66<=send && (code = getcd(nextcd))==STCONTINUE ;
+               nextcd = endcd )
+                       ;
+       nextch = s;
+       lastch = nextcd - 1;
+       if(nextcd >= send)
+               nextcd = NULL;
+       lineno = prevlin;
+       prevlin = thislin;
+       return(STINITIAL);
+}
+
+LOCAL int
+getcd(b)
+register char *b;
+{
+register int c;
+register char *p, *bend;
+int speclin;
+static char a[6];
+static char *aend      = a+6;
+
+top:
+       endcd = b;
+       bend = b+66;
+       speclin = NO;
+
+       if( (c = getc(infile)) == '&')
+               {
+               a[0] = BLANK;
+               a[5] = 'x';
+               speclin = YES;
+               bend = send;
+               }
+       else if(c=='c' || c=='C' || c=='*')
+               {
+               while( (c = getc(infile)) != '\n')
+                       if(c == EOF)
+                               return(STEOF);
+               ++thislin;
+               goto top;
+               }
+
+       else if(c != EOF)
+               {
+               /* a tab in columns 1-6 skips to column 7 */
+               ungetc(c, infile);
+               for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
+                       if(c == '\t')
+                               {
+                               while(p < aend)
+                                       *p++ = BLANK;
+                               speclin = YES;
+                               bend = send;
+                               }
+                       else
+                               *p++ = c;
+               }
+       if(c == EOF)
+               return(STEOF);
+       if(c == '\n')
+               {
+               p = a; /* XXX ??? */
+               while(p < aend)
+                       *p++ = BLANK;
+               if( ! speclin )
+                       while(endcd < bend)
+                               *endcd++ = BLANK;
+               }
+       else    {       /* read body of line */
+               while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
+                       *endcd++ = (c == '\t' ? BLANK : c);
+               if(c == EOF)
+                       return(STEOF);
+               if(c != '\n')
+                       {
+                       while( (c=getc(infile)) != '\n')
+                               if(c == EOF)
+                                       return(STEOF);
+                       }
+
+               if( ! speclin )
+                       while(endcd < bend)
+                               *endcd++ = BLANK;
+               }
+       ++thislin;
+       if(a[5]!=BLANK && a[5]!='0')
+               return(STCONTINUE);
+       for(p=a; p<aend; ++p)
+               if(*p != BLANK) goto initline;
+       for(p = b ; p<endcd ; ++p)
+               if(*p != BLANK) goto initline;
+       goto top;
+
+initline:
+       nxtstno = 0;
+       for(p = a ; p<a+5 ; ++p)
+               if(*p != BLANK) {
+                       if(isdigit((int)*p))
+                               nxtstno = 10*nxtstno + (*p - '0');
+                       else    {
+                               lineno = thislin;
+                               err("nondigit in statement number field");
+                               nxtstno = 0;
+                               break;
+                               }
+               }
+       return(STINITIAL);
+}
+
+LOCAL void
+crunch()
+{
+register char *i, *j, *j0, *j1, *prvstr;
+int ten, nh, quote;
+
+/* i is the next input character to be looked at
+j is the next output character */
+parlev = 0;
+expcom = 0;    /* exposed ','s */
+expeql = 0;    /* exposed equal signs */
+j = s;
+prvstr = s;
+for(i=s ; i<=lastch ; ++i)
+       {
+       if(*i == BLANK) continue;
+       if(*i=='\'' ||  *i=='"')
+               {
+               quote = *i;
+               *j = MYQUOTE; /* special marker */
+               for(;;)
+                       {
+                       if(++i > lastch)
+                               {
+                               err("unbalanced quotes; closing quote supplied");
+                               break;
+                               }
+                       if(*i == quote)
+                               if(i<lastch && i[1]==quote) ++i;
+                               else break;
+                       else if(*i=='\\' && i<lastch)
+                               switch(*++i)
+                                       {
+                                       case 't':
+                                               *i = '\t'; break;
+                                       case 'b':
+                                               *i = '\b'; break;
+                                       case 'n':
+                                               *i = '\n'; break;
+                                       case 'f':
+                                               *i = '\f'; break;
+                                       case '0':
+                                               *i = '\0'; break;
+                                       default:
+                                               break;
+                                       }
+                       *++j = *i;
+                       }
+               j[1] = MYQUOTE;
+               j += 2;
+               prvstr = j;
+               }
+       else if( (*i=='h' || *i=='H')  && j>prvstr)     /* test for Hollerith strings */
+               {
+               if( ! isdigit((int)j[-1])) goto copychar;
+               nh = j[-1] - '0';
+               ten = 10;
+               j1 = prvstr - 1;
+               if (j1<j-5) j1=j-5;
+               for(j0=j-2 ; j0>j1; -- j0)
+                       {
+                       if( ! isdigit((int)*j0 ) ) break;
+                       nh += ten * (*j0-'0');
+                       ten*=10;
+                       }
+               if(j0 <= j1) goto copychar;
+/* a hollerith must be preceded by a punctuation mark.
+   '*' is possible only as repetition factor in a data statement
+   not, in particular, in character*2h
+*/
+
+               if( !(*j0=='*'&&s[0]=='d') && *j0!='/' && *j0!='(' &&
+                       *j0!=',' && *j0!='=' && *j0!='.')
+                               goto copychar;
+               if(i+nh > lastch)
+                       {
+                       err1("%dH too big", nh);
+                       nh = lastch - i;
+                       }
+               j0[1] = MYQUOTE; /* special marker */
+               j = j0 + 1;
+               while(nh-- > 0)
+                       {
+                       if(*++i == '\\')
+                               switch(*++i)
+                                       {
+                                       case 't':
+                                               *i = '\t'; break;
+                                       case 'b':
+                                               *i = '\b'; break;
+                                       case 'n':
+                                               *i = '\n'; break;
+                                       case 'f':
+                                               *i = '\f'; break;
+                                       case '0':
+                                               *i = '\0'; break;
+                                       default:
+                                               break;
+                                       }
+                       *++j = *i;
+                       }
+               j[1] = MYQUOTE;
+               j+=2;
+               prvstr = j;
+               }
+       else    {
+               if(*i == '(') ++parlev;
+               else if(*i == ')') --parlev;
+               else if(parlev == 0) {
+                       if(*i == '=') expeql = 1;
+                       else if(*i == ',') expcom = 1;
+copychar:      ;       /*not a string of BLANK -- copy, shifting case if necessary */
+               }
+               if(shiftcase && isupper((int)*i))
+                       *j++ = tolower((int)*i);
+               else    *j++ = *i;
+               }
+       }
+lastch = j - 1;
+nextch = s;
+}
+
+LOCAL void
+analyz()
+{
+register char *i;
+
+       if(parlev != 0)
+               {
+               err("unbalanced parentheses, statement skipped");
+               stkey = SUNKNOWN;
+               return;
+               }
+       if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
+               {
+/* assignment or if statement -- look at character after balancing paren */
+               parlev = 1;
+               for(i=nextch+3 ; i<=lastch; ++i)
+                       if(*i == (MYQUOTE))
+                               {
+                               while(*++i != MYQUOTE)
+                                       ;
+                               }
+                       else if(*i == '(')
+                               ++parlev;
+                       else if(*i == ')')
+                               {
+                               if(--parlev == 0)
+                                       break;
+                               }
+               if(i >= lastch)
+                       stkey = SLOGIF;
+               else if(i[1] == '=')
+                       stkey = SLET;
+               else if( isdigit((int)i[1]) )
+                       stkey = SARITHIF;
+               else    stkey = SLOGIF;
+               if(stkey != SLET)
+                       nextch += 2;
+               }
+       else if(expeql) /* may be an assignment */
+               {
+               if(expcom && nextch<lastch &&
+                       nextch[0]=='d' && nextch[1]=='o')
+                               {
+                               stkey = SDO;
+                               nextch += 2;
+                               }
+               else    stkey = SLET;
+               }
+/* otherwise search for keyword */
+       else    {
+               stkey = getkwd();
+               if(stkey==SGOTO && lastch>=nextch) {
+                       if(nextch[0]=='(')
+                               stkey = SCOMPGOTO;
+                       else if(isalpha((int)nextch[0]))
+                               stkey = SASGOTO;
+               }
+       }
+       parlev = 0;
+}
+
+
+
+LOCAL int
+getkwd()
+{
+register char *i, *j;
+register struct keylist *pk, *pend;
+int k;
+
+if(! isalpha((int)nextch[0]) )
+       return(SUNKNOWN);
+k = nextch[0] - 'a';
+if((pk = keystart[k]))
+       for(pend = keyend[k] ; pk<=pend ; ++pk )
+               {
+               i = pk->keyname;
+               j = nextch;
+               while(*++i==*++j && *i!='\0')
+                       ;
+               if(*i == '\0')
+                       {
+                       nextch = j;
+                       return(pk->keyval);
+                       }
+               }
+return(SUNKNOWN);
+}
+
+
+void
+initkey()
+{
+register struct keylist *p;
+register int i,j;
+
+for(i = 0 ; i<26 ; ++i)
+       keystart[i] = NULL;
+
+for(p = keys ; p->keyname ; ++p)
+       {
+       j = p->keyname[0] - 'a';
+       if(keystart[j] == NULL)
+               keystart[j] = p;
+       keyend[j] = p;
+       }
+}
+\f
+LOCAL int
+gettok()
+{
+int havdot, havexp, havdbl;
+int radix;
+extern struct punctlist puncts[];
+struct punctlist *pp;
+#if 0
+extern struct fmtlist fmts[];
+#endif
+struct dotlist *pd;
+
+char *i, *j, *n1, *p;
+
+       if(*nextch == (MYQUOTE))
+               {
+               ++nextch;
+               p = token;
+               while(*nextch != MYQUOTE)
+                       *p++ = *nextch++;
+               ++nextch;
+               toklen = p - token;
+               *p = '\0';
+               return (SHOLLERITH);
+               }
+/*
+       if(stkey == SFORMAT)
+               {
+               for(pf = fmts; pf->fmtchar; ++pf)
+                       {
+                       if(*nextch == pf->fmtchar)
+                               {
+                               ++nextch;
+                               if(pf->fmtval == SLPAR)
+                                       ++parlev;
+                               else if(pf->fmtval == SRPAR)
+                                       --parlev;
+                               return(pf->fmtval);
+                               }
+                       }
+               if( isdigit(*nextch) )
+                       {
+                       p = token;
+                       *p++ = *nextch++;
+                       while(nextch<=lastch && isdigit(*nextch) )
+                               *p++ = *nextch++;
+                       toklen = p - token;
+                       *p = '\0';
+                       if(nextch<=lastch && *nextch=='p')
+                               {
+                               ++nextch;
+                               return(SSCALE);
+                               }
+                       else    return(SICON);
+                       }
+               if( isalpha(*nextch) )
+                       {
+                       p = token;
+                       *p++ = *nextch++;
+                       while(nextch<=lastch &&
+                               (*nextch=='.' || isdigit(*nextch) || isalpha(*nextch) ))
+                                       *p++ = *nextch++;
+                       toklen = p - token;
+                       *p = '\0';
+                       return(SFIELD);
+                       }
+               goto badchar;
+               }
+ XXX ??? */
+/* Not a format statement */
+
+if(needkwd)
+       {
+       needkwd = 0;
+       return( getkwd() );
+       }
+
+       for(pp=puncts; pp->punchar; ++pp)
+               if(*nextch == pp->punchar)
+                       {
+                       if( (*nextch=='*' || *nextch=='/') &&
+                               nextch<lastch && nextch[1]==nextch[0])
+                                       {
+                                       if(*nextch == '*')
+                                               yylval.num = SPOWER;
+                                       else    yylval.num = SCONCAT;
+                                       nextch+=2;
+                                       }
+                       else    {yylval.num=pp->punval;
+                                       if(yylval.num==SLPAR)
+                                               ++parlev;
+                                       else if(yylval.num==SRPAR)
+                                               --parlev;
+                                       ++nextch;
+                               }
+                       return(yylval.num);
+                       }
+       if(*nextch == '.') {
+               if(nextch >= lastch) goto badchar;
+               else if(isdigit((int)nextch[1])) goto numconst;
+               else    {
+                       for(pd=dots ; (j=pd->dotname) ; ++pd)
+                               {
+                               for(i=nextch+1 ; i<=lastch ; ++i)
+                                       if(*i != *j) break;
+                                       else if(*i != '.') ++j;
+                                       else    {
+                                               nextch = i+1;
+                                               return(pd->dotval);
+                                               }
+                               }
+                       goto badchar;
+                       }
+       }
+       if( isalpha((int)*nextch) )
+               {
+               p = token;
+               *p++ = *nextch++;
+               while(nextch<=lastch)
+                       if( isalpha((int)*nextch) || isdigit((int)*nextch) )
+                               *p++ = *nextch++;
+                       else break;
+               toklen = p - token;
+               *p = '\0';
+               if(inioctl && nextch<=lastch && *nextch=='=')
+                       {
+                       ++nextch;
+                       return(SNAMEEQ);
+                       }
+               if(toklen>=8 && eqn(8, token, "function") &&
+                       nextch<lastch && *nextch=='(')
+                               {
+                               nextch -= (toklen - 8);
+                               return(SFUNCTION);
+                               }
+               if(toklen > VL)
+                       {
+                       err2("name %s too long, truncated to %d", token, VL);
+                       toklen = VL;
+                       token[6] = '\0';
+                       }
+               if(toklen==1 && *nextch==MYQUOTE)
+                       {
+                       switch(token[0])
+                               {
+                               case 'z':  case 'Z':
+                               case 'x':  case 'X':
+                                       radix = 16; break;
+                               case 'o':  case 'O':
+                                       radix = 8; break;
+                               case 'b':  case 'B':
+                                       radix = 2; break;
+                               default:
+                                       err("bad bit identifier");
+                                       return(SFNAME);
+                               }
+                       ++nextch;
+                       for(p = token ; *nextch!=MYQUOTE ; )
+                               if( hextoi(*p++ = *nextch++) >= radix)
+                                       {
+                                       err("invalid binary character");
+                                       break;
+                                       }
+                       ++nextch;
+                       toklen = p - token;
+                       return( radix==16 ? SHEXCON : (radix==8 ? SOCTCON : SBITCON) );
+                       }
+               return(SFNAME);
+               }
+       if( ! isdigit((int)*nextch) ) goto badchar;
+numconst:
+       havdot = NO;
+       havexp = NO;
+       havdbl = NO;
+       for(n1 = nextch ; nextch<=lastch ; ++nextch)
+               {
+               if(*nextch == '.')
+                       if(havdot) break;
+                       else if(nextch+2<=lastch && isalpha((int)nextch[1])
+                               && isalpha((int)nextch[2]))
+                                       break;
+                       else    havdot = YES;
+               else if(*nextch=='d' || *nextch=='e')
+                       {
+                       p = nextch;
+                       havexp = YES;
+                       if(*nextch == 'd')
+                               havdbl = YES;
+                       if(nextch<lastch)
+                               if(nextch[1]=='+' || nextch[1]=='-')
+                                       ++nextch;
+                       if( ! isdigit((int)*++nextch) )
+                               {
+                               nextch = p;
+                               havdbl = havexp = NO;
+                               break;
+                               }
+                       for(++nextch ;
+                               nextch<=lastch && isdigit((int)*nextch);
+                               ++nextch);
+                       break;
+                       }
+               else if( ! isdigit((int)*nextch) )
+                       break;
+               }
+       p = token;
+       i = n1;
+       while(i < nextch)
+               *p++ = *i++;
+       toklen = p - token;
+       *p = '\0';
+       if(havdbl) return(SDCON);
+       if(havdot || havexp) return(SRCON);
+       return(SICON);
+badchar:
+       s[0] = *nextch++;
+       return(SUNKNOWN);
+}
+\f
+/* KEYWORD AND SPECIAL CHARACTER TABLES
+*/
+
+struct punctlist puncts[ ] =
+       {
+{      '(', SLPAR, },
+{      ')', SRPAR, },
+{      '=', SEQUALS, },
+{      ',', SCOMMA, },
+{      '+', SPLUS, },
+{      '-', SMINUS, },
+{      '*', SSTAR, },
+{      '/', SSLASH, },
+{      '$', SCURRENCY, },
+{      ':', SCOLON, },
+{      0, 0 }, } ;
+
+/*
+LOCAL struct fmtlist  fmts[ ] =
+       {
+       '(', SLPAR,
+       ')', SRPAR,
+       '/', SSLASH,
+       ',', SCOMMA,
+       '-', SMINUS,
+       ':', SCOLON,
+       0, 0 } ;
+*/
+
+LOCAL struct dotlist  dots[ ] =
+       {
+{      "and.", SAND, },
+{      "or.", SOR, },
+{      "not.", SNOT, },
+{      "true.", STRUE, },
+{      "false.", SFALSE, },
+{      "eq.", SEQ, },
+{      "ne.", SNE, },
+{      "lt.", SLT, },
+{      "le.", SLE, },
+{      "gt.", SGT, },
+{      "ge.", SGE, },
+{      "neqv.", SNEQV, },
+{      "eqv.", SEQV, },
+{      0, 0 }, } ;
+
+LOCAL struct keylist  keys[ ] =
+       {
+{      "assign",  SASSIGN, },
+{      "automatic",  SAUTOMATIC, },
+{      "backspace",  SBACKSPACE, },
+{      "blockdata",  SBLOCK, },
+{      "call",  SCALL, },
+{      "character",  SCHARACTER, },
+{      "close",  SCLOSE, },
+{      "common",  SCOMMON, },
+{      "complex",  SCOMPLEX, },
+{      "continue",  SCONTINUE, },
+{      "data",  SDATA, },
+{      "dimension",  SDIMENSION, },
+{      "doubleprecision",  SDOUBLE, },
+{      "doublecomplex", SDCOMPLEX, },
+{      "elseif",  SELSEIF, },
+{      "else",  SELSE, },
+{      "endfile",  SENDFILE, },
+{      "endif",  SENDIF, },
+{      "end",  SEND, },
+{      "entry",  SENTRY, },
+{      "equivalence",  SEQUIV, },
+{      "external",  SEXTERNAL, },
+{      "format",  SFORMAT, },
+{      "function",  SFUNCTION, },
+{      "goto",  SGOTO, },
+{      "implicit",  SIMPLICIT, },
+{      "include",  SINCLUDE, },
+{      "inquire",  SINQUIRE, },
+{      "intrinsic",  SINTRINSIC, },
+{      "integer",  SINTEGER, },
+{      "logical",  SLOGICAL, },
+{      "open",  SOPEN, },
+{      "parameter",  SPARAM, },
+{      "pause",  SPAUSE, },
+{      "print",  SPRINT, },
+{      "program",  SPROGRAM, },
+{      "punch",  SPUNCH, },
+{      "read",  SREAD, },
+{      "real",  SREAL, },
+{      "return",  SRETURN, },
+{      "rewind",  SREWIND, },
+{      "save",  SSAVE, },
+{      "static",  SSTATIC, },
+{      "stop",  SSTOP, },
+{      "subroutine",  SSUBROUTINE, },
+{      "then",  STHEN, },
+{      "undefined", SUNDEFINED, },
+{      "write",  SWRITE, },
+{      0, 0 }, };
diff --git a/lang/pcc/pcc/f77/fcom/main.c b/lang/pcc/pcc/f77/fcom/main.c
new file mode 100644 (file)
index 0000000..c6f7c0c
--- /dev/null
@@ -0,0 +1,442 @@
+/*     $Id: main.c,v 1.17 2012/03/22 18:51:40 plunky Exp $     */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+char xxxvers[] = "\nFORTRAN 77 PASS 1, VERSION 1.16,  3 NOVEMBER 1978\n";
+
+#include <unistd.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void mkdope(void);
+
+int ndebug;
+int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug;
+int r2debug, s2debug, t2debug, u2debug, x2debug;
+int kflag;
+int xdeljumps, xtemps, xssa, xdce;
+
+int mflag, tflag;
+
+char *ftitle = "<unknown>";
+
+#if 1 /* RAGGE */
+FILE *initfile, *sortfile;
+int dodata(char *file);
+LOCAL int nch   = 0;
+#endif
+
+static void
+usage(void)
+{
+       fprintf(stderr, "usage: fcom [qw:UuOdpC1I:Z:]\n");
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int ch;
+       int k, retcode;
+
+       infile = stdin;
+       diagfile = stderr;
+#if 1 /* RAGGE */
+       char file[] = "/tmp/initfile.XXXXXX";
+       char buf[100];
+       close(mkstemp(file));
+       sprintf(buf, "sort > %s", file);
+       initfile = popen(buf, "w");
+#endif
+
+
+#define DONE(c)        { retcode = c; goto finis; }
+
+       while ((ch = getopt(argc, argv, "qw:UuOdpC1I:Z:X:")) != -1)
+               switch (ch) {
+               case 'q':
+                       quietflag = YES;
+                       break;
+
+               case 'w':
+                       if(optarg[0]=='6' && optarg[1]=='6') {
+                               ftn66flag = YES;
+                       } else
+                               nowarnflag = YES;
+                       break;
+
+               case 'U':
+                       shiftcase = NO;
+                       break;
+
+               case 'u':
+                       undeftype = YES;
+                       break;
+
+               case 'O':
+                       optimflag = YES;
+#ifdef notyet
+                       xdeljumps = 1;
+                       xtemps = 1;
+#endif
+                       break;
+
+               case 'd':
+                       debugflag = YES;
+                       break;
+
+               case 'p':
+                       profileflag = YES;
+                       break;
+
+               case 'C':
+                       checksubs = YES;
+                       break;
+
+               case '1':
+                       onetripflag = YES;
+                       break;
+
+               case 'I':
+                       if(*optarg == '2')
+                               tyint = TYSHORT;
+                       else if(*optarg == '4') {
+                               shortsubs = NO;
+                               tyint = TYLONG;
+                       } else if(*optarg == 's')
+                               shortsubs = YES;
+                       else
+                               fatal1("invalid flag -I%c\n", *optarg);
+                       tylogical = tyint;
+                       break;
+
+               case 'Z':       /* pass2 debugging */
+                       while (*optarg)
+                               switch (*optarg++) {
+                               case 'b': /* basic block and SSA building */
+                                       ++b2debug;
+                                       break;
+                               case 'c': /* code printout */
+                                       ++c2debug;
+                                       break;
+                               case 'e': /* print tree upon pass2 enter */
+                                       ++e2debug;
+                                       break;
+                               case 'f': /* instruction matching */
+                                       ++f2debug;
+                                       break;
+                               case 'g':
+                                       ++g2debug;
+                                       break;
+                               case 'n':
+                                       ++ndebug;
+                                       break;
+                               case 'o':
+                                       ++o2debug;
+                                       break;
+                               case 'r': /* register alloc/graph coloring */
+                                       ++r2debug;
+                                       break;
+                               case 's': /* shape matching */
+                                       ++s2debug;
+                                       break;
+                               case 't':
+                                       ++t2debug;
+                                       break;
+                               case 'u': /* Sethi-Ullman debugging */
+                                       ++u2debug;
+                                       break;
+                               case 'x':
+                                       ++x2debug;
+                                       break;
+                               default:
+                                       fprintf(stderr, "unknown Z flag '%c'\n",
+                                           optarg[-1]);
+                                       exit(1);
+                               }
+                       break;
+
+               case 'X':       /* pass1 debugging */
+                       while (*optarg)
+                               switch (*optarg++) {
+                               case 'm': /* memory allocation */
+                                       ++mflag;
+                                       break;
+                               case 't': /* tree debugging */
+                                       tflag++;
+                                       break;
+                               default:
+                                       usage();
+                               }
+                       break;
+
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       mkdope();
+       initkey();
+       if (argc > 0) {
+               if (inilex(copys(argv[0])))
+                       DONE(1);
+               if (!quietflag)
+                       fprintf(diagfile, "%s:\n", argv[0]);
+               if (argc != 1)
+                       if (freopen(argv[1], "w", stdout) == NULL) {
+                               fprintf(stderr, "open output file '%s':",
+                                   argv[1]);
+                               perror(NULL);
+                               exit(1);
+                       }
+       } else {
+               inilex(copys(""));
+       }
+       fileinit();
+       procinit();
+       if((k = yyparse())) {
+               fprintf(diagfile, "Bad parse, return code %d\n", k);
+               DONE(1);
+       }
+       if(nerr > 0)
+               DONE(1);
+       if(parstate != OUTSIDE) {
+               warn("missing END statement");
+               endproc();
+       }
+       doext();
+       preven(ALIDOUBLE);
+       prtail();
+       puteof();
+       DONE(0);
+
+
+finis:
+       pclose(initfile);
+       retcode |= dodata(file);
+       unlink(file);
+       done(retcode);
+       return(retcode);
+}
+
+#define USEINIT ".data\t2"
+#define LABELFMT "%s:\n"
+
+static void
+prcha(FILEP fp, int *s)
+{
+
+fprintf(fp, ".byte 0%o,0%o\n", s[0], s[1]);
+}
+
+static void
+prskip(FILEP fp, ftnint k)
+{
+fprintf(fp, "\t.space\t%ld\n", k);
+}
+
+
+static void
+prch(int c)
+{
+static int buff[SZSHORT];
+
+buff[nch++] = c;
+if(nch == SZSHORT)
+        {
+        prcha(stdout, buff);
+        nch = 0;
+        }
+}
+
+
+static int
+rdname(int *vargroupp, char *name)
+{
+register int i, c;
+
+if( (c = getc(sortfile)) == EOF)
+        return(NO);
+*vargroupp = c - '0';
+
+for(i = 0 ; i<XL ; ++i)
+        {
+        if( (c = getc(sortfile)) == EOF)
+                return(NO);
+        if(c != ' ')
+                *name++ = c;
+        }
+*name = '\0';
+return(YES);
+}
+
+static int
+rdlong(ftnint *n)
+{
+register int c;
+
+for(c = getc(sortfile) ; c!=EOF && isspace(c) ; c = getc(sortfile) );
+        ;
+if(c == EOF)
+        return(NO);
+
+for(*n = 0 ; isdigit(c) ; c = getc(sortfile) )
+        *n = 10* (*n) + c - '0';
+return(YES);
+}
+
+static void
+prspace(ftnint n)
+{
+register ftnint m;
+
+while(nch>0 && n>0)
+        {
+        --n;
+        prch(0);
+        }
+m = SZSHORT * (n/SZSHORT);
+if(m > 0)
+        prskip(stdout, m);
+for(n -= m ; n>0 ; --n)
+        prch(0);
+}
+
+static ftnint
+doeven(ftnint tot, int align)
+{
+ftnint new;
+new = roundup(tot, align);
+prspace(new - tot);
+return(new);
+}
+
+
+int
+dodata(char *file)
+{
+       char varname[XL+1], ovarname[XL+1];
+       flag erred;
+       ftnint offset, vlen, type;
+       register ftnint ooffset, ovlen;
+       ftnint vchar;
+       int size, align;
+       int vargroup;
+       ftnint totlen;
+
+       erred = NO;
+       ovarname[0] = '\0';
+       ooffset = 0;
+       ovlen = 0;
+       totlen = 0;
+       nch = 0;
+       ftitle = file;
+
+       if( (sortfile = fopen(file, "r")) == NULL)
+               fatal1(file);
+#if 0
+       pruse(asmfile, USEINIT);
+#else
+       printf("\t%s\n", USEINIT);
+#endif
+       while (rdname(&vargroup, varname) && rdlong(&offset) &&
+           rdlong(&vlen) && rdlong(&type) ) {
+               size = typesize[type];
+               if( strcmp(varname, ovarname) ) {
+                       prspace(ovlen-ooffset);
+                       strcpy(ovarname, varname);
+                       ooffset = 0;
+                       totlen += ovlen;
+                       ovlen = vlen;
+                       if(vargroup == 0)
+                               align = (type==TYCHAR ? SZLONG :
+                                   typealign[type]);
+                       else
+                               align = ALIDOUBLE;
+                       totlen = doeven(totlen, align);
+                       if(vargroup == 2) {
+#if 0
+                               prcomblock(asmfile, varname);
+#else
+                               printf(LABELFMT, varname);
+#endif
+                       } else {
+#if 0
+                               fprintf(asmfile, LABELFMT, varname);
+#else
+                               printf(LABELFMT, varname);
+#endif
+                       }
+               }
+               if(offset < ooffset) {
+                       erred = YES;
+                       err("overlapping initializations");
+               }
+               if(offset > ooffset) {
+                       prspace(offset-ooffset);
+                       ooffset = offset;
+               }
+               if(type == TYCHAR) {
+                       if( ! rdlong(&vchar) )
+                               fatal("bad intermediate file format");
+                       prch( (int) vchar );
+               } else {
+                       putc('\t', stdout);
+                       while   ( putc( getc(sortfile), stdout)  != '\n')
+                               ;
+               }
+               if( (ooffset += size) > ovlen) {
+                       erred = YES;
+                       err("initialization out of bounds");
+               }
+       }
+
+       prspace(ovlen-ooffset);
+       totlen = doeven(totlen+ovlen, (ALIDOUBLE>SZLONG ? ALIDOUBLE : SZLONG) );
+       return(erred);
+}
+
+void
+done(k)
+int k;
+{
+static int recurs      = NO;
+
+if(recurs == NO)
+       {
+       recurs = YES;
+       }
+exit(k);
+}
diff --git a/lang/pcc/pcc/f77/fcom/misc.c b/lang/pcc/pcc/f77/fcom/misc.c
new file mode 100644 (file)
index 0000000..4471450
--- /dev/null
@@ -0,0 +1,704 @@
+/*     $Id: misc.c,v 1.17 2009/02/11 15:58:55 ragge Exp $      */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+int max(int, int);
+
+void
+cpn(n, a, b)
+register int n;
+register char *a, *b;
+{
+while(--n >= 0)
+       *b++ = *a++;
+}
+
+
+int
+eqn(n, a, b)
+register int n;
+register char *a, *b;
+{
+while(--n >= 0)
+       if(*a++ != *b++)
+               return(NO);
+return(YES);
+}
+
+
+
+
+
+
+int
+cmpstr(a, b, la, lb)   /* compare two strings */
+register char *a, *b;
+ftnint la, lb;
+{
+register char *aend, *bend;
+aend = a + la;
+bend = b + lb;
+
+
+if(la <= lb)
+       {
+       while(a < aend)
+               if(*a != *b)
+                       return( *a - *b );
+               else
+                       { ++a; ++b; }
+
+       while(b < bend)
+               if(*b != ' ')
+                       return(' ' - *b);
+               else
+                       ++b;
+       }
+
+else
+       {
+       while(b < bend)
+               if(*a != *b)
+                       return( *a - *b );
+               else
+                       { ++a; ++b; }
+       while(a < aend)
+               if(*a != ' ')
+                       return(*a - ' ');
+               else
+                       ++a;
+       }
+return(0);
+}
+
+
+
+
+
+chainp hookup(x,y)
+register chainp x, y;
+{
+register chainp p;
+
+if(x == NULL)
+       return(y);
+
+for(p = x ; p->chain.nextp ; p = p->chain.nextp)
+       ;
+p->chain.nextp = y;
+return(x);
+}
+
+
+
+struct bigblock *mklist(p)
+chainp p;
+{
+register struct bigblock *q;
+
+q = BALLO();
+q->tag = TLIST;
+q->b_list.listp = p;
+return(q);
+}
+
+
+chainp
+mkchain(bigptr p, chainp q)
+{
+       chainp r;
+
+       if(chains) {
+               r = chains;
+               chains = chains->chain.nextp;
+       } else
+               r = ALLOC(chain);
+
+       r->chain.datap = p;
+       r->chain.nextp = q;
+       return(r);
+}
+
+
+
+char * varstr(n, s)
+register int n;
+register char *s;
+{
+register int i;
+static char name[XL+1];
+
+for(i=0;  i<n && *s!=' ' && *s!='\0' ; ++i)
+       name[i] = *s++;
+
+name[i] = '\0';
+
+return( name );
+}
+
+
+
+
+char * varunder(n, s)
+register int n;
+register char *s;
+{
+register int i;
+static char name[XL+1];
+
+for(i=0;  i<n && *s!=' ' && *s!='\0' ; ++i)
+       name[i] = *s++;
+
+name[i] = '\0';
+
+return( name );
+}
+
+
+
+
+
+char * nounder(n, s)
+register int n;
+register char *s;
+{
+register int i;
+static char name[XL+1];
+
+for(i=0;  i<n && *s!=' ' && *s!='\0' ; ++s)
+       if(*s != '_')
+               name[i++] = *s;
+
+name[i] = '\0';
+
+return( name );
+}
+
+/*
+ * Save a block on heap.
+ */
+char *
+copyn(int n, char *s)
+{
+       char *p, *q;
+
+       p = q = ckalloc(n);
+       while(--n >= 0)
+               *q++ = *s++;
+       return(p);
+}
+
+/*
+ * Save a string on heap.
+ */
+char *
+copys(char *s)
+{
+       return(copyn(strlen(s)+1 , s));
+}
+
+/*
+ * convert a string to an int.
+ */
+ftnint
+convci(int n, char *s)
+{
+       ftnint sum;
+       sum = 0;
+       while(n-- > 0)
+               sum = 10*sum + (*s++ - '0');
+       return(sum);
+}
+
+char *convic(n)
+ftnint n;
+{
+static char s[20];
+register char *t;
+
+s[19] = '\0';
+t = s+19;
+
+do     {
+       *--t = '0' + n%10;
+       n /= 10;
+       } while(n > 0);
+
+return(t);
+}
+
+
+
+double convcd(n, s)
+int n;
+register char *s;
+{
+char v[100];
+register char *t;
+if(n > 90)
+       {
+       err("too many digits in floating constant");
+       n = 90;
+       }
+for(t = v ; n-- > 0 ; s++)
+       *t++ = (*s=='d' ? 'e' : *s);
+*t = '\0';
+return( atof(v) );
+}
+
+
+
+struct bigblock *mkname(l, s)
+int l;
+register char *s;
+{
+struct hashentry *hp;
+int hash;
+register struct bigblock *q;
+register int i;
+char n[VL];
+
+hash = 0;
+for(i = 0 ; i<l && *s!='\0' ; ++i)
+       {
+       hash += *s;
+       n[i] = *s++;
+       }
+hash %= MAXHASH;
+while( i < VL )
+       n[i++] = ' ';
+
+hp = hashtab + hash;
+while((q = hp->varp))
+       if( hash==hp->hashval && eqn(VL,n,q->b_name.varname) )
+               return(q);
+       else if(++hp >= lasthash)
+               hp = hashtab;
+
+if(++nintnames >= MAXHASH-1)
+       fatal("hash table full");
+hp->varp = q = BALLO();
+hp->hashval = hash;
+q->tag = TNAME;
+cpn(VL, n, q->b_name.varname);
+return(q);
+}
+
+
+
+struct labelblock *mklabel(l)
+ftnint l;
+{
+register struct labelblock *lp;
+
+if(l == 0)
+       return(0);
+
+for(lp = labeltab ; lp < highlabtab ; ++lp)
+       if(lp->stateno == l)
+               return(lp);
+
+if(++highlabtab >= labtabend)
+       fatal("too many statement numbers");
+
+lp->stateno = l;
+lp->labelno = newlabel();
+lp->blklevel = 0;
+lp->labused = NO;
+lp->labdefined = NO;
+lp->labinacc = NO;
+lp->labtype = LABUNKNOWN;
+return(lp);
+}
+
+int
+newlabel()
+{
+return( lastlabno++ );
+}
+
+
+/* find or put a name in the external symbol table */
+
+struct extsym *mkext(s)
+char *s;
+{
+int i;
+register char *t;
+char n[XL];
+struct extsym *p;
+
+i = 0;
+t = n;
+while(i<XL && *s)
+       *t++ = *s++;
+while(t < n+XL)
+       *t++ = ' ';
+
+for(p = extsymtab ; p<nextext ; ++p)
+       if(eqn(XL, n, p->extname))
+               return( p );
+
+if(nextext >= lastext)
+       fatal("too many external symbols");
+
+cpn(XL, n, nextext->extname);
+nextext->extstg = STGUNKNOWN;
+nextext->extsave = NO;
+nextext->extp = 0;
+nextext->extleng = 0;
+nextext->maxleng = 0;
+nextext->extinit = NO;
+return( nextext++ );
+}
+
+
+
+
+
+
+
+
+struct bigblock *builtin(t, s)
+int t;
+char *s;
+{
+register struct extsym *p;
+register struct bigblock *q;
+
+p = mkext(s);
+if(p->extstg == STGUNKNOWN)
+       p->extstg = STGEXT;
+else if(p->extstg != STGEXT)
+       {
+       err1("improper use of builtin %s", s);
+       return(0);
+       }
+
+q = BALLO();
+q->tag = TADDR;
+q->vtype = t;
+q->vclass = CLPROC;
+q->vstg = STGEXT;
+q->b_addr.memno = p - extsymtab;
+return(q);
+}
+
+
+void
+frchain(p)
+register chainp *p;
+{
+register chainp q;
+
+if(p==0 || *p==0)
+       return;
+
+for(q = *p; q->chain.nextp ; q = q->chain.nextp)
+       ;
+q->chain.nextp = chains;
+chains = *p;
+*p = 0;
+}
+
+
+ptr cpblock(n,p)
+register int n;
+register void * p;
+{
+register char *q, *r = p;
+ptr q0;
+
+q = q0 = ckalloc(n);
+while(n-- > 0)
+       *q++ = *r++;
+return(q0);
+}
+
+
+int
+max(a,b)
+int a,b;
+{
+return( a>b ? a : b);
+}
+
+
+ftnint lmax(a, b)
+ftnint a, b;
+{
+return( a>b ? a : b);
+}
+
+ftnint lmin(a, b)
+ftnint a, b;
+{
+return(a < b ? a : b);
+}
+
+
+
+int
+maxtype(t1, t2)
+int t1, t2;
+{
+int t;
+
+t = max(t1, t2);
+if(t==TYCOMPLEX && (t1==TYDREAL || t2==TYDREAL) )
+       t = TYDCOMPLEX;
+return(t);
+}
+
+
+
+/* return log base 2 of n if n a power of 2; otherwise -1 */
+int
+flog2(n)
+ftnint n;
+{
+int k;
+
+/* trick based on binary representation */
+
+if(n<=0 || (n & (n-1))!=0)
+       return(-1);
+
+for(k = 0 ;  n >>= 1  ; ++k)
+       ;
+return(k);
+}
+
+
+void
+frrpl()
+{
+chainp rp;
+
+while(rpllist)
+       {
+       rp = rpllist->rplblock.nextp;
+       ckfree(rpllist);
+       rpllist = rp;
+       }
+}
+
+void
+popstack(p)
+register chainp *p;
+{
+register chainp q;
+
+if(p==NULL || *p==NULL)
+       fatal("popstack: stack empty");
+q = (*p)->chain.nextp;
+ckfree(*p);
+*p = q;
+}
+
+
+
+struct bigblock *
+callk(type, name, args)
+int type;
+char *name;
+bigptr args;
+{
+register struct bigblock *p;
+
+p = mkexpr(OPCALL, builtin(type,name), args);
+p->vtype = type;
+return(p);
+}
+
+
+
+struct bigblock *
+call4(type, name, arg1, arg2, arg3, arg4)
+int type;
+char *name;
+bigptr arg1, arg2, arg3, arg4;
+{
+struct bigblock *args;
+args = mklist( mkchain(arg1, mkchain(arg2, mkchain(arg3, mkchain(arg4, NULL)) ) ) );
+return( callk(type, name, args) );
+}
+
+
+
+
+struct bigblock *call3(type, name, arg1, arg2, arg3)
+int type;
+char *name;
+bigptr arg1, arg2, arg3;
+{
+struct bigblock *args;
+args = mklist( mkchain(arg1, mkchain(arg2, mkchain(arg3, NULL) ) ) );
+return( callk(type, name, args) );
+}
+
+
+
+
+
+struct bigblock *
+call2(type, name, arg1, arg2)
+int type;
+char *name;
+bigptr arg1, arg2;
+{
+bigptr args;
+
+args = mklist( mkchain(arg1, mkchain(arg2, NULL) ) );
+return( callk(type,name, args) );
+}
+
+
+
+
+struct bigblock *call1(type, name, arg)
+int type;
+char *name;
+bigptr arg;
+{
+return( callk(type,name, mklist(mkchain(arg,0)) ));
+}
+
+
+struct bigblock *call0(type, name)
+int type;
+char *name;
+{
+return( callk(type, name, NULL) );
+}
+
+
+
+struct bigblock *
+mkiodo(dospec, list)
+chainp dospec, list;
+{
+register struct bigblock *q;
+
+q = BALLO();
+q->tag = TIMPLDO;
+q->b_impldo.varnp = (struct bigblock *)dospec;
+q->b_impldo.datalist = list;
+return(q);
+}
+
+
+
+
+ptr 
+ckalloc(int n)
+{
+       ptr p;
+
+       if ((p = calloc(1, (unsigned) n)) == NULL)
+               fatal("out of memory");
+#ifdef PCC_DEBUG
+       if (mflag)
+               printf("ckalloc: sz %d ptr %p\n", n, p);
+#endif
+       return(p);
+}
+
+void
+ckfree(void *p)
+{
+#ifdef PCC_DEBUG
+       if (mflag)
+               printf("ckfree: ptr %p\n", p);
+#endif
+       free(p);
+}
+
+#if 0
+int
+isaddr(p)
+register bigptr p;
+{
+if(p->tag == TADDR)
+       return(YES);
+if(p->tag == TEXPR)
+       switch(p->b_expr.opcode)
+               {
+               case OPCOMMA:
+                       return( isaddr(p->b_expr.rightp) );
+
+               case OPASSIGN:
+               case OPPLUSEQ:
+                       return( isaddr(p->b_expr.leftp) );
+               }
+return(NO);
+}
+#endif
+
+/*
+ * Return YES if not an expression.
+ */
+int
+addressable(bigptr p)
+{
+       switch(p->tag) {
+       case TCONST:
+               return(YES);
+
+       case TADDR:
+               return( addressable(p->b_addr.memoffset) );
+
+       default:
+               return(NO);
+       }
+}
+
+
+int
+hextoi(c)
+register int c;
+{
+register char *p;
+static char p0[17] = "0123456789abcdef";
+
+for(p = p0 ; *p ; ++p)
+       if(*p == c)
+               return( p-p0 );
+return(16);
+}
diff --git a/lang/pcc/pcc/f77/fcom/proc.c b/lang/pcc/pcc/f77/fcom/proc.c
new file mode 100644 (file)
index 0000000..2320157
--- /dev/null
@@ -0,0 +1,908 @@
+/*     $Id: proc.c,v 1.14 2008/12/24 17:40:41 sgk Exp $        */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+LOCAL void doentry(struct entrypoint *ep);
+LOCAL void retval(int t);
+LOCAL void epicode(void);
+LOCAL void procode(void);
+LOCAL int nextarg(int);
+LOCAL int nextarg(int);
+LOCAL void dobss(void);
+LOCAL void docommon(void);
+LOCAL void docomleng(void);
+
+
+/* start a new procedure */
+
+void
+newproc()
+{
+       if(parstate != OUTSIDE) {
+               execerr("missing end statement");
+               endproc();
+       }
+
+       parstate = INSIDE;
+       procclass = CLMAIN;     /* default */
+}
+
+
+
+/* end of procedure. generate variables, epilogs, and prologs */
+
+void
+endproc()
+{
+       struct labelblock *lp;
+
+       if(parstate < INDATA)
+               enddcl();
+       if(ctlstack >= ctls)
+               err("DO loop or BLOCK IF not closed");
+       for(lp = labeltab ; lp < labtabend ; ++lp)
+               if(lp->stateno!=0 && lp->labdefined==NO)
+                       err1("missing statement number %s",
+                           convic(lp->stateno) );
+
+       epicode();
+       procode();
+       dobss();
+       prdbginfo();
+
+       putbracket();
+
+       procinit();     /* clean up for next procedure */
+}
+
+
+
+/*
+ * End of declaration section of procedure.  Allocate storage.
+ */
+void
+enddcl()
+{
+       chainp p;
+
+       parstate = INEXEC;
+       docommon();
+       doequiv();
+       docomleng();
+       for(p = entries ; p ; p = p->entrypoint.nextp)
+               doentry(&p->entrypoint);
+}
+
+/* ROUTINES CALLED WHEN ENCOUNTERING ENTRY POINTS */
+
+/*
+ * Called when a PROGRAM or BLOCK DATA statement is found, or if a statement
+ * is encountered outside of any block.
+ */
+void
+startproc(struct extsym *progname, int class)
+{
+       chainp p;
+
+       p = ALLOC(entrypoint);
+       if(class == CLMAIN) {
+               puthead("MAIN__");
+               newentry( mkname(5, "MAIN_") );
+       }
+       p->entrypoint.entryname = progname;
+       p->entrypoint.entrylabel = newlabel();
+       entries = p;
+
+       procclass = class;
+       retlabel = newlabel();
+       if (!quietflag) {
+               fprintf(diagfile, "   %s",
+                   (class==CLMAIN ? "MAIN" : "BLOCK DATA") );
+               if (progname)
+                       fprintf(diagfile, " %s",
+                           nounder(XL, procname = progname->extname));
+               fprintf(diagfile, ":\n");
+       }
+}
+
+/* subroutine or function statement */
+
+struct extsym *
+newentry(struct bigblock *v)
+{
+       struct extsym *p;
+
+       p = mkext( varunder(VL, v->b_name.varname) );
+
+       if (p==NULL || p->extinit ||
+           !ONEOF(p->extstg, M(STGUNKNOWN)|M(STGEXT))) {
+               if(p == 0)
+                       dclerr("invalid entry name", v);
+               else
+                       dclerr("external name already used", v);
+               return(0);
+       }
+       v->vstg = STGAUTO;
+       v->b_name.vprocclass = PTHISPROC;
+       v->vclass = CLPROC;
+       p->extstg = STGEXT;
+       p->extinit = YES;
+       return(p);
+}
+
+/*
+ * Called if a SUBROUTINE, FUNCTION or ENTRY statement is found.
+ */
+void
+entrypt(int class, int type, ftnint length, struct extsym *entry, chainp args)
+{
+       struct bigblock *q;
+       chainp p;
+
+       if(class != CLENTRY)
+               puthead( varstr(XL, procname = entry->extname) );
+       if (!quietflag) {
+               if (class == CLENTRY)
+                       fprintf(diagfile, "       entry ");
+               fprintf(diagfile, "   %s:\n", nounder(XL, entry->extname));
+       }
+       q = mkname(VL, nounder(XL,entry->extname) );
+
+       if( (type = lengtype(type, (int) length)) != TYCHAR)
+               length = 0;
+
+       if(class == CLPROC) {
+               procclass = CLPROC;
+               proctype = type;
+               procleng = length;
+
+               retlabel = newlabel();
+               if(type == TYSUBR)
+                       ret0label = newlabel();
+       }
+
+       p = ALLOC(entrypoint);
+       entries = hookup(entries, p);
+       p->entrypoint.entryname = entry;
+       p->entrypoint.arglist = args;
+       p->entrypoint.entrylabel = newlabel();
+       p->entrypoint.enamep = q;
+
+       if(class == CLENTRY) {
+               class = CLPROC;
+               if(proctype == TYSUBR)
+                       type = TYSUBR;
+       }
+
+       q->vclass = class;
+       q->b_name.vprocclass = PTHISPROC;
+       settype(q, type, (int) length);
+       /* hold all initial entry points till end of declarations */
+       if(parstate >= INDATA)
+               doentry(&p->entrypoint);
+}
+\f
+/* generate epilogs */
+
+int multitypes = 0; /* XXX */
+
+LOCAL void
+epicode()
+{
+       int i;
+
+       if(procclass==CLPROC) {
+               if(proctype==TYSUBR) {
+                       putlabel(ret0label);
+                       if(substars)
+                               putforce(TYINT, MKICON(0) );
+                       putlabel(retlabel);
+                       goret(TYSUBR);
+               } else  {
+                       putlabel(retlabel);
+                       if(multitypes) {
+                               typeaddr = autovar(1, TYADDR, NULL);
+                               putbranch( cpexpr(typeaddr) );
+                               for(i = 0; i < NTYPES ; ++i) {
+                                       if(rtvlabel[i] != 0) {
+                                               putlabel(rtvlabel[i]);
+                                               retval(i);
+                                       }
+                               }
+                       } else
+                               retval(proctype);
+               }
+       } else if(procclass != CLBLOCK) {
+               putlabel(retlabel);
+               goret(TYSUBR);
+       }
+}
+
+
+/* generate code to return value of type  t */
+
+LOCAL void
+retval(t)
+register int t;
+{
+register struct bigblock *p;
+
+switch(t)
+       {
+       case TYCHAR:
+       case TYCOMPLEX:
+       case TYDCOMPLEX:
+               break;
+
+       case TYLOGICAL:
+               t = tylogical;
+       case TYADDR:
+       case TYSHORT:
+       case TYLONG:
+               p = cpexpr(retslot);
+               p->vtype = t;
+               putforce(t, p);
+               break;
+
+       case TYREAL:
+       case TYDREAL:
+               p = cpexpr(retslot);
+               p->vtype = t;
+               putforce(t, p);
+               break;
+
+       default:
+               fatal1("retval: impossible type %d", t);
+       }
+goret(t);
+}
+
+
+/* Allocate extra argument array if needed. Generate prologs. */
+
+LOCAL void
+procode()
+{
+register chainp p;
+struct bigblock *argvec;
+
+       if(lastargslot>0 && nentry>1)
+               argvec = autovar(lastargslot/FSZADDR, TYADDR, NULL);
+       else
+               argvec = NULL;
+
+       for(p = entries ; p ; p = p->entrypoint.nextp)
+               prolog(&p->entrypoint, argvec);
+
+       putrbrack(procno);
+
+       prendproc();
+}
+
+/*
+   manipulate argument lists (allocate argument slot positions)
+ * keep track of return types and labels
+ */
+LOCAL void
+doentry(struct entrypoint *ep)
+{
+       int type;
+       struct bigblock *np, *q;
+       chainp p;
+
+       ++nentry;
+       if(procclass == CLMAIN) {
+               putlabel(ep->entrylabel);
+               return;
+       } else if(procclass == CLBLOCK)
+               return;
+
+       impldcl(np = mkname(VL, nounder(XL, ep->entryname->extname)));
+       type = np->vtype;
+       if(proctype == TYUNKNOWN)
+               if( (proctype = type) == TYCHAR)
+                       procleng = (np->vleng ? np->vleng->b_const.fconst.ci : (ftnint) 0);
+
+       if(proctype == TYCHAR) {
+               if(type != TYCHAR)
+                       err("noncharacter entry of character function");
+               else if( (np->vleng ? np->vleng->b_const.fconst.ci : (ftnint) 0) != procleng)
+                       err("mismatched character entry lengths");
+       } else if(type == TYCHAR)
+               err("character entry of noncharacter function");
+       else if(type != proctype)
+               multitype = YES;
+       if(rtvlabel[type] == 0)
+               rtvlabel[type] = newlabel();
+       ep->typelabel = rtvlabel[type];
+
+       if(type == TYCHAR) {
+               if(chslot < 0) {
+                       chslot = nextarg(TYADDR);
+                       chlgslot = nextarg(TYLENG);
+               }
+               np->vstg = STGARG;
+               np->b_name.vardesc.varno = chslot;
+               if(procleng == 0)
+                       np->vleng = mkarg(TYLENG, chlgslot);
+       } else if( ISCOMPLEX(type) ) {
+               np->vstg = STGARG;
+               if(cxslot < 0)
+                       cxslot = nextarg(TYADDR);
+               np->b_name.vardesc.varno = cxslot;
+       } else if(type != TYSUBR) {
+               if(nentry == 1)
+                       retslot = autovar(1, TYDREAL, NULL);
+               np->vstg = STGAUTO;
+               np->b_name.voffset = retslot->b_addr.memoffset->b_const.fconst.ci;
+       }
+
+       for(p = ep->arglist ; p ; p = p->chain.nextp)
+               if(! ((q = p->chain.datap)->b_name.vdcldone) )
+                       q->b_name.vardesc.varno = nextarg(TYADDR);
+
+       for(p = ep->arglist ; p ; p = p->chain.nextp)
+               if(! ((q = p->chain.datap)->b_name.vdcldone) ) {
+                       impldcl(q);
+                       q->b_name.vdcldone = YES;
+                       if(q->vtype == TYCHAR) {
+                               if(q->vleng == NULL)    /* character*(*) */
+                                       q->vleng = mkarg(TYLENG, nextarg(TYLENG) );
+                               else if(nentry == 1)
+                                       nextarg(TYLENG);
+                       } else if(q->vclass==CLPROC && nentry==1)
+                               nextarg(TYLENG) ;
+               }
+       putlabel(ep->entrylabel);
+}
+
+
+
+LOCAL int
+nextarg(type)
+int type;
+{
+int k;
+k = lastargslot;
+lastargslot += typesize[type];
+return(k);
+}
+\f
+/* generate variable references */
+
+LOCAL void
+dobss()
+{
+register struct hashentry *p;
+register struct bigblock *q;
+register int i;
+int align;
+ftnint leng, iarrl;
+
+       setloc(UDATA);
+
+for(p = hashtab ; p<lasthash ; ++p)
+    if((q = p->varp))
+       {
+       if( (q->vclass==CLUNKNOWN && q->vstg!=STGARG) ||
+           (q->vclass==CLVAR && q->vstg==STGUNKNOWN) )
+               warn1("local variable %s never used", varstr(VL,q->b_name.varname) );
+       else if(q->vclass==CLVAR && q->vstg==STGBSS)
+               {
+               align = (q->vtype==TYCHAR ? ALILONG : typealign[q->vtype]);
+               if(bssleng % align != 0)
+                       {
+                       bssleng = roundup(bssleng, align);
+                       preven(align);
+                       }
+               prlocvar( memname(STGBSS, q->b_name.vardesc.varno), iarrl = iarrlen(q) );
+               bssleng += iarrl;
+               }
+       else if(q->vclass==CLPROC && q->b_name.vprocclass==PEXTERNAL && q->vstg!=STGARG)
+               mkext(varunder(VL, q->b_name.varname)) ->extstg = STGEXT;
+
+       if(q->vclass==CLVAR && q->vstg!=STGARG)
+               {
+               if(q->b_name.vdim && !ISICON(q->b_name.vdim->nelt) )
+                       dclerr("adjustable dimension on non-argument", q);
+               if(q->vtype==TYCHAR && (q->vleng==NULL || !ISICON(q->vleng)))
+                       dclerr("adjustable leng on nonargument", q);
+               }
+       }
+
+for(i = 0 ; i < nequiv ; ++i)
+       if(eqvclass[i].eqvinit==NO && (leng = eqvclass[i].eqvleng)!=0 )
+               {
+               bssleng = roundup(bssleng, ALIDOUBLE);
+               preven(ALIDOUBLE);
+               prlocvar( memname(STGEQUIV, i), leng);
+               bssleng += leng;
+               }
+}
+
+
+
+void
+doext()
+{
+struct extsym *p;
+
+for(p = extsymtab ; p<nextext ; ++p)
+       prext( varstr(XL, p->extname), p->maxleng, p->extinit);
+}
+
+
+
+
+ftnint iarrlen(q)
+register struct bigblock *q;
+{
+ftnint leng;
+
+leng = typesize[q->vtype];
+if(leng <= 0)
+       return(-1);
+if(q->b_name.vdim) {
+       if( ISICON(q->b_name.vdim->nelt) )
+               leng *= q->b_name.vdim->nelt->b_const.fconst.ci;
+       else    return(-1);
+}
+if(q->vleng) {
+       if( ISICON(q->vleng) )
+               leng *= q->vleng->b_const.fconst.ci;
+       else    return(-1);
+}
+return(leng);
+}
+\f
+LOCAL void 
+docommon()
+{
+register struct extsym *p;
+register chainp q;
+struct dimblock *t;
+bigptr neltp;
+register struct bigblock *v;
+ftnint size;
+int type;
+
+for(p = extsymtab ; p<nextext ; ++p)
+       if(p->extstg==STGCOMMON)
+               {
+               for(q = p->extp ; q ; q = q->chain.nextp)
+                       {
+                       v = q->chain.datap;
+                       if(v->b_name.vdcldone == NO)
+                               vardcl(v);
+                       type = v->vtype;
+                       if(p->extleng % typealign[type] != 0)
+                               {
+                               dclerr("common alignment", v);
+                               p->extleng = roundup(p->extleng, typealign[type]);
+                               }
+                       v->b_name.voffset = p->extleng;
+                       v->b_name.vardesc.varno = p - extsymtab;
+                       if(type == TYCHAR)
+                               size = v->vleng->b_const.fconst.ci;
+                       else    size = typesize[type];
+                       if((t = v->b_name.vdim)) {
+                               if( (neltp = t->nelt) && ISCONST(neltp) )
+                                       size *= neltp->b_const.fconst.ci;
+                               else
+                                       dclerr("adjustable array in common", v);
+                       }
+                       p->extleng += size;
+                       }
+
+               frchain( &(p->extp) );
+               }
+}
+
+
+
+
+
+LOCAL void
+docomleng()
+{
+register struct extsym *p;
+
+for(p = extsymtab ; p < nextext ; ++p)
+       if(p->extstg == STGCOMMON)
+               {
+               if(p->maxleng!=0 && p->extleng!=0 && p->maxleng!=p->extleng &&
+                   !eqn(XL,"_BLNK__ ",p->extname) )
+                       warn1("incompatible lengths for common block %s",
+                               nounder(XL, p->extname) );
+               if(p->maxleng < p->extleng)
+                       p->maxleng = p->extleng;
+               p->extleng = 0;
+       }
+}
+
+
+
+\f
+/* ROUTINES DEALING WITH AUTOMATIC AND TEMPORARY STORAGE */
+void
+frtemp(p)
+struct bigblock *p;
+{
+holdtemps = mkchain(p, holdtemps);
+}
+
+
+
+
+/* allocate an automatic variable slot */
+
+struct bigblock *
+autovar(int nelt, int t, bigptr lengp)
+{
+       ftnint leng = 0;
+       register struct bigblock *q;
+
+       if(t == TYCHAR) {
+               if( ISICON(lengp) )
+                       leng = lengp->b_const.fconst.ci;
+               else
+                       fatal("automatic variable of nonconstant length");
+       } else
+               leng = typesize[t];
+       autoleng = roundup( autoleng, typealign[t]);
+
+       q = BALLO();
+       q->tag = TADDR;
+       q->vtype = t;
+       if(t == TYCHAR)
+               q->vleng = MKICON(leng);
+       q->vstg = STGAUTO;
+       q->b_addr.ntempelt = nelt;
+#ifdef BACKAUTO
+       /* stack grows downward */
+       autoleng += nelt*leng;
+       q->b_addr.memoffset = MKICON( - autoleng );
+#else
+       q->b_addr.memoffset = MKICON( autoleng );
+       autoleng += nelt*leng;
+#endif
+
+       return(q);
+}
+
+
+struct bigblock *mktmpn(nelt, type, lengp)
+int nelt;
+register int type;
+bigptr lengp;
+{
+ftnint leng = 0; /* XXX gcc */
+chainp p, oldp;
+register struct bigblock *q;
+
+if(type==TYUNKNOWN || type==TYERROR)
+       fatal1("mktmpn: invalid type %d", type);
+
+if(type==TYCHAR) {
+       if( ISICON(lengp) )
+               leng = lengp->b_const.fconst.ci;
+       else    {
+               err("adjustable length");
+               return( errnode() );
+               }
+}
+for(oldp = (chainp)&templist ; (p = oldp->chain.nextp) ; oldp = p)
+       {
+       q = p->chain.datap;
+       if(q->vtype==type && q->b_addr.ntempelt==nelt &&
+           (type!=TYCHAR || q->vleng->b_const.fconst.ci==leng) )
+               {
+               oldp->chain.nextp = p->chain.nextp;
+               ckfree(p);
+               return(q);
+               }
+       }
+q = autovar(nelt, type, lengp);
+q->b_addr.istemp = YES;
+return(q);
+}
+
+
+
+
+struct bigblock *fmktemp(type, lengp)
+int type;
+bigptr lengp;
+{
+return( mktmpn(1,type,lengp) );
+}
+\f
+/* VARIOUS ROUTINES FOR PROCESSING DECLARATIONS */
+
+struct extsym *comblock(len, s)
+register int len;
+register char *s;
+{
+struct extsym *p;
+
+if(len == 0)
+       {
+       s = BLANKCOMMON;
+       len = strlen(s);
+       }
+p = mkext( varunder(len, s) );
+if(p->extstg == STGUNKNOWN)
+       p->extstg = STGCOMMON;
+else if(p->extstg != STGCOMMON)
+       {
+       err1("%s cannot be a common block name", s);
+       return(0);
+       }
+
+return( p );
+}
+
+void
+incomm(c, v)
+struct extsym *c;
+struct bigblock *v;
+{
+if(v->vstg != STGUNKNOWN)
+       dclerr("incompatible common declaration", v);
+else
+       {
+       v->vstg = STGCOMMON;
+       c->extp = hookup(c->extp, mkchain(v,NULL) );
+       }
+}
+
+
+
+void
+settype(v, type, length)
+register struct bigblock * v;
+register int type;
+register int length;
+{
+if(type == TYUNKNOWN)
+       return;
+
+if(type==TYSUBR && v->vtype!=TYUNKNOWN && v->vstg==STGARG)
+       {
+       v->vtype = TYSUBR;
+       frexpr(v->vleng);
+       }
+else if(type < 0)      /* storage class set */
+       {
+       if(v->vstg == STGUNKNOWN)
+               v->vstg = - type;
+       else if(v->vstg != -type)
+               dclerr("incompatible storage declarations", v);
+       }
+else if(v->vtype == TYUNKNOWN)
+       {
+       if( (v->vtype = lengtype(type, length))==TYCHAR && length!=0)
+               v->vleng = MKICON(length);
+       }
+else if(v->vtype!=type || (type==TYCHAR && v->vleng->b_const.fconst.ci!=length) )
+       dclerr("incompatible type declarations", v);
+}
+
+
+
+
+int
+lengtype(type, length)
+register int type;
+register int length;
+{
+switch(type)
+       {
+       case TYREAL:
+               if(length == 8)
+                       return(TYDREAL);
+               if(length == 4)
+                       goto ret;
+               break;
+
+       case TYCOMPLEX:
+               if(length == 16)
+                       return(TYDCOMPLEX);
+               if(length == 8)
+                       goto ret;
+               break;
+
+       case TYSHORT:
+       case TYDREAL:
+       case TYDCOMPLEX:
+       case TYCHAR:
+       case TYUNKNOWN:
+       case TYSUBR:
+       case TYERROR:
+               goto ret;
+
+       case TYLOGICAL:
+               if(length == 4)
+                       goto ret;
+               break;
+
+       case TYLONG:
+               if(length == 0)
+                       return(tyint);
+               if(length == 2)
+                       return(TYSHORT);
+               if(length == 4)
+                       goto ret;
+               break;
+       default:
+               fatal1("lengtype: invalid type %d", type);
+       }
+
+if(length != 0)
+       err("incompatible type-length combination");
+
+ret:
+       return(type);
+}
+
+
+
+
+void
+setintr(v)
+register struct bigblock * v;
+{
+register int k;
+
+if(v->vstg == STGUNKNOWN)
+       v->vstg = STGINTR;
+else if(v->vstg!=STGINTR)
+       dclerr("incompatible use of intrinsic function", v);
+if(v->vclass==CLUNKNOWN)
+       v->vclass = CLPROC;
+if(v->b_name.vprocclass == PUNKNOWN)
+       v->b_name.vprocclass = PINTRINSIC;
+else if(v->b_name.vprocclass != PINTRINSIC)
+       dclerr("invalid intrinsic declaration", v);
+if((k = intrfunct(v->b_name.varname)))
+       v->b_name.vardesc.varno = k;
+else
+       dclerr("unknown intrinsic function", v);
+}
+
+
+void
+setext(v)
+register struct bigblock * v;
+{
+if(v->vclass == CLUNKNOWN)
+       v->vclass = CLPROC;
+else if(v->vclass != CLPROC)
+       dclerr("invalid external declaration", v);
+
+if(v->b_name.vprocclass == PUNKNOWN)
+       v->b_name.vprocclass = PEXTERNAL;
+else if(v->b_name.vprocclass != PEXTERNAL)
+       dclerr("invalid external declaration", v);
+}
+
+
+
+
+/* create dimensions block for array variable */
+void
+setbound(v, nd, dims)
+register struct bigblock * v;
+int nd;
+struct uux dims[ ];
+{
+register bigptr q, t;
+register struct dimblock *p;
+int i;
+
+if(v->vclass == CLUNKNOWN)
+       v->vclass = CLVAR;
+else if(v->vclass != CLVAR)
+       {
+       dclerr("only variables may be arrays", v);
+       return;
+       }
+
+v->b_name.vdim = p = (struct dimblock *) ckalloc( sizeof(int) + (3+2*nd)*sizeof(bigptr) );
+p->ndim = nd;
+p->nelt = MKICON(1);
+
+for(i=0 ; i<nd ; ++i)
+       {
+       if( (q = dims[i].ub) == NULL)
+               {
+               if(i == nd-1)
+                       {
+                       frexpr(p->nelt);
+                       p->nelt = NULL;
+                       }
+               else
+                       err("only last bound may be asterisk");
+               p->dims[i].dimsize = MKICON(1);;
+               p->dims[i].dimexpr = NULL;
+               }
+       else
+               {
+               if(dims[i].lb)
+                       {
+                       q = mkexpr(OPMINUS, q, cpexpr(dims[i].lb));
+                       q = mkexpr(OPPLUS, q, MKICON(1) );
+                       }
+               if( ISCONST(q) )
+                       {
+                       p->dims[i].dimsize = q;
+                       p->dims[i].dimexpr = NULL;
+                       }
+               else    {
+                       p->dims[i].dimsize = autovar(1, tyint, NULL);
+                       p->dims[i].dimexpr = q;
+                       }
+               if(p->nelt)
+                       p->nelt = mkexpr(OPSTAR, p->nelt, cpexpr(p->dims[i].dimsize));
+               }
+       }
+
+q = dims[nd-1].lb;
+if(q == NULL)
+       q = MKICON(1);
+
+for(i = nd-2 ; i>=0 ; --i)
+       {
+       t = dims[i].lb;
+       if(t == NULL)
+               t = MKICON(1);
+       if(p->dims[i].dimsize)
+               q = mkexpr(OPPLUS, t, mkexpr(OPSTAR, cpexpr(p->dims[i].dimsize), q) );
+       }
+
+if( ISCONST(q) )
+       {
+       p->baseoffset = q;
+       p->basexpr = NULL;
+       }
+else
+       {
+       p->baseoffset = autovar(1, tyint, NULL);
+       p->basexpr = q;
+       }
+}
diff --git a/lang/pcc/pcc/f77/fcom/put.c b/lang/pcc/pcc/f77/fcom/put.c
new file mode 100644 (file)
index 0000000..356ed75
--- /dev/null
@@ -0,0 +1,299 @@
+/*     $Id: put.c,v 1.17 2008/05/11 15:28:03 ragge Exp $       */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * INTERMEDIATE CODE GENERATION PROCEDURES COMMON TO BOTH
+ * JOHNSON AND RITCHIE FAMILIES OF SECOND PASSES
+*/
+
+#include "defines.h"
+#include "defs.h"
+
+#include "scjdefs.h"
+
+char *ops [ ] =
+       {
+       "??", "+", "-", "*", "/", "**", "-",
+       "OR", "AND", "EQV", "NEQV", "NOT",
+       "CONCAT",
+       "<", "==", ">", "<=", "!=", ">=",
+       " of ", " ofC ", " = ", " += ", " *= ", " CONV ", " << ", " % ",
+       " , ", " ? ", " : "
+       " abs ", " min ", " max ", " addr ", " indirect ",
+       " bitor ", " bitand ", " bitxor ", " bitnot ", " >> ",
+       };
+
+/*
+ * The index position here matches tho OPx numbers in defines.h.
+ * Do not change!
+ */
+int ops2 [ ] =
+       {
+       P2BAD, P2PLUS, P2MINUS, P2STAR, P2SLASH, P2BAD, P2NEG,
+       P2BAD, P2BAD, P2EQ, P2NE, P2BAD,
+       P2BAD,
+       P2LT, P2EQ, P2GT, P2LE, P2NE, P2GE,
+       P2CALL, P2CALL, P2ASSIGN, P2BAD, P2BAD, P2CONV, P2LSHIFT, P2MOD,
+       P2BAD, P2BAD, P2BAD,
+       P2BAD, P2BAD, P2BAD, P2BAD, P2BAD,
+       P2BITOR, P2BITAND, P2BITXOR, P2BITNOT, P2RSHIFT
+       };
+
+
+int types2 [ ] =
+       {
+       P2BAD, INT|PTR, SHORT, LONG, FLOAT, DOUBLE,
+       FLOAT, DOUBLE, LONG, CHAR, INT, P2BAD
+       };
+
+void
+setlog()
+{
+types2[TYLOGICAL] = types2[tylogical];
+}
+
+NODE *
+putex1(bigptr q)
+{
+       NODE *p;
+       q = fixtype(q);
+       p = putx(q);
+       templist = hookup(templist, holdtemps);
+       holdtemps = NULL;
+       return p;
+}
+
+/*
+ * Print out an assignment.
+ */
+void
+puteq(bigptr lp, bigptr rp)
+{
+       putexpr(mkexpr(OPASSIGN, lp, rp));
+}
+
+/*
+ * Return a copied node of the real part of an expression.
+ */
+struct bigblock *
+realpart(struct bigblock *p)
+{
+       struct bigblock *q;
+
+       q = cpexpr(p);
+       if( ISCOMPLEX(p->vtype) )
+               q->vtype += (TYREAL-TYCOMPLEX);
+       return(q);
+}
+
+/*
+ * Return a copied node of the imaginary part of an expression.
+ */
+struct bigblock *
+imagpart(struct bigblock *p)
+{
+       struct bigblock *q;
+
+       if( ISCOMPLEX(p->vtype) ) {
+               q = cpexpr(p);
+               q->vtype += (TYREAL-TYCOMPLEX);
+               q->b_addr.memoffset = mkexpr(OPPLUS, q->b_addr.memoffset,
+                   MKICON(typesize[q->vtype]));
+       } else
+               q = mkrealcon( ISINT(p->vtype) ? TYDREAL : p->vtype , 0.0);
+       return(q);
+}
+
+struct bigblock *
+putconst(struct bigblock *p)
+{
+       struct bigblock *q;
+       struct literal *litp, *lastlit;
+       int i, k, type;
+       int litflavor;
+
+       if( ! ISCONST(p) )
+               fatal1("putconst: bad tag %d", p->tag);
+
+       q = BALLO();
+       q->tag = TADDR;
+       type = p->vtype;
+       q->vtype = ( type==TYADDR ? TYINT : type );
+       q->vleng = cpexpr(p->vleng);
+       q->vstg = STGCONST;
+       q->b_addr.memno = newlabel();
+       q->b_addr.memoffset = MKICON(0);
+
+       /* check for value in literal pool, and update pool if necessary */
+
+       switch(type = p->vtype) {
+       case TYCHAR:
+               if(p->vleng->b_const.fconst.ci > XL)
+                       break;  /* too long for literal table */
+               litflavor = 1;
+               goto loop;
+
+       case TYREAL:
+       case TYDREAL:
+               litflavor = 2;
+               goto loop;
+
+       case TYLOGICAL:
+               type = tylogical;
+       case TYSHORT:
+       case TYLONG:
+               litflavor = 3;
+
+       loop:
+               lastlit = litpool + nliterals;
+               for(litp = litpool ; litp<lastlit ; ++litp)
+                       if(type == litp->littype)
+                           switch(litflavor) {
+                       case 1:
+                               if(p->vleng->b_const.fconst.ci !=
+                                   litp->litval.litcval.litclen)
+                                       break;
+                               if(!eqn((int)p->vleng->b_const.fconst.ci,
+                                   p->b_const.fconst.ccp,
+                                       litp->litval.litcval.litcstr) )
+                                               break;
+                       ret:
+                               q->b_addr.memno = litp->litnum;
+                               frexpr(p);
+                               return(q);
+
+                       case 2:
+                               if(p->b_const.fconst.cd[0] ==
+                                   litp->litval.litdval)
+                                       goto ret;
+                               break;
+
+                       case 3:
+                               if(p->b_const.fconst.ci == litp->litval.litival)
+                                       goto ret;
+                               break;
+                       }
+               if(nliterals < MAXLITERALS) {
+                       ++nliterals;
+                       litp->littype = type;
+                       litp->litnum = q->b_addr.memno;
+                       switch(litflavor) {
+                       case 1:
+                               litp->litval.litcval.litclen =
+                                   p->vleng->b_const.fconst.ci;
+                               cpn( (int) litp->litval.litcval.litclen,
+                                       p->b_const.fconst.ccp,
+                                       litp->litval.litcval.litcstr);
+                               break;
+
+                       case 2:
+                               litp->litval.litdval = p->b_const.fconst.cd[0];
+                               break;
+
+                       case 3:
+                               litp->litval.litival = p->b_const.fconst.ci;
+                               break;
+                       }
+               }
+       default:
+               break;
+       }
+
+       preven(typealign[ type==TYCHAR ? TYLONG : type ]);
+       prlabel(q->b_addr.memno);
+
+       k = 1;
+       switch(type) {
+       case TYLOGICAL:
+       case TYSHORT:
+       case TYLONG:
+               prconi(stdout, type, p->b_const.fconst.ci);
+               break;
+
+       case TYCOMPLEX:
+               k = 2;
+       case TYREAL:
+               type = TYREAL;
+               goto flpt;
+
+       case TYDCOMPLEX:
+               k = 2;
+       case TYDREAL:
+               type = TYDREAL;
+
+       flpt:
+               for(i = 0 ; i < k ; ++i)
+                       prconr(stdout, type, p->b_const.fconst.cd[i]);
+               break;
+
+       case TYCHAR:
+               putstr(p->b_const.fconst.ccp,
+                   p->vleng->b_const.fconst.ci);
+               break;
+
+       case TYADDR:
+               prcona(p->b_const.fconst.ci);
+               break;
+
+       default:
+               fatal1("putconst: bad type %d", p->vtype);
+       }
+
+       frexpr(p);
+       return( q );
+}
+
+/*
+ * put out a character string constant.  begin every one on
+ * a long integer boundary, and pad with nulls
+ */
+void
+putstr(char *s, ftnint n)
+{
+       int b[FSZSHORT];
+       int i;
+
+       i = 0;
+       while(--n >= 0) {
+               b[i++] = *s++;
+               if(i == FSZSHORT) {
+                       prchars(b);
+                       i = 0;
+               }
+       }
+
+       while(i < FSZSHORT)
+               b[i++] = '\0';
+       prchars(b);
+}
diff --git a/lang/pcc/pcc/f77/fcom/putscj.c b/lang/pcc/pcc/f77/fcom/putscj.c
new file mode 100644 (file)
index 0000000..fb6302b
--- /dev/null
@@ -0,0 +1,1451 @@
+/*     $Id: putscj.c,v 1.18 2008/12/19 08:08:48 ragge Exp $    */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* INTERMEDIATE CODE GENERATION FOR S C JOHNSON C COMPILERS */
+/* NEW VERSION USING BINARY POLISH POSTFIX INTERMEDIATE */
+
+#include <unistd.h>
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+#include "scjdefs.h"
+
+LOCAL struct bigblock *putcall(struct bigblock *p);
+LOCAL NODE *putmnmx(struct bigblock *p);
+LOCAL NODE *putmem(bigptr, int, ftnint);
+LOCAL NODE *putaddr(struct bigblock *, int);
+LOCAL void putct1(bigptr, struct bigblock *, struct bigblock *, int *);
+LOCAL int ncat(bigptr p);
+LOCAL NODE *putcat(struct bigblock *, bigptr);
+LOCAL NODE *putchcmp(struct bigblock *p);
+LOCAL NODE *putcheq(struct bigblock *p);
+LOCAL NODE *putcxcmp(struct bigblock *p);
+LOCAL struct bigblock *putcx1(bigptr);
+LOCAL NODE *putcxop(bigptr p);
+LOCAL struct bigblock *putcxeq(struct bigblock *p);
+LOCAL NODE *putpower(bigptr p);
+LOCAL NODE *putop(bigptr p);
+LOCAL NODE *putchop(bigptr p);
+LOCAL struct bigblock *putch1(bigptr);
+LOCAL struct bigblock *intdouble(struct bigblock *);
+
+extern int ops2[];
+extern int types2[];
+static char *inproc;
+static NODE *callval; /* to get return value right */
+extern int negrel[];
+
+#define XINT(z)        ONEOF(z, MSKINT|MSKCHAR)
+#define        P2TYPE(x)       (types2[(x)->vtype])
+#define        P2OP(x)         (ops2[(x)->b_expr.opcode])
+
+static void
+sendp2(NODE *p)
+{
+       extern int thisline;
+
+       p2tree(p);
+       thisline = lineno;
+       if (debugflag)
+               fwalk(p, e2print, 0);
+       pass2_compile(ipnode(p));
+}
+
+static NODE *
+putassign(bigptr lp, bigptr rp)
+{
+       return putx(fixexpr(mkexpr(OPASSIGN, lp, rp)));
+}
+
+
+void
+puthead(char *s)
+{
+       struct interpass_prolog *ipp = ckalloc(sizeof(struct interpass_prolog));
+       int olbl, lbl1, lbl2;
+       unsigned int i;
+
+       if (s == NULL)
+               return;
+       if (inproc)
+               fatal1("puthead %s in procedure", s);
+       inproc = s;
+       olbl = lastlabno;
+       lbl1 = newlabel();
+       lbl2 = newlabel();
+
+       for (i = 0; i < NIPPREGS; i++)
+               ipp->ipp_regs[i] = 0;   /* no regs used yet */
+       ipp->ipp_autos = 0;             /* no autos used yet */
+       ipp->ipp_name = copys(s);               /* function name */
+       ipp->ipp_type = INT;            /* type not known yet? */
+       ipp->ipp_vis = 1;               /* always visible */
+       ipp->ip_tmpnum = 0;             /* no temp nodes used in F77 yet */
+       ipp->ip_lblnum = olbl;          /* # used labels so far */
+       ipp->ipp_ip.ip_lbl = lbl1;      /* first label, for optim */
+       ipp->ipp_ip.type = IP_PROLOG;
+       pass2_compile((struct interpass *)ipp);
+
+}
+
+/* It is necessary to precede each procedure with a "left bracket"
+ * line that tells pass 2 how many register variables and how
+ * much automatic space is required for the function.  This compiler
+ * does not know how much automatic space is needed until the
+ * entire procedure has been processed.  Therefore, "puthead"
+ * is called at the begining to record the current location in textfile,
+ * then to put out a placeholder left bracket line.  This procedure
+ * repositions the file and rewrites that line, then puts the
+ * file pointer back to the end of the file.
+ */
+
+void
+putbracket()
+{
+       struct interpass_prolog *ipp = ckalloc(sizeof(struct interpass_prolog));
+       unsigned int i;
+
+       if (inproc == 0)
+               fatal1("puteof outside procedure");
+       for (i = 0; i < NIPPREGS; i++)
+               ipp->ipp_regs[i] = 0;
+       ipp->ipp_autos = autoleng;
+       ipp->ipp_name = copys(inproc);
+       ipp->ipp_type = INT; /* XXX should set the correct type */
+       ipp->ipp_vis = 1;
+       ipp->ip_tmpnum = 0;
+       ipp->ip_lblnum = lastlabno;
+       ipp->ipp_ip.ip_lbl = retlabel;
+       ipp->ipp_ip.type = IP_EPILOG;
+       printf("\t.text\n"); /* XXX */
+       pass2_compile((struct interpass *)ipp);
+       inproc = 0;
+}
+
+
+
+void
+putrbrack(int k)
+{
+}
+
+
+void
+puteof()
+{
+}
+
+
+/* put out code for if( ! p) goto l  */
+void
+putif(bigptr p, int l)
+{
+       NODE *p1;
+       int k;
+
+       if( ( k = (p = fixtype(p))->vtype) != TYLOGICAL) {
+               if(k != TYERROR)
+                       err("non-logical expression in IF statement");
+               frexpr(p);
+       } else {
+               p1 = putex1(p);
+               if (p1->n_op == EQ && p1->n_right->n_op == ICON &&
+                   p1->n_right->n_lval == 0 && logop(p1->n_left->n_op)) {
+                       /* created by OPOR */
+                       NODE *q = p1->n_left;
+                       q->n_op = negrel[q->n_op - EQ];
+                       nfree(p1->n_right);
+                       nfree(p1);
+                       p1 = q;
+               }
+               if (logop(p1->n_op) == 0)
+                       p1 = mkbinode(NE, p1, mklnode(ICON, 0, 0, INT), INT);
+               if (p1->n_left->n_op == ICON) {
+                       /* change constants to right */
+                       NODE *p2 = p1->n_left;
+                       p1->n_left = p1->n_right;
+                       p1->n_right = p2;
+                       if (p1->n_op != EQ && p1->n_op != NE)
+                               p1->n_op = negrel[p1->n_op - EQ];
+               }
+               p1->n_op = negrel[p1->n_op - EQ];
+               p1 = mkbinode(CBRANCH, p1, mklnode(ICON, l, 0, INT), INT);
+               sendp2(p1);
+       }
+}
+
+/* Arithmetic IF  */
+void
+prarif(bigptr p, int neg, int zer, int pos)
+{
+       bigptr x1 = fmktemp(p->vtype, NULL);
+
+       putexpr(mkexpr(OPASSIGN, cpexpr(x1), p));
+       putif(mkexpr(OPGE, cpexpr(x1), MKICON(0)), neg);
+       putif(mkexpr(OPLE, x1, MKICON(0)), pos);
+       putgoto(zer);
+}
+
+/* put out code for  goto l   */
+void
+putgoto(int label)
+{
+       NODE *p;
+
+       p = mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT);
+       sendp2(p);
+}
+
+
+/* branch to address constant or integer variable */
+void
+putbranch(struct bigblock *q)
+{
+       NODE *p;
+
+       p = mkunode(GOTO, putex1(q), 0, INT);
+       sendp2(p);
+}
+
+/*
+ * put out label l: in text segment
+ */
+void
+putlabel(int label)
+{
+       struct interpass *ip = ckalloc(sizeof(struct interpass));
+
+       ip->type = IP_DEFLAB;
+       ip->lineno = lineno;
+       ip->ip_lbl = label;
+       pass2_compile(ip);
+}
+
+
+/*
+ * Called from inner routines.  Generates a NODE tree and writes it out.
+ */
+void
+putexpr(bigptr q)
+{
+       NODE *p;
+       p = putex1(q);
+       sendp2(p);
+}
+
+
+
+void
+putcmgo(bigptr x, int nlab, struct labelblock *labels[])
+{
+       bigptr y;
+       int i;
+
+       if (!ISINT(x->vtype)) {
+               execerr("computed goto index must be integer", NULL);
+               return;
+       }
+
+       y = fmktemp(x->vtype, NULL);
+       putexpr(mkexpr(OPASSIGN, cpexpr(y), x));
+#ifdef notyet /* target-specific computed goto */
+       vaxgoto(y, nlab, labels);
+#else
+       /*
+        * Primitive implementation, should use table here.
+        */
+       for(i = 0 ; i < nlab ; ++i)
+               putif(mkexpr(OPNE, cpexpr(y), MKICON(i+1)), labels[i]->labelno);
+       frexpr(y);
+#endif
+}
+
+/*
+ * Convert a f77 tree statement to something that looks like a
+ * pcc expression tree.
+ */
+NODE *
+putx(bigptr q)
+{
+       struct bigblock *x1;
+       NODE *p = NULL; /* XXX */
+       int opc;
+       int type, k;
+
+#ifdef PCC_DEBUG
+       if (tflag) {
+               printf("putx %p\n", q);
+               fprint(q, 0);
+       }
+#endif
+
+       switch(q->tag) {
+       case TERROR:
+               ckfree(q);
+               break;
+
+       case TCONST:
+               switch(type = q->vtype) {
+                       case TYLOGICAL:
+                               type = tyint;
+                       case TYLONG:
+                       case TYSHORT:
+                               p = mklnode(ICON, q->b_const.fconst.ci,
+                                   0, types2[type]);
+                               ckfree(q);
+                               break;
+
+                       case TYADDR:
+                               p = mklnode(ICON, 0, 0, types2[type]);
+                               p->n_name = copys(memname(STGCONST,
+                                   (int)q->b_const.fconst.ci));
+                               ckfree(q);
+                               break;
+
+                       default:
+                               p = putx(putconst(q));
+                               break;
+                       }
+               break;
+
+       case TEXPR:
+               switch(opc = q->b_expr.opcode) {
+                       case OPCALL:
+                       case OPCCALL:
+                               if( ISCOMPLEX(q->vtype) )
+                                       p = putcxop(q);
+                               else {
+                                       putcall(q);
+                                       p = callval;
+                               }
+                               break;
+
+                       case OPMIN:
+                       case OPMAX:
+                               p = putmnmx(q);
+                               break;
+
+                       case OPASSIGN:
+                               if (ISCOMPLEX(q->b_expr.leftp->vtype) ||
+                                   ISCOMPLEX(q->b_expr.rightp->vtype)) {
+                                       frexpr(putcxeq(q));
+                               } else if (ISCHAR(q))
+                                       p = putcheq(q);
+                               else
+                                       goto putopp;
+                               break;
+
+                       case OPEQ:
+                       case OPNE:
+                               if (ISCOMPLEX(q->b_expr.leftp->vtype) ||
+                                   ISCOMPLEX(q->b_expr.rightp->vtype) ) {
+                                       p = putcxcmp(q);
+                                       break;
+                               }
+                       case OPLT:
+                       case OPLE:
+                       case OPGT:
+                       case OPGE:
+                               if(ISCHAR(q->b_expr.leftp))
+                                       p = putchcmp(q);
+                               else
+                                       goto putopp;
+                               break;
+
+                       case OPPOWER:
+                               p = putpower(q);
+                               break;
+
+                       case OPSTAR:
+                               /*   m * (2**k) -> m<<k   */
+                               if (XINT(q->b_expr.leftp->vtype) &&
+                                   ISICON(q->b_expr.rightp) &&
+                                   ((k = flog2(q->b_expr.rightp->b_const.fconst.ci))>0) ) {
+                                       q->b_expr.opcode = OPLSHIFT;
+                                       frexpr(q->b_expr.rightp);
+                                       q->b_expr.rightp = MKICON(k);
+                                       goto putopp;
+                               }
+
+                       case OPMOD:
+                               goto putopp;
+                       case OPPLUS:
+                       case OPMINUS:
+                       case OPSLASH:
+                       case OPNEG:
+                               if( ISCOMPLEX(q->vtype) )
+                                       p = putcxop(q);
+                               else    
+                                       goto putopp;
+                               break;
+
+                       case OPCONV:
+                               if( ISCOMPLEX(q->vtype) )
+                                       p = putcxop(q);
+                               else if (ISCOMPLEX(q->b_expr.leftp->vtype)) {
+                                       p = putx(mkconv(q->vtype,
+                                           realpart(putcx1(q->b_expr.leftp))));
+                                       ckfree(q);
+                               } else
+                                       goto putopp;
+                               break;
+
+                       case OPAND:
+                               /* Create logical AND */
+                               x1 = fmktemp(TYLOGICAL, NULL);
+                               putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+                                   mklogcon(0)));
+                               k = newlabel();
+                               putif(q->b_expr.leftp, k);
+                               putif(q->b_expr.rightp, k);
+                               putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+                                   mklogcon(1)));
+                               putlabel(k);
+                               p = putx(x1);
+                               break;
+
+                       case OPNOT: /* Logical NOT */
+                               x1 = fmktemp(TYLOGICAL, NULL);
+                               putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+                                   mklogcon(1)));
+                               k = newlabel();
+                               putif(q->b_expr.leftp, k);
+                               putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+                                   mklogcon(0)));
+                               putlabel(k);
+                               p = putx(x1);
+                               break;
+
+                       case OPOR: /* Create logical OR */
+                               x1 = fmktemp(TYLOGICAL, NULL);
+                               putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+                                   mklogcon(1)));
+                               k = newlabel();
+                               putif(mkexpr(OPEQ, q->b_expr.leftp,
+                                   mklogcon(0)), k);
+                               putif(mkexpr(OPEQ, q->b_expr.rightp,
+                                   mklogcon(0)), k);
+                               putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+                                   mklogcon(0)));
+                               putlabel(k);
+                               p = putx(x1);
+                               break;
+
+                       case OPCOMMA:
+                               for (x1 = q; x1->b_expr.opcode == OPCOMMA; 
+                                   x1 = x1->b_expr.leftp)
+                                       putexpr(x1->b_expr.rightp);
+                               p = putx(x1);
+                               break;
+
+                       case OPEQV:
+                       case OPNEQV:
+                       case OPADDR:
+                       case OPBITOR:
+                       case OPBITAND:
+                       case OPBITXOR:
+                       case OPBITNOT:
+                       case OPLSHIFT:
+                       case OPRSHIFT:
+               putopp:
+                               p = putop(q);
+                               break;
+
+                       default:
+                               fatal1("putx: invalid opcode %d", opc);
+                       }
+               break;
+
+       case TADDR:
+               p = putaddr(q, YES);
+               break;
+
+       default:
+               fatal1("putx: impossible tag %d", q->tag);
+       }
+       return p;
+}
+
+LOCAL NODE *
+putop(bigptr q)
+{
+       NODE *p;
+       int k;
+       bigptr lp, tp;
+       int pt, lt;
+
+#ifdef PCC_DEBUG
+       if (tflag) {
+               printf("putop %p\n", q);
+               fprint(q, 0);
+       }
+#endif
+       switch(q->b_expr.opcode) { /* check for special cases and rewrite */
+       case OPCONV:
+               pt = q->vtype;
+               lp = q->b_expr.leftp;
+               lt = lp->vtype;
+               while(q->tag==TEXPR && q->b_expr.opcode==OPCONV &&
+                    ((ISREAL(pt)&&ISREAL(lt)) ||
+                       (XINT(pt)&&(ONEOF(lt,MSKINT|MSKADDR))) )) {
+                       if(lp->tag != TEXPR) {
+                               if(pt==TYINT && lt==TYLONG)
+                                       break;
+                               if(lt==TYINT && pt==TYLONG)
+                                       break;
+                       }
+                       ckfree(q);
+                       q = lp;
+                       pt = lt;
+                       lp = q->b_expr.leftp;
+                       lt = lp->vtype;
+               }
+               if(q->tag==TEXPR && q->b_expr.opcode==OPCONV)
+                       break;
+               p = putx(q);
+               return p;
+
+       case OPADDR:
+               lp = q->b_expr.leftp;
+               if(lp->tag != TADDR) {
+                       tp = fmktemp(lp->vtype, lp->vleng);
+                       p = putx(mkexpr(OPASSIGN, cpexpr(tp), lp));
+                       sendp2(p);
+                       lp = tp;
+               }
+               p = putaddr(lp, NO);
+               ckfree(q);
+               return p;
+       }
+
+       if ((k = ops2[q->b_expr.opcode]) <= 0)
+               fatal1("putop: invalid opcode %d (%d)", q->b_expr.opcode, k);
+       p = putx(q->b_expr.leftp);
+       if(q->b_expr.rightp)
+               p = mkbinode(k, p, putx(q->b_expr.rightp), types2[q->vtype]);
+       else
+               p = mkunode(k, p, 0, types2[q->vtype]);
+
+       if(q->vleng)
+               frexpr(q->vleng);
+       ckfree(q);
+       return p;
+}
+
+/*
+ * Put return values into correct register.
+ */
+void
+putforce(int t, bigptr p)
+{
+       NODE *p1;
+
+       p = mkconv(t, fixtype(p));
+       p1 = putx(p);
+       p1 = mkunode(FORCE, p1, 0, 
+               (t==TYSHORT ? SHORT : (t==TYLONG ? LONG : LDOUBLE)));
+       sendp2(p1);
+}
+
+LOCAL NODE *
+putpower(bigptr p)
+{
+       NODE *p3;
+       bigptr base;
+       struct bigblock *t1, *t2;
+       ftnint k = 0; /* XXX gcc */
+       int type;
+
+       if(!ISICON(p->b_expr.rightp) ||
+           (k = p->b_expr.rightp->b_const.fconst.ci)<2)
+               fatal("putpower: bad call");
+       base = p->b_expr.leftp;
+       type = base->vtype;
+       t1 = fmktemp(type, NULL);
+       t2 = NULL;
+       p3 = putassign(cpexpr(t1), cpexpr(base) );
+       sendp2(p3);
+
+       for( ; (k&1)==0 && k>2 ; k>>=1 ) {
+               p3 = putassign(cpexpr(t1),
+                   mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)));
+               sendp2(p3);
+       }
+
+       if(k == 2)
+               p3 = putx(mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)));
+       else {
+               t2 = fmktemp(type, NULL);
+               p3 = putassign(cpexpr(t2), cpexpr(t1));
+               sendp2(p3);
+       
+               for(k>>=1 ; k>1 ; k>>=1) {
+                       p3 = putassign(cpexpr(t1),
+                           mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)));
+                       sendp2(p3);
+                       if(k & 1) {
+                               p3 = putassign(cpexpr(t2),
+                                   mkexpr(OPSTAR, cpexpr(t2), cpexpr(t1)));
+                               sendp2(p3);
+                       }
+               }
+               p3 = putx( mkexpr(OPSTAR, cpexpr(t2),
+               mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)) ));
+       }
+       frexpr(t1);
+       if(t2)
+               frexpr(t2);
+       frexpr(p);
+       return p3;
+}
+
+LOCAL struct bigblock *
+intdouble(struct bigblock *p)
+{
+       struct bigblock *t;
+
+       t = fmktemp(TYDREAL, NULL);
+
+       sendp2(putassign(cpexpr(t), p));
+       return(t);
+}
+
+LOCAL struct bigblock *
+putcxeq(struct bigblock *q)
+{
+       struct bigblock *lp, *rp;
+
+       lp = putcx1(q->b_expr.leftp);
+       rp = putcx1(q->b_expr.rightp);
+       sendp2(putassign(realpart(lp), realpart(rp)));
+       if( ISCOMPLEX(q->vtype) ) {
+               sendp2(putassign(imagpart(lp), imagpart(rp)));
+       }
+       frexpr(rp);
+       ckfree(q);
+       return(lp);
+}
+
+
+
+LOCAL NODE *
+putcxop(bigptr q)
+{
+       NODE *p;
+
+       p = putaddr(putcx1(q), NO);
+       return p;
+}
+
+LOCAL struct bigblock *
+putcx1(bigptr qq)
+{
+       struct bigblock *q, *lp, *rp;
+       register struct bigblock *resp;
+       NODE *p;
+       int opcode;
+       int ltype, rtype;
+
+       ltype = rtype = 0; /* XXX gcc */
+       if(qq == NULL)
+               return(NULL);
+
+       switch(qq->tag) {
+       case TCONST:
+               if( ISCOMPLEX(qq->vtype) )
+                       qq = putconst(qq);
+               return( qq );
+
+       case TADDR:
+               if( ! addressable(qq) ) {
+                       resp = fmktemp(tyint, NULL);
+                       p = putassign( cpexpr(resp), qq->b_addr.memoffset );
+                       sendp2(p);
+                       qq->b_addr.memoffset = resp;
+               }
+               return( qq );
+
+       case TEXPR:
+               if( ISCOMPLEX(qq->vtype) )
+                       break;
+               resp = fmktemp(TYDREAL, NO);
+               p = putassign( cpexpr(resp), qq);
+               sendp2(p);
+               return(resp);
+
+       default:
+               fatal1("putcx1: bad tag %d", qq->tag);
+       }
+
+       opcode = qq->b_expr.opcode;
+       if(opcode==OPCALL || opcode==OPCCALL) {
+               q = putcall(qq);
+               sendp2(callval);
+               return(q);
+       } else if(opcode == OPASSIGN) {
+               return( putcxeq(qq) );
+       }
+
+       resp = fmktemp(qq->vtype, NULL);
+       if((lp = putcx1(qq->b_expr.leftp) ))
+               ltype = lp->vtype;
+       if((rp = putcx1(qq->b_expr.rightp) ))
+               rtype = rp->vtype;
+
+       switch(opcode) {
+       case OPCOMMA:
+               frexpr(resp);
+               resp = rp;
+               rp = NULL;
+               break;
+
+       case OPNEG:
+               p = putassign(realpart(resp),
+                   mkexpr(OPNEG, realpart(lp), NULL));
+               sendp2(p);
+               p = putassign(imagpart(resp),
+                   mkexpr(OPNEG, imagpart(lp), NULL));
+               sendp2(p);
+               break;
+
+       case OPPLUS:
+       case OPMINUS:
+               p = putassign( realpart(resp),
+                   mkexpr(opcode, realpart(lp), realpart(rp) ));
+               sendp2(p);
+               if(rtype < TYCOMPLEX) {
+                       p = putassign(imagpart(resp), imagpart(lp) );
+               } else if(ltype < TYCOMPLEX) {
+                       if(opcode == OPPLUS)
+                               p = putassign( imagpart(resp), imagpart(rp) );
+                       else
+                               p = putassign( imagpart(resp),
+                                   mkexpr(OPNEG, imagpart(rp), NULL) );
+               } else
+                       p = putassign( imagpart(resp),
+                           mkexpr(opcode, imagpart(lp), imagpart(rp) ));
+               sendp2(p);
+               break;
+
+       case OPSTAR:
+               if(ltype < TYCOMPLEX) {
+                       if( ISINT(ltype) )
+                               lp = intdouble(lp);
+                       p = putassign( realpart(resp),
+                           mkexpr(OPSTAR, cpexpr(lp), realpart(rp) ));
+                       sendp2(p);
+                       p = putassign( imagpart(resp),
+                           mkexpr(OPSTAR, cpexpr(lp), imagpart(rp) ));
+               } else if(rtype < TYCOMPLEX) {
+                       if( ISINT(rtype) )
+                               rp = intdouble(rp);
+                       p = putassign( realpart(resp),
+                           mkexpr(OPSTAR, cpexpr(rp), realpart(lp) ));
+                       sendp2(p);
+                       p = putassign( imagpart(resp),
+                           mkexpr(OPSTAR, cpexpr(rp), imagpart(lp) ));
+               } else {
+                       p = putassign( realpart(resp), mkexpr(OPMINUS,
+                               mkexpr(OPSTAR, realpart(lp), realpart(rp)),
+                               mkexpr(OPSTAR, imagpart(lp), imagpart(rp)) ));
+                       sendp2(p);
+                       p = putassign( imagpart(resp), mkexpr(OPPLUS,
+                               mkexpr(OPSTAR, realpart(lp), imagpart(rp)),
+                               mkexpr(OPSTAR, imagpart(lp), realpart(rp)) ));
+               }
+               sendp2(p);
+               break;
+
+       case OPSLASH:
+               /* fixexpr has already replaced all divisions
+                * by a complex by a function call
+                */
+               if( ISINT(rtype) )
+                       rp = intdouble(rp);
+               p = putassign( realpart(resp),
+                   mkexpr(OPSLASH, realpart(lp), cpexpr(rp)) );
+               sendp2(p);
+               p = putassign( imagpart(resp),
+                   mkexpr(OPSLASH, imagpart(lp), cpexpr(rp)) );
+               sendp2(p);
+               break;
+
+       case OPCONV:
+               p = putassign( realpart(resp), realpart(lp) );
+               if( ISCOMPLEX(lp->vtype) )
+                       q = imagpart(lp);
+               else if(rp != NULL)
+                       q = realpart(rp);
+               else
+                       q = mkrealcon(TYDREAL, 0.0);
+               sendp2(p);
+               p = putassign( imagpart(resp), q);
+               sendp2(p);
+               break;
+
+       default:
+               fatal1("putcx1 of invalid opcode %d", opcode);
+       }
+
+       frexpr(lp);
+       frexpr(rp);
+       ckfree(qq);
+       return(resp);
+}
+
+
+LOCAL NODE *
+putcxcmp(struct bigblock *p)
+{
+       NODE *p1;
+       int opcode;
+       struct bigblock *lp, *rp;
+       struct bigblock *q;
+
+       opcode = p->b_expr.opcode;
+       lp = putcx1(p->b_expr.leftp);
+       rp = putcx1(p->b_expr.rightp);
+
+       q = mkexpr( opcode==OPEQ ? OPAND : OPOR ,
+           mkexpr(opcode, realpart(lp), realpart(rp)),
+           mkexpr(opcode, imagpart(lp), imagpart(rp)) );
+       p1 = putx( fixexpr(q) );
+
+       ckfree(lp);
+       ckfree(rp);
+       ckfree(p);
+       return p1;
+}
+
+LOCAL struct bigblock *
+putch1(bigptr p)
+{
+       struct bigblock *t;
+
+       switch(p->tag) {
+       case TCONST:
+               return( putconst(p) );
+
+       case TADDR:
+               return(p);
+
+       case TEXPR:
+               switch(p->b_expr.opcode) {
+                       case OPCALL:
+                       case OPCCALL:
+                               t = putcall(p);
+                               sendp2(callval);
+                               break;
+
+                       case OPCONCAT:
+                               t = fmktemp(TYCHAR, cpexpr(p->vleng) );
+                               sendp2(putcat( cpexpr(t), p ));
+                               break;
+
+                       case OPCONV:
+                               if(!ISICON(p->vleng) ||
+                                   p->vleng->b_const.fconst.ci!=1
+                                  || ! XINT(p->b_expr.leftp->vtype) )
+                                       fatal("putch1: bad character conversion");
+                               t = fmktemp(TYCHAR, MKICON(1) );
+                               sendp2(putassign( cpexpr(t), p));
+                               break;
+                       default:
+                               fatal1("putch1: invalid opcode %d", p->b_expr.opcode);
+                               t = NULL; /* XXX gcc */
+                       }
+               return(t);
+
+       default:
+               fatal1("putch1: bad tag %d", p->tag);
+       }
+/* NOTREACHED */
+return NULL; /* XXX gcc */
+}
+\f
+
+
+
+LOCAL NODE *
+putchop(bigptr p)
+{
+       NODE *p1;
+
+       p1 = putaddr( putch1(p) , NO );
+       return p1;
+}
+
+
+/*
+ * Assign a character to another.
+ */
+LOCAL NODE *
+putcheq(struct bigblock *p)
+{
+       NODE *p1, *p2, *p3;
+
+       if( p->b_expr.rightp->tag==TEXPR &&
+           p->b_expr.rightp->b_expr.opcode==OPCONCAT )
+               p3 = putcat(p->b_expr.leftp, p->b_expr.rightp);
+       else if( ISONE(p->b_expr.leftp->vleng) &&
+           ISONE(p->b_expr.rightp->vleng) ) {
+               p1 = putaddr( putch1(p->b_expr.leftp) , YES );
+               p2 = putaddr( putch1(p->b_expr.rightp) , YES );
+               p3 = mkbinode(ASSIGN, p1, p2, CHAR);
+       } else
+               p3 = putx(call2(TYINT, "s_copy",
+                   p->b_expr.leftp, p->b_expr.rightp));
+
+       frexpr(p->vleng);
+       ckfree(p);
+       return p3;
+}
+
+
+
+/*
+ * Compare character(s) code.
+ */
+LOCAL NODE *
+putchcmp(struct bigblock *p)
+{
+       NODE *p1, *p2, *p3;
+
+       if(ISONE(p->b_expr.leftp->vleng) && ISONE(p->b_expr.rightp->vleng) ) {
+               p1 = putaddr( putch1(p->b_expr.leftp) , YES );
+               p2 = putaddr( putch1(p->b_expr.rightp) , YES );
+               p3 = mkbinode(ops2[p->b_expr.opcode], p1, p2, CHAR);
+               ckfree(p);
+       } else {
+               p->b_expr.leftp = call2(TYINT,"s_cmp",
+                   p->b_expr.leftp, p->b_expr.rightp);
+               p->b_expr.rightp = MKICON(0);
+               p3 = putop(p);
+       }
+       return p3;
+}
+
+LOCAL NODE *
+putcat(bigptr lhs, bigptr rhs)
+{
+       NODE *p3;
+       int n;
+       struct bigblock *lp, *cp;
+
+       n = ncat(rhs);
+       lp = mktmpn(n, TYLENG, NULL);
+       cp = mktmpn(n, TYADDR, NULL);
+
+       n = 0;
+       putct1(rhs, lp, cp, &n);
+
+       p3 = putx( call4(TYSUBR, "s_cat", lhs, cp, lp, MKICON(n) ) );
+       return p3;
+}
+
+LOCAL int
+ncat(bigptr p)
+{
+       if(p->tag==TEXPR && p->b_expr.opcode==OPCONCAT)
+               return( ncat(p->b_expr.leftp) + ncat(p->b_expr.rightp) );
+       else
+               return(1);
+}
+
+LOCAL void
+putct1(bigptr q, bigptr lp, bigptr cp, int *ip)
+{
+       NODE *p;
+       int i;
+       struct bigblock *lp1, *cp1;
+
+       if(q->tag==TEXPR && q->b_expr.opcode==OPCONCAT) {
+               putct1(q->b_expr.leftp, lp, cp, ip);
+               putct1(q->b_expr.rightp, lp, cp , ip);
+               frexpr(q->vleng);
+               ckfree(q);
+       } else {
+               i = (*ip)++;
+               lp1 = cpexpr(lp);
+               lp1->b_addr.memoffset =
+                   mkexpr(OPPLUS, lp1->b_addr.memoffset, MKICON(i*FSZLENG));
+               cp1 = cpexpr(cp);
+               cp1->b_addr.memoffset =
+                   mkexpr(OPPLUS, cp1->b_addr.memoffset, MKICON(i*FSZADDR));
+               p = putassign( lp1, cpexpr(q->vleng) );
+               sendp2(p);
+               p = putassign( cp1, addrof(putch1(q)) );
+               sendp2(p);
+       }
+}
+
+/*
+ * Create a tree that can later be converted to an OREG.
+ */
+static NODE *
+oregtree(int off, int reg, int type)
+{
+       NODE *p, *q;
+
+       p = mklnode(REG, 0, reg, INCREF(type));
+       q = mklnode(ICON, off, 0, INT);
+       return mkunode(UMUL, mkbinode(PLUS, p, q, INCREF(type)), 0, type);
+}
+
+static NODE *
+putaddr(bigptr q, int indir)
+{
+       int type, type2, funct;
+       NODE *p, *p1, *p2;
+       ftnint offset;
+       bigptr offp;
+
+       p = p1 = p2 = NULL; /* XXX */
+
+       type = q->vtype;
+       type2 = types2[type];
+       funct = (q->vclass==CLPROC ? FTN<<TSHIFT : 0);
+
+       offp = (q->b_addr.memoffset ? cpexpr(q->b_addr.memoffset) : NULL);
+
+       offset = simoffset(&offp);
+       if(offp)
+               offp = mkconv(TYINT, offp);
+
+       switch(q->vstg) {
+       case STGAUTO:
+               if(indir && !offp) {
+                       p = oregtree(offset, AUTOREG, type2);
+                       break;
+               }
+
+               if(!indir && !offp && !offset) {
+                       p = mklnode(REG, 0, AUTOREG, INCREF(type2));
+                       break;
+               }
+
+               p = mklnode(REG, 0, AUTOREG, INCREF(type2));
+               if(offp) {
+                       p1 = putx(offp);
+                       if(offset)
+                               p2 = mklnode(ICON, offset, 0, INT);
+               } else
+                       p1 = mklnode(ICON, offset, 0, INT);
+               if (offp && offset)
+                       p1 = mkbinode(PLUS, p1, p2, INCREF(type2));
+               p = mkbinode(PLUS, p, p1, INCREF(type2));
+               if (indir)
+                       p = mkunode(UMUL, p, 0, type2);
+               break;
+
+       case STGARG:
+               p = oregtree(ARGOFFSET + (ftnint)(q->b_addr.memno),
+                   ARGREG, INCREF(type2)|funct);
+
+               if (offp)
+                       p1 = putx(offp);
+               if (offset)
+                       p2 = mklnode(ICON, offset, 0, INT);
+               if (offp && offset)
+                       p1 = mkbinode(PLUS, p1, p2, INCREF(type2));
+               else if (offset)
+                       p1 = p2;
+               if (offp || offset)
+                       p = mkbinode(PLUS, p, p1, INCREF(type2));
+               if (indir)
+                       p = mkunode(UMUL, p, 0, type2);
+               break;
+
+       case STGLENG:
+               if(indir) {
+                       p = oregtree(ARGOFFSET + (ftnint)(q->b_addr.memno),
+                           ARGREG, INCREF(type2)|funct);
+               } else  {
+                       fatal1("faddrnode: STGLENG: fixme!");
+#if 0
+                       p2op(P2PLUS, types2[TYLENG] | P2PTR );
+                       p2reg(ARGREG, types2[TYLENG] | P2PTR );
+                       p2icon( ARGOFFSET +
+                               (ftnint) (FUDGEOFFSET*p->b_addr.memno), P2INT);
+#endif
+               }
+               break;
+
+
+       case STGBSS:
+       case STGINIT:
+       case STGEXT:
+       case STGCOMMON:
+       case STGEQUIV:
+       case STGCONST:
+               if(offp) {
+                       p1 = putx(offp);
+                       p2 = putmem(q, ICON, offset);
+                       p = mkbinode(PLUS, p1, p2, INCREF(type2));
+                       if(indir)
+                               p = mkunode(UMUL, p, 0, type2);
+               } else
+                       p = putmem(q, (indir ? NAME : ICON), offset);
+               break;
+
+       case STGREG:
+               if(indir)
+                       p = mklnode(REG, 0, q->b_addr.memno, type2);
+               else
+                       fatal("attempt to take address of a register");
+               break;
+
+       default:
+               fatal1("putaddr: invalid vstg %d", q->vstg);
+       }
+       frexpr(q);
+       return p;
+}
+
+NODE *
+putmem(bigptr q, int class, ftnint offset)
+{
+       NODE *p;
+       int type2;
+
+       type2 = types2[q->vtype];
+       if(q->vclass == CLPROC)
+               type2 |= (FTN<<TSHIFT);
+       if (class == ICON)
+               type2 |= PTR;
+       p = mklnode(class, offset, 0, type2);
+       p->n_name = copys(memname(q->vstg, q->b_addr.memno));
+       return p;
+}
+
+
+\f
+LOCAL struct bigblock *
+putcall(struct bigblock *qq)
+{
+       chainp arglist, charsp, cp;
+       int n, first;
+       struct bigblock *t;
+       struct bigblock *q;
+       struct bigblock *fval;
+       int type, type2, ctype, indir;
+       NODE *lp, *p1, *p2;
+
+       lp = p2 = NULL; /* XXX */
+
+       type2 = types2[type = qq->vtype];
+       charsp = NULL;
+       indir =  (qq->b_expr.opcode == OPCCALL);
+       n = 0;
+       first = YES;
+
+       if(qq->b_expr.rightp) {
+               arglist = qq->b_expr.rightp->b_list.listp;
+               ckfree(qq->b_expr.rightp);
+       } else
+               arglist = NULL;
+
+       for(cp = arglist ; cp ; cp = cp->chain.nextp)
+               if(indir) {
+                       ++n;
+               } else {
+                       q = cp->chain.datap;
+                       if(q->tag == TCONST)
+                               cp->chain.datap = q = putconst(q);
+                       if( ISCHAR(q) ) {
+                               charsp = hookup(charsp,
+                                   mkchain(cpexpr(q->vleng), 0) );
+                               n += 2;
+                       } else if(q->vclass == CLPROC) {
+                               charsp = hookup(charsp,
+                                   mkchain( MKICON(0) , 0));
+                               n += 2;
+                       } else
+                               n += 1;
+               }
+
+       if(type == TYCHAR) {
+               if( ISICON(qq->vleng) ) {
+                       fval = fmktemp(TYCHAR, qq->vleng);
+                       n += 2;
+               } else {
+                       err("adjustable character function");
+                       return NULL;
+               }
+       } else if(ISCOMPLEX(type)) {
+               fval = fmktemp(type, NULL);
+               n += 1;
+       } else
+               fval = NULL;
+
+       ctype = (fval ? P2INT : type2);
+       p1 = putaddr(qq->b_expr.leftp, NO);
+
+       if(fval) {
+               first = NO;
+               lp = putaddr( cpexpr(fval), NO);
+               if(type==TYCHAR)
+                       lp = mkbinode(CM, lp, putx(cpexpr(qq->vleng)), INT);
+       }
+
+       for(cp = arglist ; cp ; cp = cp->chain.nextp) {
+               q = cp->chain.datap;
+               if(q->tag==TADDR && (indir || q->vstg!=STGREG) )
+                       p2 = putaddr(q, indir && q->vtype!=TYCHAR);
+               else if( ISCOMPLEX(q->vtype) )
+                       p2 = putcxop(q);
+               else if (ISCHAR(q) ) {
+                       p2 = putchop(q);
+               } else if( ! ISERROR(q) ) {
+                       if(indir)
+                               p2 = putx(q);
+                       else    {
+                               t = fmktemp(q->vtype, q->vleng);
+                               p2 = putassign( cpexpr(t), q );
+                               sendp2(p2);
+                               p2 = putaddr(t, NO);
+                       }
+               }
+               if(first) {
+                       first = NO;
+                       lp = p2;
+               } else
+                       lp = mkbinode(CM, lp, p2, INT);
+       }
+
+       if(arglist)
+               frchain(&arglist);
+       for(cp = charsp ; cp ; cp = cp->chain.nextp) {
+               p2 = putx( mkconv(TYLENG,cp->chain.datap) );
+               lp = mkbinode(CM, lp, p2, INT);
+       }
+       frchain(&charsp);
+       if (n > 0)
+               callval = mkbinode(CALL, p1, lp, ctype);
+       else
+               callval = mkunode(UCALL, p1, 0, ctype);
+       ckfree(qq);
+       return(fval);
+}
+
+/*
+ * Write out code to do min/max calculations.
+ * Note that these operators may have multiple arguments in fortran.
+ */
+LOCAL NODE *
+putmnmx(struct bigblock *p)
+{
+       NODE *n1, *n2;
+       int op, type, lab;
+       chainp p0, p1;
+       struct bigblock *tp;
+
+       type = p->vtype;
+       op = (p->b_expr.opcode==OPMIN ? LT : GT );
+       p0 = p->b_expr.leftp->b_list.listp;
+       ckfree(p->b_expr.leftp);
+       ckfree(p);
+
+       /*
+        * Store first value in a temporary, then compare it with 
+        * each following value and save that if needed.
+        */
+       tp = fmktemp(type, NULL);
+       sendp2(putassign(cpexpr(tp), p0->chain.datap));
+
+       for(p1 = p0->chain.nextp ; p1 ; p1 = p1->chain.nextp) {
+               n1 = putx(cpexpr(tp));
+               n2 = putx(cpexpr(p1->chain.datap));
+               lab = newlabel();
+               sendp2(mkbinode(CBRANCH, mkbinode(op, n1, n2, INT), 
+                   mklnode(ICON, lab, 0, INT), INT));
+               sendp2(putassign(cpexpr(tp), p1->chain.datap));
+               putlabel(lab);
+       }
+       return putx(tp);
+}
+
+ftnint
+simoffset(bigptr *p0)
+{
+       ftnint offset, prod;
+       bigptr p, lp, rp;
+
+       offset = 0;
+       p = *p0;
+       if(p == NULL)
+               return(0);
+
+       if( ! ISINT(p->vtype) )
+               return(0);
+
+       if(p->tag==TEXPR && p->b_expr.opcode==OPSTAR) {
+               lp = p->b_expr.leftp;
+               rp = p->b_expr.rightp;
+               if(ISICON(rp) && lp->tag==TEXPR &&
+                   lp->b_expr.opcode==OPPLUS && ISICON(lp->b_expr.rightp)) {
+                       p->b_expr.opcode = OPPLUS;
+                       lp->b_expr.opcode = OPSTAR;
+                       prod = rp->b_const.fconst.ci *
+                           lp->b_expr.rightp->b_const.fconst.ci;
+                       lp->b_expr.rightp->b_const.fconst.ci =
+                           rp->b_const.fconst.ci;
+                       rp->b_const.fconst.ci = prod;
+               }
+       }
+
+       if(p->tag==TEXPR && p->b_expr.opcode==OPPLUS &&
+           ISICON(p->b_expr.rightp)) {
+               rp = p->b_expr.rightp;
+               lp = p->b_expr.leftp;
+               offset += rp->b_const.fconst.ci;
+               frexpr(rp);
+               ckfree(p);
+               *p0 = lp;
+       }
+
+       if(p->tag == TCONST) {
+               offset += p->b_const.fconst.ci;
+               frexpr(p);
+               *p0 = NULL;
+       }
+
+       return(offset);
+}
+
+/*
+ * F77 uses ckalloc() (malloc) for NODEs.
+ */
+NODE *
+talloc()
+{
+       NODE *p = ckalloc(sizeof(NODE));
+       p->n_name = "";
+       return p;
+}
+
+#ifdef PCC_DEBUG
+static char *tagnam[] = {
+ "NONE", "NAME", "CONST", "EXPR", "ADDR", "PRIM", "LIST", "IMPLDO", "ERROR",
+};
+static char *typnam[] = {
+ "unknown", "addr", "short", "long", "real", "dreal", "complex", "dcomplex",
+ "logical", "char", "subr", "error",
+};
+static char *classnam[] = {
+ "unknown", "param", "var", "entry", "main", "block", "proc",
+};
+static char *stgnam[] = {
+ "unknown", "arg", "auto", "bss", "init", "const", "intr", "stfunct",
+ "common", "equiv", "reg", "leng",
+};
+
+
+/*
+ * Print out a f77 tree, for diagnostic purposes.
+ */
+void
+fprint(bigptr p, int indx)
+{
+       extern char *ops[];
+       int x = indx;
+       bigptr lp, rp;
+       struct chain *bp;
+
+       if (p == NULL)
+               return;
+
+       while (x >= 2) {
+               putchar('\t');
+               x -= 2;
+       }
+       if (x--)
+               printf("    " );
+       printf("%p) %s, ", p, tagnam[p->tag]);
+       if (p->vtype)
+               printf("type=%s, ", typnam[p->vtype]);
+       if (p->vclass)
+               printf("class=%s, ", classnam[p->vclass]);
+       if (p->vstg)
+               printf("stg=%s, ", stgnam[p->vstg]);
+
+       lp = rp = NULL;
+       switch (p->tag) {
+       case TEXPR:
+               printf("OP %s\n", ops[p->b_expr.opcode]);
+               lp = p->b_expr.leftp;
+               rp = p->b_expr.rightp;
+               break;
+       case TADDR:
+               printf("memno=%d\n", p->b_addr.memno);
+               lp = p->vleng;
+               rp = p->b_addr.memoffset;
+               break;
+       case TCONST:
+               switch (p->vtype) {
+               case TYSHORT:
+               case TYLONG:
+               case TYLOGICAL:
+               case TYADDR:
+                       printf("val=%ld\n", p->b_const.fconst.ci);
+                       break;
+               case TYCHAR:
+                       lp = p->vleng;
+                       printf("\n");
+                       break;
+               }
+               break;
+       case TPRIM:
+               lp = p->b_prim.namep;
+               rp = p->b_prim.argsp;
+               printf("fcharp=%p, lcharp=%p\n", p->b_prim.fcharp, p->b_prim.lcharp);
+               break;
+       case TNAME:
+               printf("name=%s\n", p->b_name.varname);
+               break;
+       case TLIST:
+               printf("\n");
+               for (bp = &p->b_list.listp->chain; bp; bp = &bp->nextp->chain)
+                       fprint(bp->datap, indx+1);
+               break;
+       default:
+               printf("\n");
+       }
+
+       fprint(lp, indx+1);
+       fprint(rp, indx+1);
+}
+#endif
diff --git a/lang/pcc/pcc/f77/fcom/scjdefs.h b/lang/pcc/pcc/f77/fcom/scjdefs.h
new file mode 100644 (file)
index 0000000..dcc6bc8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Map pass2 nodes to pass1 dito.
+ */
+#include "node.h"
+
+
+#define P2BAD -1
+#define P2PLUS PLUS
+#define P2MINUS MINUS
+#define P2NEG UMINUS
+#define P2STAR MUL
+#define P2BITAND AND
+#define P2BITOR OR
+#define P2BITXOR ER
+#define P2GOTO GOTO
+#define P2ASSIGN ASSIGN
+#define P2SLASH DIV
+#define P2MOD MOD
+#define P2LSHIFT LS
+#define P2RSHIFT RS
+#define P2CALL CALL
+#define P2CALL0 UCALL
+
+#define P2BITNOT -1
+#define P2EQ EQ
+#define P2NE NE
+#define P2LE LE
+#define P2LT LT
+#define P2GE GE
+#define P2GT GT
+#define        P2CONV  SCONV
+
+/* special operators included only for fortran's use */
+
+#define P2INT INT
+
+#define P2PTR PTR
diff --git a/lang/pcc/pcc/f77/fcom/tokens b/lang/pcc/pcc/f77/fcom/tokens
new file mode 100644 (file)
index 0000000..aefeb33
--- /dev/null
@@ -0,0 +1,95 @@
+SEOS
+SCOMMENT
+SLABEL
+SUNKNOWN
+SHOLLERITH
+SICON
+SRCON
+SDCON
+SBITCON
+SOCTCON
+SHEXCON
+STRUE
+SFALSE
+SFNAME
+SNAMEEQ
+SFIELD
+SSCALE
+SINCLUDE
+SLET
+SASSIGN
+SAUTOMATIC
+SBACKSPACE
+SBLOCK
+SCALL
+SCHARACTER
+SCLOSE
+SCOMMON
+SCOMPLEX
+SCONTINUE
+SDATA
+SDCOMPLEX
+SDIMENSION
+SDO
+SDOUBLE
+SELSE
+SELSEIF
+SEND
+SENDFILE
+SENDIF
+SENTRY
+SEQUIV
+SEXTERNAL
+SFORMAT
+SFUNCTION
+SGOTO
+SASGOTO
+SCOMPGOTO
+SARITHIF
+SLOGIF
+SIMPLICIT
+SINQUIRE
+SINTEGER
+SINTRINSIC
+SLOGICAL
+SOPEN
+SPARAM
+SPAUSE
+SPRINT
+SPROGRAM
+SPUNCH
+SREAD
+SREAL
+SRETURN
+SREWIND
+SSAVE
+SSTATIC
+SSTOP
+SSUBROUTINE
+STHEN
+STO
+SUNDEFINED
+SWRITE
+SLPAR
+SRPAR
+SEQUALS
+SCOLON
+SCOMMA
+SCURRENCY
+SPLUS
+SMINUS
+SSTAR
+SSLASH
+SPOWER
+SCONCAT
+SAND
+SOR
+SNEQV
+SEQV
+SNOT
+SEQ
+SLT
+SGT
+SLE
+SGE
+SNE
diff --git a/lang/pcc/pcc/install-sh b/lang/pcc/pcc/install-sh
new file mode 100755 (executable)
index 0000000..0ec27bc
--- /dev/null
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd=$cpprog
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd=$stripprog
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "$0: no input file specified" >&2
+       exit 1
+else
+       :
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+
+       if [ -d "$dst" ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=$mkdirprog
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f "$src" ] || [ -d "$src" ]
+       then
+               :
+       else
+               echo "$0: $src does not exist" >&2
+               exit 1
+       fi
+
+       if [ x"$dst" = x ]
+       then
+               echo "$0: no destination specified" >&2
+               exit 1
+       else
+               :
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d "$dst" ]
+       then
+               dst=$dst/`basename "$src"`
+       else
+               :
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+       '
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp=$pathcomp$1
+       shift
+
+       if [ ! -d "$pathcomp" ] ;
+        then
+               $mkdirprog "$pathcomp"
+       else
+               :
+       fi
+
+       pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd "$dst" &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ]
+       then
+               dstfile=`basename "$dst"`
+       else
+               dstfile=`basename "$dst" $transformbasename |
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ]
+       then
+               dstfile=`basename "$dst"`
+       else
+               :
+       fi
+
+# Make a couple of temp file names in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+       rmtmp=$dstdir/#rm.$$#
+
+# Trap to clean up temp files at exit.
+
+       trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+       trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd "$src" "$dsttmp" &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# Now remove or move aside any old file at destination location.  We try this
+# two ways since rm can't unlink itself on some systems and the destination
+# file might be busy for other reasons.  In this case, the final cleanup
+# might fail but the new file should still install successfully.
+
+{
+       if [ -f "$dstdir/$dstfile" ]
+       then
+               $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+               $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+               {
+                 echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+                 (exit 1); exit
+               }
+       else
+               :
+       fi
+} &&
+
+# Now rename the file to the real destination.
+
+       $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+       (exit 0); exit
+}
diff --git a/lang/pcc/pcc/mip/common.c b/lang/pcc/pcc/mip/common.c
new file mode 100644 (file)
index 0000000..96917e9
--- /dev/null
@@ -0,0 +1,1012 @@
+/*     $Id: common.c,v 1.122 2015/09/30 20:04:30 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pass2.h"
+#include "unicode.h"
+
+# ifndef EXIT
+# define EXIT exit
+# endif
+
+int nerrors = 0;  /* number of errors */
+extern char *ftitle;
+int lineno;
+int savstringsz, newattrsz, nodesszcnt;
+
+int warniserr = 0;
+
+#ifndef WHERE
+#define        WHERE(ch) fprintf(stderr, "%s, line %d: ", ftitle, lineno);
+#endif
+
+static void
+incerr(void)
+{
+       if (++nerrors > 30)
+               cerror("too many errors");
+}
+
+/*
+ * nonfatal error message
+ * the routine where is different for pass 1 and pass 2;
+ * it tells where the error took place
+ */
+void
+uerror(const char *s, ...)
+{
+       va_list ap;
+
+       va_start(ap, s);
+       WHERE('u');
+       vfprintf(stderr, s, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       incerr();
+}
+
+/*
+ * compiler error: die
+ */
+void
+cerror(const char *s, ...)
+{
+       va_list ap;
+
+       va_start(ap, s);
+       WHERE('c');
+
+       /* give the compiler the benefit of the doubt */
+       if (nerrors && nerrors <= 30) {
+               fprintf(stderr,
+                   "cannot recover from earlier errors: goodbye!\n");
+       } else {
+               fprintf(stderr, "compiler error: ");
+               vfprintf(stderr, s, ap);
+               fprintf(stderr, "\n");
+       }
+       va_end(ap);
+       EXIT(1);
+}
+
+/*
+ * warning
+ */
+void
+u8error(const char *s, ...)
+{
+       va_list ap;
+       va_start(ap, s);
+       WHERE('w');
+       fprintf(stderr, "warning: ");
+       vfprintf(stderr, s, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       if (warniserr)
+               incerr();
+}
+
+#ifdef MKEXT
+int wdebug;
+#endif
+
+/*
+ * warning
+ */
+void
+werror(const char *s, ...)
+{
+       extern int wdebug;
+       va_list ap;
+
+       if (wdebug)
+               return;
+       va_start(ap, s);
+       WHERE('w');
+       fprintf(stderr, "warning: ");
+       vfprintf(stderr, s, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       if (warniserr)
+               incerr();
+}
+
+#ifndef MKEXT
+
+struct Warning {
+       char *flag;
+       char warn;
+       char err;
+       char *fmt;
+};
+
+/*
+ * conditional warnings
+ */
+struct Warning Warnings[] = {
+       {
+               "truncate", 0, 0,
+               "conversion from '%s' to '%s' may alter its value"
+       }, {
+               "strict-prototypes", 0, 0,
+               "function declaration isn't a prototype"
+       }, {
+               "missing-prototypes", 0, 0,
+               "no previous prototype for `%s'"
+       }, {
+               "implicit-int", 0, 0,
+               "return type defaults to `int'",
+       }, {
+               "implicit-function-declaration", 0, 0,
+               "implicit declaration of function '%s'"
+       }, {
+               "shadow", 0, 0,
+               "declaration of '%s' shadows a %s declaration"
+       }, {
+               "pointer-sign", 0, 0,
+               "illegal pointer combination"
+       }, {
+               "sign-compare", 0, 0,
+               "comparison between signed and unsigned"
+       }, {
+               "unknown-pragmas", 0, 0,
+               "ignoring #pragma %s %s"
+       }, {
+               "unreachable-code", 0, 0,
+               "statement not reached"
+       }, {
+               "deprecated-declarations", 1, 0,
+               "`%s' is deprecated"
+       }, {
+               "attributes", 1, 0,
+               "unsupported attribute `%s'"
+       }, {    NULL    }
+};
+
+/*
+ * set the warn/err status of a conditional warning
+ */
+int
+Wset(char *str, int warn, int err)
+{
+       struct Warning *w = Warnings;
+
+       for (w = Warnings; w->flag; w++) {
+               if (strcmp(w->flag, str) == 0) {
+                       w->warn = warn;
+                       w->err = err;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+/*
+ * handle a conditional warning flag.
+ */
+void
+Wflags(char *str)
+{
+       struct Warning *w;
+       int isset, iserr;
+
+       /* handle -Werror specially */
+       if (strcmp("error", str) == 0) {
+               for (w = Warnings; w->flag; w++)
+                       w->err = 1;
+
+               warniserr = 1;
+               return;
+       }
+
+       isset = 1;
+       if (strncmp("no-", str, 3) == 0) {
+               str += 3;
+               isset = 0;
+       }
+
+       iserr = 0;
+       if (strncmp("error=", str, 6) == 0) {
+               str += 6;
+               iserr = 1;
+       }
+
+       for (w = Warnings; w->flag; w++) {
+               if (strcmp(w->flag, str) != 0)
+                       continue;
+
+               if (isset) {
+                       if (iserr)
+                               w->err = 1;
+                       w->warn = 1;
+               } else if (iserr) {
+                       w->err = 0;
+               } else {
+                       w->warn = 0;
+               }
+
+               return;
+       }
+
+       fprintf(stderr, "unrecognised warning option '%s'\n", str);
+}
+
+/*
+ * emit a conditional warning
+ */
+void
+warner(int type, ...)
+{
+       va_list ap;
+       char *t;
+#ifndef PASS2
+       extern int issyshdr;
+
+       if (issyshdr && type == Wtruncate)
+               return; /* Too many false positives */
+#endif
+
+       if (Warnings[type].warn == 0)
+               return; /* no warning */
+       if (Warnings[type].err) {
+               t = "error";
+               incerr();
+       } else
+               t = "warning";
+
+       va_start(ap, type);
+       fprintf(stderr, "%s:%d: %s: ", ftitle, lineno, t);
+       vfprintf(stderr, Warnings[type].fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+#endif /* MKEXT */
+
+#ifndef MKEXT
+static NODE *freelink;
+int usednodes;
+
+#ifndef LANG_F77
+NODE *
+talloc(void)
+{
+       register NODE *p;
+
+       usednodes++;
+
+       if (freelink != NULL) {
+               p = freelink;
+               freelink = p->n_left;
+               if (p->n_op != FREE)
+                       cerror("node not FREE: %p", p);
+               if (ndebug)
+                       printf("alloc node %p from freelist\n", p);
+               return p;
+       }
+
+       p = permalloc(sizeof(NODE));
+       nodesszcnt += sizeof(NODE);
+       p->n_op = FREE;
+       if (ndebug)
+               printf("alloc node %p from memory\n", p);
+       return p;
+}
+#endif
+
+/*
+ * make a fresh copy of p
+ */
+NODE *
+tcopy(NODE *p)
+{
+       NODE *q;
+
+       q = talloc();
+       *q = *p;
+
+       switch (optype(q->n_op)) {
+       case BITYPE:
+               q->n_right = tcopy(p->n_right);
+       case UTYPE:
+               q->n_left = tcopy(p->n_left);
+       }
+
+       return(q);
+}
+
+#ifndef LANG_F77
+/*
+ * ensure that all nodes have been freed
+ */
+void
+tcheck(void)
+{
+#ifdef LANG_CXX
+       extern int inlnodecnt;
+#else
+#define        inlnodecnt 0
+#endif
+
+       if (nerrors)
+               return;
+
+       if ((usednodes - inlnodecnt) != 0)
+               cerror("usednodes == %d, inlnodecnt %d", usednodes, inlnodecnt);
+}
+#endif
+
+/*
+ * free the tree p
+ */
+void
+tfree(NODE *p)
+{
+       if (p->n_op != FREE)
+               walkf(p, (void (*)(NODE *, void *))nfree, 0);
+}
+
+/*
+ * Free a node, and return its left descendant.
+ * It is up to the caller to know whether the return value is usable.
+ */
+NODE *
+nfree(NODE *p)
+{
+       NODE *l;
+#ifdef PCC_DEBUG_NODES
+       NODE *q;
+#endif
+
+       if (p == NULL)
+               cerror("freeing blank node!");
+               
+       l = p->n_left;
+       if (p->n_op == FREE)
+               cerror("freeing FREE node", p);
+#ifdef PCC_DEBUG_NODES
+       q = freelink;
+       while (q != NULL) {
+               if (q == p)
+                       cerror("freeing free node %p", p);
+               q = q->n_left;
+       }
+#endif
+
+       if (ndebug)
+               printf("freeing node %p\n", p);
+       p->n_op = FREE;
+       p->n_left = freelink;
+       freelink = p;
+       usednodes--;
+       return l;
+}
+#endif
+
+#ifdef LANG_F77
+#define OPTYPE(x) optype(x)
+#else
+#define OPTYPE(x) coptype(x)
+#endif
+
+#ifdef MKEXT
+#define coptype(o)     (dope[o]&TYFLG)
+#else
+#ifndef PASS2
+int cdope(int);
+#define coptype(o)     (cdope(o)&TYFLG)
+#else
+#define coptype(o)     (dope[o]&TYFLG)
+#endif
+#endif
+
+void
+fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down)
+{
+
+       int down1, down2;
+
+       more:
+       down1 = down2 = 0;
+
+       (*f)(t, down, &down1, &down2);
+
+       switch (OPTYPE( t->n_op )) {
+
+       case BITYPE:
+               fwalk( t->n_left, f, down1 );
+               t = t->n_right;
+               down = down2;
+               goto more;
+
+       case UTYPE:
+               t = t->n_left;
+               down = down1;
+               goto more;
+
+       }
+}
+
+void
+walkf(NODE *t, void (*f)(NODE *, void *), void *arg)
+{
+       int opty;
+
+
+       opty = OPTYPE(t->n_op);
+
+       if (opty != LTYPE)
+               walkf( t->n_left, f, arg );
+       if (opty == BITYPE)
+               walkf( t->n_right, f, arg );
+       (*f)(t, arg);
+}
+
+int dope[DSIZE];
+char *opst[DSIZE];
+
+struct dopest {
+       int dopeop;
+       char opst[8];
+       int dopeval;
+} indope[] = {
+       { NAME, "NAME", LTYPE, },
+       { REG, "REG", LTYPE, },
+       { OREG, "OREG", LTYPE, },
+       { TEMP, "TEMP", LTYPE, },
+       { ICON, "ICON", LTYPE, },
+       { FCON, "FCON", LTYPE, },
+       { CCODES, "CCODES", LTYPE, },
+       { UMINUS, "U-", UTYPE, },
+       { UMUL, "U*", UTYPE, },
+       { FUNARG, "FUNARG", UTYPE, },
+       { UCALL, "UCALL", UTYPE|CALLFLG, },
+       { UFORTCALL, "UFCALL", UTYPE|CALLFLG, },
+       { COMPL, "~", UTYPE, },
+       { FORCE, "FORCE", UTYPE, },
+       { XARG, "XARG", UTYPE, },
+       { XASM, "XASM", BITYPE, },
+       { SCONV, "SCONV", UTYPE, },
+       { PCONV, "PCONV", UTYPE, },
+       { PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, },
+       { MINUS, "-", BITYPE|FLOFLG|SIMPFLG, },
+       { MUL, "*", BITYPE|FLOFLG|MULFLG, },
+       { AND, "&", BITYPE|SIMPFLG|COMMFLG, },
+       { CM, ",", BITYPE, },
+       { ASSIGN, "=", BITYPE|ASGFLG, },
+       { DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG, },
+       { MOD, "%", BITYPE|DIVFLG, },
+       { LS, "<<", BITYPE|SHFFLG, },
+       { RS, ">>", BITYPE|SHFFLG, },
+       { OR, "|", BITYPE|COMMFLG|SIMPFLG, },
+       { ER, "^", BITYPE|COMMFLG|SIMPFLG, },
+       { CALL, "CALL", BITYPE|CALLFLG, },
+       { FORTCALL, "FCALL", BITYPE|CALLFLG, },
+       { EQ, "==", BITYPE|LOGFLG, },
+       { NE, "!=", BITYPE|LOGFLG, },
+       { LE, "<=", BITYPE|LOGFLG, },
+       { LT, "<", BITYPE|LOGFLG, },
+       { GE, ">=", BITYPE|LOGFLG, },
+       { GT, ">", BITYPE|LOGFLG, },
+       { UGT, "UGT", BITYPE|LOGFLG, },
+       { UGE, "UGE", BITYPE|LOGFLG, },
+       { ULT, "ULT", BITYPE|LOGFLG, },
+       { ULE, "ULE", BITYPE|LOGFLG, },
+       { CBRANCH, "CBRANCH", BITYPE, },
+       { FLD, "FLD", UTYPE, },
+       { PMCONV, "PMCONV", BITYPE, },
+       { PVCONV, "PVCONV", BITYPE, },
+       { RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG, },
+       { GOTO, "GOTO", UTYPE, },
+       { STASG, "STASG", BITYPE|ASGFLG, },
+       { STARG, "STARG", UTYPE, },
+       { STCALL, "STCALL", BITYPE|CALLFLG, },
+       { USTCALL, "USTCALL", UTYPE|CALLFLG, },
+       { ADDROF, "U&", UTYPE, },
+
+       { -1,   "",     0 },
+};
+
+void
+mkdope(void)
+{
+       struct dopest *q;
+
+       for( q = indope; q->dopeop >= 0; ++q ){
+               dope[q->dopeop] = q->dopeval;
+               opst[q->dopeop] = q->opst;
+       }
+}
+
+/*
+ * output a nice description of the type of t
+ */
+void
+tprint(TWORD t, TWORD q)
+{
+       static char * tnames[BTMASK+1] = {
+               "undef",
+               "bool",
+               "char",
+               "uchar",
+               "short",
+               "ushort",
+               "int",
+               "unsigned",
+               "long",
+               "ulong",
+               "longlong",
+               "ulonglong",
+               "float",
+               "double",
+               "ldouble",
+               "strty",
+               "unionty",
+               "enumty",
+               "moety",
+               "void",
+               "signed", /* pass1 */
+               "farg", /* pass1 */
+               "fimag", /* pass1 */
+               "dimag", /* pass1 */
+               "limag", /* pass1 */
+               "fcomplex", /* pass1 */
+               "dcomplex", /* pass1 */
+               "lcomplex", /* pass1 */
+               "enumty", /* pass1 */
+               "?", "?", "?"
+               };
+
+       for(;; t = DECREF(t), q = DECREF(q)) {
+               if (ISCON(q))
+                       putchar('C');
+               if (ISVOL(q))
+                       putchar('V');
+
+               if (ISPTR(t))
+                       printf("PTR ");
+               else if (ISFTN(t))
+                       printf("FTN ");
+               else if (ISARY(t))
+                       printf("ARY ");
+               else {
+                       printf("%s%s%s", ISCON(q << TSHIFT) ? "const " : "",
+                           ISVOL(q << TSHIFT) ? "volatile " : "", tnames[t]);
+                       return;
+               }
+       }
+}
+
+/*
+ * Memory allocation routines.
+ * Memory are allocated from the system in MEMCHUNKSZ blocks.
+ * permalloc() returns a bunch of memory that is never freed.
+ * Memory allocated through tmpalloc() will be released the
+ * next time a function is ended (via tmpfree()).
+ */
+
+#define        MEMCHUNKSZ 8192 /* 8k per allocation */
+struct balloc {
+       char a1;
+       union {
+               long long l;
+               long double d;
+       } a2;
+};
+
+#define        ALIGNMENT offsetof(struct balloc, a2)
+#define        ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1))
+
+static char *allocpole;
+static size_t allocleft;
+size_t permallocsize, tmpallocsize, lostmem;
+
+void *
+permalloc(size_t size)
+{
+       void *rv;
+
+       if (size > MEMCHUNKSZ) {
+               if ((rv = malloc(size)) == NULL)
+                       cerror("permalloc: missing %d bytes", size);
+               return rv;
+       }
+       if (size == 0)
+               cerror("permalloc2");
+       if (allocleft < size) {
+               /* loses unused bytes */
+               lostmem += allocleft;
+               if ((allocpole = malloc(MEMCHUNKSZ)) == NULL)
+                       cerror("permalloc: out of memory");
+               allocleft = MEMCHUNKSZ;
+       }
+       size = ROUNDUP(size);
+       rv = &allocpole[MEMCHUNKSZ-allocleft];
+       allocleft -= size;
+       permallocsize += size;
+       return rv;
+}
+
+void *
+tmpcalloc(size_t size)
+{
+       void *rv;
+
+       rv = tmpalloc(size);
+       memset(rv, 0, size);
+       return rv;
+}
+
+/*
+ * Duplicate a string onto the temporary heap.
+ */
+char *
+tmpstrdup(char *str)
+{
+       size_t len;
+
+       len = strlen(str) + 1;
+       return memcpy(tmpalloc(len), str, len);
+}
+
+/*
+ * Allocation routines for temporary memory.
+ */
+#if 0
+#define        ALLDEBUG(x)     printf x
+#else
+#define        ALLDEBUG(x)
+#endif
+
+#define        NELEM   ((MEMCHUNKSZ-ROUNDUP(sizeof(struct xalloc *)))/ALIGNMENT)
+#define        ELEMSZ  (ALIGNMENT)
+#define        MAXSZ   (NELEM*ELEMSZ)
+struct xalloc {
+       struct xalloc *next;
+       union {
+               struct balloc b; /* for initial alignment */
+               char elm[MAXSZ];
+       } u;
+} *tapole, *tmpole;
+int uselem = NELEM; /* next unused element */
+
+void *
+tmpalloc(size_t size)
+{
+       struct xalloc *xp;
+       void *rv;
+       size_t nelem;
+
+       nelem = ROUNDUP(size)/ELEMSZ;
+       ALLDEBUG(("tmpalloc(%ld,%ld) %zd (%zd) ", ELEMSZ, NELEM, size, nelem));
+       if (nelem > NELEM/2) {
+               size += ROUNDUP(sizeof(struct xalloc *));
+               if ((xp = malloc(size)) == NULL)
+                       cerror("out of memory");
+               ALLDEBUG(("XMEM! (%zd,%p) ", size, xp));
+               xp->next = tmpole;
+               tmpole = xp;
+               ALLDEBUG(("rv %p\n", &xp->u.elm[0]));
+               return &xp->u.elm[0];
+       }
+       if (nelem + uselem >= NELEM) {
+               ALLDEBUG(("MOREMEM! "));
+               /* alloc more */
+               if ((xp = malloc(sizeof(struct xalloc))) == NULL)
+                       cerror("out of memory");
+               xp->next = tapole;
+               tapole = xp;
+               uselem = 0;
+       } else
+               xp = tapole;
+       rv = &xp->u.elm[uselem * ELEMSZ];
+       ALLDEBUG(("elemno %d ", uselem));
+       uselem += nelem;
+       ALLDEBUG(("new %d rv %p\n", uselem, rv));
+       return rv;
+}
+
+void
+tmpfree(void)
+{
+       struct xalloc *x1;
+
+       while (tmpole) {
+               x1 = tmpole;
+               tmpole = tmpole->next;
+               ALLDEBUG(("XMEM! free %p\n", x1));
+               free(x1);
+       }
+       while (tapole && tapole->next) {
+               x1 = tapole;
+               tapole = tapole->next;
+               ALLDEBUG(("MOREMEM! free %p\n", x1));
+               free(x1);
+       }
+       if (tapole)
+               uselem = 0;
+}
+
+/*
+ * Set a mark for later removal from the temp heap.
+ */
+void
+markset(struct mark *m)
+{
+       m->tmsav = tmpole;
+       m->tasav = tapole;
+       m->elem = uselem;
+}
+
+/*
+ * Remove everything on tmp heap from a mark.
+ */
+void
+markfree(struct mark *m)
+{
+       struct xalloc *x1;
+
+       while (tmpole != m->tmsav) {
+               x1 = tmpole;
+               tmpole = tmpole->next;
+               free(x1);
+       }
+       while (tapole != m->tasav) {
+               x1 = tapole;
+               tapole = tapole->next;
+               free(x1);
+       }
+       uselem = m->elem;
+}
+
+/*
+ * Allocate space on the permanent stack for a string of length len+1
+ * and copy it there.
+ * Return the new address.
+ */
+char *
+newstring(char *s, size_t len)
+{
+       char *u, *c;
+
+       len++;
+       savstringsz += len;
+       if (allocleft < len) {
+               u = c = permalloc(len);
+       } else {
+               u = c = &allocpole[MEMCHUNKSZ-allocleft];
+               allocleft -= ROUNDUP(len);
+               permallocsize += ROUNDUP(len);
+       }
+       while (len--)
+               *c++ = *s++;
+       return u;
+}
+
+/*
+ * Do a preorder walk of the CM list p and apply function f on each element.
+ */
+void
+flist(NODE *p, void (*f)(NODE *, void *), void *arg)
+{
+       if (p->n_op == CM) {
+               (*f)(p->n_right, arg);
+               flist(p->n_left, f, arg);
+       } else
+               (*f)(p, arg);
+}
+
+/*
+ * The same as flist but postorder.
+ */
+void
+listf(NODE *p, void (*f)(NODE *))
+{
+       if (p->n_op == CM) {
+               listf(p->n_left, f);
+               (*f)(p->n_right);
+       } else
+               (*f)(p);
+}
+
+/*
+ * Get list argument number n from list, or NIL if out of list.
+ */
+NODE *
+listarg(NODE *p, int n, int *cnt)
+{
+       NODE *r;
+
+       if (p->n_op == CM) {
+               r = listarg(p->n_left, n, cnt);
+               if (n == ++(*cnt))
+                       r = p->n_right;
+       } else {
+               *cnt = 0;
+               r = n == 0 ? p : NIL;
+       }
+       return r;
+}
+
+/*
+ * Make a type unsigned, if possible.
+ */
+TWORD
+enunsign(TWORD t)
+{
+       if (BTYPE(t) >= CHAR && BTYPE(t) <= ULONGLONG)
+               t |= 1;
+       return t;
+}
+
+/*
+ * Make a type signed, if possible.
+ */
+TWORD
+deunsign(TWORD t)
+{
+       if (BTYPE(t) >= CHAR && BTYPE(t) <= ULONGLONG)
+               t &= ~1;
+       return t;
+}
+
+/*
+ * Attribute functions.
+ */
+struct attr *
+attr_new(int type, int nelem)
+{
+       struct attr *ap;
+       int sz;
+
+       sz = sizeof(struct attr) + nelem * sizeof(union aarg);
+
+       ap = memset(permalloc(sz), 0, sz);
+       newattrsz += sz;
+       ap->atype = type;
+       ap->sz = nelem;
+       return ap;
+}
+
+/*
+ * Add attribute list new before old and return new.
+ */
+struct attr *
+attr_add(struct attr *old, struct attr *new)
+{
+       struct attr *ap;
+
+       if (new == NULL)
+               return old; /* nothing to add */
+
+       for (ap = new; ap->next; ap = ap->next)
+               ;
+       ap->next = old;
+       return new;
+}
+
+/*
+ * Search for attribute type in list ap.  Return entry or NULL.
+ */
+struct attr *
+attr_find(struct attr *ap, int type)
+{
+
+       for (; ap && ap->atype != type; ap = ap->next)
+               ;
+       return ap;
+}
+
+/*
+ * Copy an attribute struct.
+ * Return destination.
+ */
+struct attr *
+attr_copy(struct attr *aps, struct attr *apd, int n)
+{
+       int sz = sizeof(struct attr) + n * sizeof(union aarg);
+       return memcpy(apd, aps, sz);
+}
+
+/*
+ * Duplicate an attribute, like strdup.
+ */
+struct attr *
+attr_dup(struct attr *ap)
+{
+       int sz = sizeof(struct attr) + ap->sz * sizeof(union aarg);
+       ap = memcpy(permalloc(sz), ap, sz);
+       ap->next = NULL;
+       return ap;
+}
+
+void *
+xmalloc(int size)
+{
+       void *rv;
+
+       if ((rv = malloc(size)) == NULL)
+               cerror("out of memory!");
+       return rv;
+}
+
+void *
+xstrdup(char *s)
+{
+       void *rv;
+
+       if ((rv = strdup(s)) == NULL)
+               cerror("out of memory!");
+       return rv;
+}
+
+void *
+xcalloc(int a, int b)
+{
+       void *rv;
+
+       if ((rv = calloc(a, b)) == NULL)
+               cerror("out of memory!");
+       return rv;
+}
diff --git a/lang/pcc/pcc/mip/manifest.h b/lang/pcc/pcc/mip/manifest.h
new file mode 100644 (file)
index 0000000..023479c
--- /dev/null
@@ -0,0 +1,405 @@
+/*     $Id: manifest.h,v 1.110 2015/08/11 20:08:22 ragge Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MANIFEST
+#define        MANIFEST
+
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "macdefs.h"
+#include "node.h"
+#include "compat.h"
+
+/*
+ * Node types
+ */
+#define LTYPE  02              /* leaf */
+#define UTYPE  04              /* unary */
+#define BITYPE 010             /* binary */
+
+/*
+ * DSIZE is the size of the dope array
+ */
+#define DSIZE  (MAXOP+1)
+
+/*
+ * Type names, used in symbol table building.
+ * The order of the integer types are important.
+ * Signed types must have bit 0 unset, unsigned types set (used below).
+ */
+#define        UNDEF           0       /* free symbol table entry */
+#define        BOOL            1       /* function argument */
+#define        CHAR            2
+#define        UCHAR           3
+#define        SHORT           4
+#define        USHORT          5
+#define        INT             6
+#define        UNSIGNED        7
+#define        LONG            8
+#define        ULONG           9      
+#define        LONGLONG        10
+#define        ULONGLONG       11
+#define        FLOAT           12
+#define        DOUBLE          13
+#define        LDOUBLE         14
+#define        STRTY           15
+#define        UNIONTY         16
+#define        XTYPE           17      /* Extended target-specific type */
+/* #define     MOETY           18 */   /* member of enum */
+#define        VOID            19
+
+#define        MAXTYPES        19      /* highest type+1 to be used by lang code */
+/*
+ * Various flags
+ */
+#define NOLAB  (-1)
+
+/* 
+ * Type modifiers.
+ */
+#define        PTR             0x20
+#define        FTN             0x40
+#define        ARY             0x60
+#define        CON             0x20
+#define        VOL             0x40
+
+/*
+ * Type packing constants
+ */
+#define TMASK  0x060
+#define TMASK1 0x180
+#define TMASK2 0x1e0
+#define BTMASK 0x1f
+#define BTSHIFT        5
+#define TSHIFT 2
+
+/*
+ * Macros
+ */
+#define MODTYPE(x,y)   x = ((x)&(~BTMASK))|(y) /* set basic type of x to y */
+#define BTYPE(x)       ((x)&BTMASK)            /* basic type of x */
+#define        ISLONGLONG(x)   ((x) == LONGLONG || (x) == ULONGLONG)
+#define ISUNSIGNED(x)  (((x) <= ULONGLONG) && (((x) & 1) == (UNSIGNED & 1)))
+#define UNSIGNABLE(x)  (((x)<=ULONGLONG&&(x)>=CHAR) && !ISUNSIGNED(x))
+#define ENUNSIGN(x)    enunsign(x)
+#define DEUNSIGN(x)    deunsign(x)
+#define ISINTEGER(x)   ((x) >= BOOL && (x) <= ULONGLONG)
+#define ISPTR(x)       (((x)&TMASK)==PTR)
+#define ISFTN(x)       (((x)&TMASK)==FTN)      /* is x a function type? */
+#define ISARY(x)       (((x)&TMASK)==ARY)      /* is x an array type? */
+#define        ISCON(x)        (((x)&CON)==CON)        /* is x const? */
+#define        ISVOL(x)        (((x)&VOL)==VOL)        /* is x volatile? */
+#define INCREF(x)      ((((x)&~BTMASK)<<TSHIFT)|PTR|((x)&BTMASK))
+#define INCQAL(x)      ((((x)&~BTMASK)<<TSHIFT)|((x)&BTMASK))
+#define DECREF(x)      ((((x)>>TSHIFT)&~BTMASK)|((x)&BTMASK))
+#define DECQAL(x)      ((((x)>>TSHIFT)&~BTMASK)|((x)&BTMASK))
+#define SETOFF(x,y)    { if ((x)%(y) != 0) (x) = (((x)/(y) + 1) * (y)); }
+               /* advance x to a multiple of y */
+#define NOFIT(x,y,z)   (((x)%(z) + (y)) > (z))
+               /* can y bits be added to x without overflowing z */
+
+/* Endianness. Target is expected to TARGET_ENDIAN to one of these  */
+#define TARGET_LE      1
+#define TARGET_BE      2
+#define TARGET_PDP     3
+#define TARGET_ANY     4
+
+#ifndef SPECIAL_INTEGERS
+#define        ASGLVAL(lval, val)
+#endif
+
+/*
+ * Pack and unpack field descriptors (size and offset)
+ */
+#define PKFIELD(s,o)   (((o)<<7)| (s))
+#define UPKFSZ(v)      ((v)&0177)
+#define UPKFOFF(v)     ((v)>>7)
+
+/*
+ * Operator information
+ */
+#define TYFLG  016
+#define ASGFLG 01
+#define LOGFLG 020
+
+#define SIMPFLG        040
+#define COMMFLG        0100
+#define DIVFLG 0200
+#define FLOFLG 0400
+#define LTYFLG 01000
+#define CALLFLG        02000
+#define MULFLG 04000
+#define SHFFLG 010000
+#define ASGOPFLG 020000
+
+#define SPFLG  040000
+
+#define        regno(p)        ((p)->n_rval)   /* register number */
+
+/*
+ * 
+ */
+extern int gflag, kflag, pflag;
+extern int sspflag;
+extern int xssa, xtailcall, xtemps, xdeljumps, xdce;
+extern int xuchar;
+
+int yyparse(void);
+void yyaccpt(void);
+
+/*
+ * List handling macros, similar to those in 4.4BSD.
+ * The double-linked list is insque-style.
+ */
+/* Double-linked list macros */
+#define        DLIST_INIT(h,f)         { (h)->f.q_forw = (h); (h)->f.q_back = (h); }
+#define        DLIST_ENTRY(t)          struct { struct t *q_forw, *q_back; }
+#define        DLIST_NEXT(h,f)         (h)->f.q_forw
+#define        DLIST_PREV(h,f)         (h)->f.q_back
+#define DLIST_ISEMPTY(h,f)     ((h)->f.q_forw == (h))
+#define DLIST_ENDMARK(h)       (h)
+#define        DLIST_FOREACH(v,h,f) \
+       for ((v) = (h)->f.q_forw; (v) != (h); (v) = (v)->f.q_forw)
+#define        DLIST_FOREACH_REVERSE(v,h,f) \
+       for ((v) = (h)->f.q_back; (v) != (h); (v) = (v)->f.q_back)
+#define        DLIST_INSERT_BEFORE(h,e,f) {    \
+       (e)->f.q_forw = (h);            \
+       (e)->f.q_back = (h)->f.q_back;  \
+       (e)->f.q_back->f.q_forw = (e);  \
+       (h)->f.q_back = (e);            \
+}
+#define        DLIST_INSERT_AFTER(h,e,f) {     \
+       (e)->f.q_forw = (h)->f.q_forw;  \
+       (e)->f.q_back = (h);            \
+       (e)->f.q_forw->f.q_back = (e);  \
+       (h)->f.q_forw = (e);            \
+}
+#define DLIST_REMOVE(e,f) {                     \
+       (e)->f.q_forw->f.q_back = (e)->f.q_back; \
+       (e)->f.q_back->f.q_forw = (e)->f.q_forw; \
+}
+
+/* Single-linked list */
+#define        SLIST_INIT(h)   \
+       { (h)->q_forw = NULL; (h)->q_last = &(h)->q_forw; }
+#define        SLIST_SETUP(h) { NULL, &(h)->q_forw }
+#define        SLIST_ENTRY(t)  struct { struct t *q_forw; }
+#define        SLIST_HEAD(n,t) struct n { struct t *q_forw, **q_last; }
+#define        SLIST_ISEMPTY(h) ((h)->q_last == &(h)->q_forw)
+#define        SLIST_FIRST(h)  ((h)->q_forw)
+#define        SLIST_FOREACH(v,h,f) \
+       for ((v) = (h)->q_forw; (v) != NULL; (v) = (v)->f.q_forw)
+#define        SLIST_INSERT_FIRST(h,e,f) {             \
+       if ((h)->q_last == &(h)->q_forw)        \
+               (h)->q_last = &(e)->f.q_forw;   \
+       (e)->f.q_forw = (h)->q_forw;            \
+       (h)->q_forw = (e);                      \
+}
+#define        SLIST_INSERT_LAST(h,e,f) {      \
+       (e)->f.q_forw = NULL;           \
+       *(h)->q_last = (e);             \
+       (h)->q_last = &(e)->f.q_forw;   \
+}
+
+#ifndef        MKEXT
+/*
+ * Functions for inter-pass communication.
+ *
+ */
+struct interpass {
+       DLIST_ENTRY(interpass) qelem;
+       int type;
+       int lineno;
+       union {
+               NODE *_p;
+               int _locctr;
+               int _label;
+               int _curoff;
+               char *_name;
+       } _un;
+};
+
+/*
+ * Special struct for prologue/epilogue.
+ * - ip_lblnum contains the lowest/highest+1 label used
+ * - ip_lbl is set before/after all code and after/before the prolog/epilog.
+ */
+struct interpass_prolog {
+       struct interpass ipp_ip;
+       char *ipp_name;         /* Function name */
+       int ipp_vis;            /* Function visibility */
+       TWORD ipp_type;         /* Function type */
+#define        NIPPREGS        BIT2BYTE(MAXREGS)/sizeof(bittype)
+       bittype ipp_regs[NIPPREGS];
+                               /* Bitmask of registers to save */
+       int ipp_autos;          /* Size on stack needed */
+       int ip_tmpnum;          /* # allocated temp nodes so far */
+       int ip_lblnum;          /* # used labels so far */
+       int *ip_labels;         /* labels used in computed goto */
+#ifdef TARGET_IPP_MEMBERS
+       TARGET_IPP_MEMBERS
+#endif
+};
+#else
+struct interpass { int dummy; };
+struct interpass_prolog;
+#endif /* !MKEXT */
+
+/*
+ * Epilog/prolog takes following arguments (in order):
+ * - type
+ * - regs
+ * - autos
+ * - name
+ * - type
+ * - retlab
+ */
+
+#define        ip_node _un._p
+#define        ip_locc _un._locctr
+#define        ip_lbl  _un._label
+#define        ip_name _un._name
+#define        ip_asm  _un._name
+#define        ip_off  _un._curoff
+
+/* Types of inter-pass structs */
+#define        IP_NODE         1
+#define        IP_PROLOG       2
+#define        IP_EPILOG       4
+#define        IP_DEFLAB       5
+#define        IP_DEFNAM       6
+#define        IP_ASM          7
+#define        MAXIP           7
+
+void send_passt(int type, ...);
+
+
+/*
+ * Attributes common to all passes.
+ */
+enum {
+       ATTR_NONE,
+#ifdef GCC_COMPAT
+       GCC_ATYP_STDCALL,
+       GCC_ATYP_CDECL,
+#endif
+#ifdef ATTR_MI_TARGET
+       ATTR_MI_TARGET,
+#endif
+       ATTR_MI_MAX
+};
+
+struct attr *attr_add(struct attr *orig, struct attr *new);
+struct attr *attr_new(int, int);
+struct attr *attr_find(struct attr *, int);
+struct attr *attr_copy(struct attr *src, struct attr *dst, int nelem);
+struct attr *attr_dup(struct attr *ap);
+
+/*
+ * External declarations, typedefs and the like
+ */
+
+/* used for memory allocation */
+typedef struct mark {
+       void *tmsav;
+       void *tasav;
+       int elem;
+} MARK;
+
+/* memory management stuff */
+void *permalloc(size_t);
+void *tmpcalloc(size_t);
+void *tmpalloc(size_t);
+void tmpfree(void);
+char *newstring(char *, size_t);
+char *tmpstrdup(char *str);
+void markset(struct mark *m);
+void markfree(struct mark *m);
+void *xmalloc(int size);
+void *xcalloc(int a, int b);
+void *xstrdup(char *s);
+
+int getlab(void);
+
+/* command-line processing */
+void mflags(char *);
+
+void tprint(TWORD, TWORD);
+
+/* pass t communication subroutines */
+void topt_compile(struct interpass *);
+
+/* pass 2 communication subroutines */
+void pass2_compile(struct interpass *);
+
+/* node routines */
+NODE *nfree(NODE *);
+void tfree(NODE *);
+NODE *tcopy(NODE *);
+void walkf(NODE *, void (*f)(NODE *, void *), void *);
+void fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down);
+void flist(NODE *p, void (*f)(NODE *, void *), void *);
+void listf(NODE *p, void (*f)(NODE *));
+NODE *listarg(NODE *p, int n, int *cnt);
+void cerror(const char *s, ...);
+void werror(const char *s, ...);
+void uerror(const char *s, ...);
+void mkdope(void);
+void tcheck(void);
+
+extern int nerrors;            /* number of errors seen so far */
+extern int warniserr;          /* treat warnings as errors */
+
+/* gcc warning stuff */
+#define        Wtruncate                       0
+#define        Wstrict_prototypes              1
+#define        Wmissing_prototypes             2
+#define        Wimplicit_int                   3
+#define        Wimplicit_function_declaration  4
+#define        Wshadow                         5
+#define        Wpointer_sign                   6
+#define        Wsign_compare                   7
+#define        Wunknown_pragmas                8
+#define        Wunreachable_code               9
+#define        Wdeprecated_declarations        10
+#define        Wattributes                     11
+
+void warner(int type, ...);
+int Wset(char *, int, int);
+void Wflags(char *);
+TWORD deunsign(TWORD t);
+TWORD enunsign(TWORD t);
+#endif
diff --git a/lang/pcc/pcc/mip/match.c b/lang/pcc/pcc/mip/match.c
new file mode 100644 (file)
index 0000000..684d31c
--- /dev/null
@@ -0,0 +1,1258 @@
+/*      $Id: match.c,v 1.104 2015/11/17 19:19:40 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+void setclass(int tmp, int class);
+int getclass(int tmp);
+
+#ifdef PCC_DEBUG
+static char *srtyp[] = { "SRNOPE", "SRDIR", "SROREG", "SRREG" };
+#endif
+
+/*
+ * return true if shape is appropriate for the node p
+ *
+ * Return values:
+ * SRNOPE  Cannot match this shape.
+ * SRDIR   Direct match, may or may not traverse down.
+ * SRREG   Will match if put in a regster XXX - kill this?
+ */
+int
+tshape(NODE *p, int shape)
+{
+       int o, mask;
+
+       o = p->n_op;
+
+#ifdef PCC_DEBUG
+       if (s2debug)
+               printf("tshape(%p, %s) op = %s\n", p, prcook(shape), opst[o]);
+#endif
+
+       if (shape & SPECIAL) {
+
+               switch (shape) {
+               case SZERO:
+               case SONE:
+               case SMONE:
+               case SSCON:
+               case SCCON:
+                       if (o != ICON || p->n_name[0])
+                               return SRNOPE;
+                       if (getlval(p)== 0 && shape == SZERO)
+                               return SRDIR;
+                       if (getlval(p) == 1 && shape == SONE)
+                               return SRDIR;
+                       if (getlval(p) == -1 && shape == SMONE)
+                               return SRDIR;
+                       if (getlval(p) > -257 && getlval(p) < 256 &&
+                           shape == SCCON)
+                               return SRDIR;
+                       if (getlval(p) > -32769 && getlval(p) < 32768 &&
+                           shape == SSCON)
+                               return SRDIR;
+                       return SRNOPE;
+
+               case SSOREG:    /* non-indexed OREG */
+                       if (o == OREG && !R2TEST(p->n_rval))
+                               return SRDIR;
+                       return SRNOPE;
+
+               default:
+                       return (special(p, shape));
+               }
+       }
+
+       if (shape & SANY)
+               return SRDIR;
+
+       if ((shape&INTEMP) && shtemp(p)) /* XXX remove? */
+               return SRDIR;
+
+       if ((shape&SWADD) && (o==NAME||o==OREG))
+               if (BYTEOFF(getlval(p)))
+                       return SRNOPE;
+
+       switch (o) {
+
+       case NAME:
+               if (shape & SNAME)
+                       return SRDIR;
+               break;
+
+       case ICON:
+       case FCON:
+               if (shape & SCON)
+                       return SRDIR;
+               break;
+
+       case FLD:
+               if (shape & SFLD)
+                       return flshape(p->n_left);
+               break;
+
+       case CCODES:
+               if (shape & SCC)
+                       return SRDIR;
+               break;
+
+       case REG:
+       case TEMP:
+               mask = PCLASS(p);
+               if (shape & mask)
+                       return SRDIR;
+               break;
+
+       case OREG:
+               if (shape & SOREG)
+                       return SRDIR;
+               break;
+
+       case UMUL:
+#if 0
+               if (shumul(p->n_left) & shape)
+                       return SROREG;  /* Calls offstar to traverse down */
+               break;
+#else
+               return shumul(p->n_left, shape);
+#endif
+
+       }
+       return SRNOPE;
+}
+
+/*
+ * does the type t match tword
+ */
+int
+ttype(TWORD t, int tword)
+{
+       if (tword & TANY)
+               return(1);
+
+#ifdef PCC_DEBUG
+       if (t2debug)
+               printf("ttype(0x%x, 0x%x)\n", t, tword);
+#endif
+       if (ISPTR(t) && ISFTN(DECREF(t)) && (tword & TFTN)) {
+               /* For funny function pointers */
+               return 1;
+       }
+       if (ISPTR(t) && (tword&TPTRTO)) {
+               do {
+                       t = DECREF(t);
+               } while (ISARY(t));
+                       /* arrays that are left are usually only
+                        * in structure references...
+                        */
+               return (ttype(t, tword&(~TPTRTO)));
+       }
+       if (t != BTYPE(t))
+               return (tword & TPOINT); /* TPOINT means not simple! */
+       if (tword & TPTRTO)
+               return(0);
+
+       switch (t) {
+       case CHAR:
+               return( tword & TCHAR );
+       case SHORT:
+               return( tword & TSHORT );
+       case STRTY:
+       case UNIONTY:
+               return( tword & TSTRUCT );
+       case INT:
+               return( tword & TINT );
+       case UNSIGNED:
+               return( tword & TUNSIGNED );
+       case USHORT:
+               return( tword & TUSHORT );
+       case UCHAR:
+               return( tword & TUCHAR );
+       case ULONG:
+               return( tword & TULONG );
+       case LONG:
+               return( tword & TLONG );
+       case LONGLONG:
+               return( tword & TLONGLONG );
+       case ULONGLONG:
+               return( tword & TULONGLONG );
+       case FLOAT:
+               return( tword & TFLOAT );
+       case DOUBLE:
+               return( tword & TDOUBLE );
+       case LDOUBLE:
+               return( tword & TLDOUBLE );
+       }
+
+       return(0);
+}
+
+#define FLDSZ(x)       UPKFSZ(x)
+#if TARGET_ENDIAN == TARGET_LE
+#define        FLDSHF(x)       UPKFOFF(x)
+#else
+#define        FLDSHF(x)       (SZINT - FLDSZ(x) - UPKFOFF(x))
+#endif
+
+/*
+ * generate code by interpreting table entry
+ */
+void
+expand(NODE *p, int cookie, char *cp)
+{
+       CONSZ val;
+
+#if 0
+       printf("expand\n");
+       fwalk(p, e2print, 0);
+#endif
+
+       for( ; *cp; ++cp ){
+               switch( *cp ){
+
+               default:
+                       putchar(*cp);
+                       continue;  /* this is the usual case... */
+
+               case 'Z':  /* special machine dependent operations */
+                       zzzcode( p, *++cp );
+                       continue;
+
+               case 'F':  /* this line deleted if FOREFF is active */
+                       if (cookie & FOREFF) {
+                               while (*cp && *cp != '\n')
+                                       cp++;
+                               if (*cp == 0)
+                                       return;
+                       }
+                       continue;
+
+               case 'S':  /* field size */
+                       if (fldexpand(p, cookie, &cp))
+                               continue;
+                       printf("%d", FLDSZ(p->n_rval));
+                       continue;
+
+               case 'H':  /* field shift */
+                       if (fldexpand(p, cookie, &cp))
+                               continue;
+                       printf("%d", FLDSHF(p->n_rval));
+                       continue;
+
+               case 'M':  /* field mask */
+               case 'N':  /* complement of field mask */
+                       if (fldexpand(p, cookie, &cp))
+                               continue;
+                       val = 1;
+                       val <<= FLDSZ(p->n_rval);
+                       --val;
+                       val <<= FLDSHF(p->n_rval);
+                       adrcon( *cp=='M' ? val : ~val );
+                       continue;
+
+               case 'L':  /* output special label field */
+                       if (*++cp == 'C')
+                               printf(LABFMT, p->n_label);
+                       else
+                               printf(LABFMT, (int)getlval(getlr(p,*cp)));
+                       continue;
+
+               case 'O':  /* opcode string */
+#ifdef FINDMOPS
+                       if (p->n_op == ASSIGN)
+                               hopcode(*++cp, p->n_right->n_op);
+                       else
+#endif
+                       hopcode( *++cp, p->n_op );
+                       continue;
+
+               case 'B':  /* byte offset in word */
+                       val = getlval(getlr(p,*++cp));
+                       val = BYTEOFF(val);
+                       printf( CONFMT, val );
+                       continue;
+
+               case 'C': /* for constant value only */
+                       conput(stdout, getlr( p, *++cp ) );
+                       continue;
+
+               case 'I': /* in instruction */
+                       insput( getlr( p, *++cp ) );
+                       continue;
+
+               case 'A': /* address of */
+                       adrput(stdout, getlr( p, *++cp ) );
+                       continue;
+
+               case 'U': /* for upper half of address, only */
+                       upput(getlr(p, *++cp), SZLONG);
+                       continue;
+
+                       }
+
+               }
+
+       }
+
+NODE resc[NRESC];
+
+NODE *
+getlr(NODE *p, int c)
+{
+       /* return the pointer to the left or right side of p, or p itself,
+          depending on the optype of p */
+
+       switch (c) {
+
+       case '1':
+       case '2':
+       case '3':
+       case 'D':
+               if (c == 'D')
+                       c = 0;
+               else
+                       c -= '0';
+               if (resc[c].n_op == FREE)
+                       comperr("getlr: free node");
+               return &resc[c];
+
+       case 'L':
+               return( optype( p->n_op ) == LTYPE ? p : p->n_left );
+
+       case 'R':
+               return( optype( p->n_op ) != BITYPE ? p : p->n_right );
+
+       }
+       cerror( "bad getlr: %c", c );
+       /* NOTREACHED */
+       return NULL;
+}
+
+#ifdef PCC_DEBUG
+#define        F2DEBUG(x)      if (f2debug) printf x
+#define        F2WALK(x)       if (f2debug) fwalk(x, e2print, 0)
+#else
+#define        F2DEBUG(x)
+#define        F2WALK(x)
+#endif
+
+/*
+ * Convert a node to REG or OREG.
+ * Shape is register class where we want the result.
+ * Returns register class if register nodes.
+ * If w is: (should be shapes)
+ *     - SRREG - result in register, call geninsn().
+ *     - SROREG - create OREG; call offstar().
+ *     - 0 - clear su, walk down.
+ */
+static int
+swmatch(NODE *p, int shape, int w)
+{
+       int rv = 0;
+
+       F2DEBUG(("swmatch: p=%p, shape=%s, w=%s\n", p, prcook(shape), srtyp[w]));
+
+       switch (w) {
+       case SRREG:
+               rv = geninsn(p, shape);
+               break;
+
+       case SROREG:
+               /* should be here only if op == UMUL */
+               if (p->n_op != UMUL && p->n_op != FLD)
+                       comperr("swmatch %p", p);
+               if (p->n_op == FLD) {
+                       offstar(p->n_left->n_left, shape);
+                       p->n_left->n_su = 0;
+               } else
+                       offstar(p->n_left, shape);
+               p->n_su = 0;
+               rv = ffs(shape)-1;
+               break;
+
+       case 0:
+               if (optype(p->n_op) == BITYPE)
+                       swmatch(p->n_right, 0, 0);
+               if (optype(p->n_op) != LTYPE)
+                       swmatch(p->n_left, 0, 0);
+               p->n_su = 0;
+       }
+       return rv;
+
+}
+
+/*
+ * Help routines for find*() functions.
+ * If the node will be a REG node and it will be rewritten in the
+ * instruction, ask for it to be put in a register.
+ */
+static int
+chcheck(NODE *p, int shape, int rew)
+{
+       int sh, sha;
+
+       sha = shape;
+       if (shape & SPECIAL)
+               shape = 0;
+
+       switch ((sh = tshape(p, sha))) {
+       case SRNOPE:
+               if (shape & INREGS)
+                       sh = SRREG;
+               break;
+
+       case SROREG:
+       case SRDIR:
+               if (rew == 0)
+                       break;
+               if (shape & INREGS)
+                       sh = SRREG;
+               else
+                       sh = SRNOPE;
+               break;
+       }
+       return sh;
+}
+
+/*
+ * Check how to walk further down.
+ * Merge with swmatch()?
+ *     sh - shape for return value (register class).
+ *     p - node (for this leg)
+ *     shape - given shape for this leg
+ *     cookie - cookie given for parent node
+ *     rew - 
+ *     go - switch key for traversing down
+ *     returns register class.
+ */
+static int
+shswitch(int sh, NODE *p, int shape, int cookie, int rew, int go)
+{
+       int lsh;
+
+       F2DEBUG(("shswitch: p=%p, shape=%s, ", p, prcook(shape)));
+       F2DEBUG(("cookie=%s, rew=0x%x, go=%s\n", prcook(cookie), rew, srtyp[go]));
+
+       switch (go) {
+       case SRDIR: /* direct match, just clear su */
+               (void)swmatch(p, 0, 0);
+               break;
+
+       case SROREG: /* call offstar to prepare for OREG conversion */
+               (void)swmatch(p, shape, SROREG);
+               break;
+
+       case SRREG: /* call geninsn() to get value into register */
+               lsh = shape & (FORCC | INREGS);
+               if (rew && cookie != FOREFF)
+                       lsh &= (cookie & (FORCC | INREGS));
+               lsh = swmatch(p, lsh, SRREG);
+               if (rew)
+                       sh = lsh;
+               break;
+       }
+       return sh;
+}
+
+/*
+ * Find the best instruction to evaluate the given tree.
+ * Best is to match both subnodes directly, second-best is if
+ * subnodes must be evaluated into OREGs, thereafter if nodes 
+ * must be put into registers.
+ * Whether 2-op instructions or 3-op is preferred is depending on in
+ * which order they are found in the table.
+ * mtchno is set to the count of regs needed for its legs.
+ */
+int
+findops(NODE *p, int cookie)
+{
+       extern int *qtable[];
+       struct optab *q, *qq = NULL;
+       int i, shl, shr, *ixp, sh;
+       int lvl = 10, idx = 0, gol = 0, gor = 0;
+       NODE *l, *r;
+
+       F2DEBUG(("findops node %p (%s)\n", p, prcook(cookie)));
+       F2WALK(p);
+
+       ixp = qtable[p->n_op];
+       l = getlr(p, 'L');
+       r = getlr(p, 'R');
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("findop: ixp %d str %s\n", ixp[i], q->cstring));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+
+               if (ttype(l->n_type, q->ltype) == 0 ||
+                   ttype(r->n_type, q->rtype) == 0)
+                       continue; /* Types must be correct */
+
+               if ((cookie & q->visit) == 0)
+                       continue; /* must get a result */
+
+               F2DEBUG(("findop got types\n"));
+
+               if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
+                       continue;
+
+               F2DEBUG(("findop lshape %s\n", srtyp[shl]));
+               F2WALK(l);
+
+               if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
+                       continue;
+
+               F2DEBUG(("findop rshape %s\n", srtyp[shr]));
+               F2WALK(r);
+
+               /* Help register assignment after SSA by preferring */
+               /* 2-op insns instead of 3-ops */
+               if (xssa && (q->rewrite & RLEFT) == 0 && shl == SRDIR)
+                       shl = SRREG;
+
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               if (lvl <= (shl + shr))
+                       continue;
+               lvl = shl + shr;
+               qq = q;
+               idx = ixp[i];
+               gol = shl;
+               gor = shr;
+       }
+       if (lvl == 10) {
+               F2DEBUG(("findops failed\n"));
+               if (setbin(p))
+                       return FRETRY;
+               return FFAIL;
+       }
+
+       F2DEBUG(("findops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+       sh = -1;
+
+#ifdef mach_pdp11
+       if (cookie == FORCC && p->n_op != AND)  /* XXX - fix */
+               cookie = INREGS;
+#else
+       if (cookie == FORCC)
+               cookie = INREGS;
+#endif
+
+       sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+           qq->rewrite & RLEFT, gol);
+       sh = shswitch(sh, p->n_right, qq->rshape, cookie,
+           qq->rewrite & RRIGHT, gor);
+
+       if (sh == -1) {
+               if (cookie == FOREFF || cookie == FORCC)
+                       sh = 0;
+               else
+                       sh = ffs(cookie & qq->visit & INREGS)-1;
+       }
+       F2DEBUG(("findops: node %p sh %d (%s)\n", p, sh, prcook(1 << sh)));
+       p->n_su = MKIDX(idx, 0);
+       SCLASS(p->n_su, sh);
+       return sh;
+}
+
+/*
+ * Find the best relation op for matching the two trees it has.
+ * This is a sub-version of the function findops() above.
+ * The instruction with the lowest grading is emitted.
+ *
+ * Level assignment for priority:
+ *     left    right   prio
+ *     -       -       -
+ *     direct  direct  1
+ *     direct  OREG    2       # make oreg
+ *     OREG    direct  2       # make oreg
+ *     OREG    OREG    2       # make both oreg
+ *     direct  REG     3       # put in reg
+ *     OREG    REG     3       # put in reg, make oreg
+ *     REG     direct  3       # put in reg
+ *     REG     OREG    3       # put in reg, make oreg
+ *     REG     REG     4       # put both in reg
+ */
+int
+relops(NODE *p)
+{
+       extern int *qtable[];
+       struct optab *q;
+       int i, shl = 0, shr = 0, sh;
+       NODE *l, *r;
+       int *ixp, idx = 0;
+       int lvl = 10, gol = 0, gor = 0;
+
+       F2DEBUG(("relops tree:\n"));
+       F2WALK(p);
+
+       l = getlr(p, 'L');
+       r = getlr(p, 'R');
+       ixp = qtable[p->n_op];
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("relops: ixp %d\n", ixp[i]));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+
+               if (ttype(l->n_type, q->ltype) == 0 ||
+                   ttype(r->n_type, q->rtype) == 0)
+                       continue; /* Types must be correct */
+
+               F2DEBUG(("relops got types\n"));
+               if ((shl = chcheck(l, q->lshape, 0)) == SRNOPE)
+                       continue;
+               F2DEBUG(("relops lshape %d\n", shl));
+               F2WALK(p);
+               if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
+                       continue;
+               F2DEBUG(("relops rshape %d\n", shr));
+               F2WALK(p);
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               if (lvl <= (shl + shr))
+                       continue;
+               lvl = shl + shr;
+               idx = ixp[i];
+               gol = shl;
+               gor = shr;
+       }
+       if (lvl == 10) {
+               F2DEBUG(("relops failed\n"));
+               if (setbin(p))
+                       return FRETRY;
+               return FFAIL;
+       }
+       F2DEBUG(("relops entry %d(%s %s)\n", idx, srtyp[gol], srtyp[gor]));
+
+       q = &table[idx];
+
+       (void)shswitch(-1, p->n_left, q->lshape, INREGS,
+           q->rewrite & RLEFT, gol);
+
+       (void)shswitch(-1, p->n_right, q->rshape, INREGS,
+           q->rewrite & RRIGHT, gor);
+
+       sh = 0;
+       if (q->rewrite & RLEFT)
+               sh = ffs(q->lshape & INREGS)-1;
+       else if (q->rewrite & RRIGHT)
+               sh = ffs(q->rshape & INREGS)-1;
+
+       F2DEBUG(("relops: node %p\n", p));
+       p->n_su = MKIDX(idx, 0);
+       SCLASS(p->n_su, sh);
+       return 0;
+}
+
+/*
+ * Find a matching assign op.
+ *
+ * Level assignment for priority:
+ *     left    right   prio
+ *     -       -       -
+ *     direct  direct  1
+ *     direct  REG     2
+ *     direct  OREG    3
+ *     OREG    direct  4
+ *     OREG    REG     5
+ *     OREG    OREG    6
+ */
+int
+findasg(NODE *p, int cookie)
+{
+       extern int *qtable[];
+       struct optab *q;
+       int i, sh, shl, shr, lvl = 10;
+       NODE *l, *r;
+       int *ixp;
+       struct optab *qq = NULL; /* XXX gcc */
+       int idx = 0, gol = 0, gor = 0;
+
+       shl = shr = 0;
+
+       F2DEBUG(("findasg tree: %s\n", prcook(cookie)));
+       F2WALK(p);
+
+       ixp = qtable[p->n_op];
+       l = getlr(p, 'L');
+       r = getlr(p, 'R');
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("findasg: ixp %d\n", ixp[i]));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+
+               if (ttype(l->n_type, q->ltype) == 0 ||
+                   ttype(r->n_type, q->rtype) == 0)
+                       continue; /* Types must be correct */
+
+               if ((cookie & q->visit) == 0)
+                       continue; /* must get a result */
+
+               F2DEBUG(("findasg got types\n"));
+#ifdef mach_pdp11 /* XXX - check for other targets too */
+               if (p->n_op == STASG && ISPTR(l->n_type)) {
+                       /* Accept lvalue to be in register */
+                       /* if struct assignment is given a pointer */
+                       if ((shl = chcheck(l, q->lshape,
+                           q->rewrite & RLEFT)) == SRNOPE)
+                               continue;
+               } else
+#endif
+               {
+                       if ((shl = tshape(l, q->lshape)) == SRNOPE)
+                               continue;
+                       if (shl == SRREG)
+                               continue;
+               }
+
+               F2DEBUG(("findasg lshape %d\n", shl));
+               F2WALK(l);
+
+               if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
+                       continue;
+
+               F2DEBUG(("findasg rshape %d\n", shr));
+               F2WALK(r);
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               if (lvl <= (shl + shr))
+                       continue;
+
+               lvl = shl + shr;
+               qq = q;
+               idx = ixp[i];
+               gol = shl;
+               gor = shr;
+       }
+
+       if (lvl == 10) {
+               F2DEBUG(("findasg failed\n"));
+               if (setasg(p, cookie))
+                       return FRETRY;
+               return FFAIL;
+       }
+       F2DEBUG(("findasg entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+       sh = -1;
+       sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+           qq->rewrite & RLEFT, gol);
+
+       sh = shswitch(sh, p->n_right, qq->rshape, cookie,
+           qq->rewrite & RRIGHT, gor);
+
+#ifdef mach_pdp11 /* XXX all targets? */
+       lvl = 0;
+       if (cookie == FOREFF)
+               lvl = RVEFF, sh = 0;
+       else if (cookie == FORCC)
+               lvl = RVCC, sh = 0;
+       else if (sh == -1) {
+               sh = ffs(cookie & qq->visit & INREGS)-1;
+#ifdef PCC_DEBUG
+               if (sh == -1)
+                       comperr("findasg bad shape");
+#endif
+               SCLASS(lvl,sh);
+       } else
+               SCLASS(lvl,sh);
+       p->n_su = MKIDX(idx, lvl);
+#else
+       if (sh == -1) {
+               if (cookie == FOREFF)
+                       sh = 0;
+               else
+                       sh = ffs(cookie & qq->visit & INREGS)-1;
+       }
+       F2DEBUG(("findasg: node %p class %d\n", p, sh));
+
+       p->n_su = MKIDX(idx, 0);
+       SCLASS(p->n_su, sh);
+#endif /* mach_pdp11 */
+#ifdef FINDMOPS
+       p->n_su &= ~ISMOPS;
+#endif
+       return sh;
+}
+
+/*
+ * Search for an UMUL table entry that can turn an indirect node into
+ * a move from an OREG.
+ */
+int
+findumul(NODE *p, int cookie)
+{
+       extern int *qtable[];
+       struct optab *q = NULL; /* XXX gcc */
+       int i, shl = 0, shr = 0, sh;
+       int *ixp;
+
+       F2DEBUG(("findumul p %p (%s)\n", p, prcook(cookie)));
+       F2WALK(p);
+
+       ixp = qtable[p->n_op];
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("findumul: ixp %d\n", ixp[i]));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+
+               if ((q->visit & cookie) == 0)
+                       continue; /* wrong registers */
+
+               if (ttype(p->n_type, q->rtype) == 0)
+                       continue; /* Types must be correct */
+               
+
+               F2DEBUG(("findumul got types, rshape %s\n", prcook(q->rshape)));
+               /*
+                * Try to create an OREG of the node.
+                * Fake left even though it's right node,
+                * to be sure of conversion if going down left.
+                */
+               if ((shl = chcheck(p, q->rshape, 0)) == SRNOPE)
+                       continue;
+               
+               shr = 0;
+
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               F2DEBUG(("findumul got shape %s\n", srtyp[shl]));
+
+               break; /* XXX search better matches */
+       }
+       if (ixp[i] < 0) {
+               F2DEBUG(("findumul failed\n"));
+               if (setuni(p, cookie))
+                       return FRETRY;
+               return FFAIL;
+       }
+       F2DEBUG(("findumul entry %d(%s %s)\n", ixp[i], srtyp[shl], srtyp[shr]));
+
+       sh = shswitch(-1, p, q->rshape, cookie, q->rewrite & RLEFT, shl);
+       if (sh == -1)
+               sh = ffs(cookie & q->visit & INREGS)-1;
+
+       F2DEBUG(("findumul: node %p (%s)\n", p, prcook(1 << sh)));
+       p->n_su = MKIDX(ixp[i], 0);
+       SCLASS(p->n_su, sh);
+       return sh;
+}
+
+/*
+ * Find a leaf type node that puts the value into a register.
+ */
+int
+findleaf(NODE *p, int cookie)
+{
+       extern int *qtable[];
+       struct optab *q = NULL; /* XXX gcc */
+       int i, sh;
+       int *ixp;
+
+       F2DEBUG(("findleaf p %p (%s)\n", p, prcook(cookie)));
+       F2WALK(p);
+
+       ixp = qtable[p->n_op];
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("findleaf: ixp %d\n", ixp[i]));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+               if ((q->visit & cookie) == 0)
+                       continue; /* wrong registers */
+
+               if (ttype(p->n_type, q->rtype) == 0 ||
+                   ttype(p->n_type, q->ltype) == 0)
+                       continue; /* Types must be correct */
+
+               F2DEBUG(("findleaf got types, rshape %s\n", prcook(q->rshape)));
+
+               if (chcheck(p, q->rshape, 0) != SRDIR)
+                       continue;
+
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               break;
+       }
+       if (ixp[i] < 0) {
+               F2DEBUG(("findleaf failed\n"));
+               if (setuni(p, cookie))
+                       return FRETRY;
+               return FFAIL;
+       }
+       F2DEBUG(("findleaf entry %d\n", ixp[i]));
+
+       sh = ffs(cookie & q->visit & INREGS)-1;
+       F2DEBUG(("findleaf: node %p (%s)\n", p, prcook(1 << sh)));
+       p->n_su = MKIDX(ixp[i], 0);
+       SCLASS(p->n_su, sh);
+       return sh;
+}
+
+/*
+ * Find a UNARY op that satisfy the needs.
+ * For now, the destination is always a register.
+ * Both source and dest types must match, but only source (left)
+ * shape is of interest.
+ */
+int
+finduni(NODE *p, int cookie)
+{
+       extern int *qtable[];
+       struct optab *q;
+       NODE *l, *r;
+       int i, shl = 0, num = 4;
+       int *ixp, idx = 0;
+       int sh;
+
+       F2DEBUG(("finduni tree: %s\n", prcook(cookie)));
+       F2WALK(p);
+
+       l = getlr(p, 'L');
+       if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL)
+               r = p;
+       else
+               r = getlr(p, 'R');
+       ixp = qtable[p->n_op];
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("finduni: ixp %d\n", ixp[i]));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+
+               if (ttype(l->n_type, q->ltype) == 0)
+                       continue; /* Type must be correct */
+
+               F2DEBUG(("finduni got left type\n"));
+               if (ttype(r->n_type, q->rtype) == 0)
+                       continue; /* Type must be correct */
+
+               F2DEBUG(("finduni got types\n"));
+               if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
+                       continue;
+
+               F2DEBUG(("finduni got shapes %d\n", shl));
+
+               if ((cookie & q->visit) == 0)   /* check correct return value */
+                       continue;               /* XXX - should check needs */
+
+               /* avoid clobbering of longlived regs */
+               /* let register allocator coalesce */
+               if ((q->rewrite & RLEFT) && (shl == SRDIR) /* && isreg(l) */)
+                       shl = SRREG;
+
+               F2DEBUG(("finduni got cookie\n"));
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               if (shl >= num)
+                       continue;
+               num = shl;
+               idx = ixp[i];
+
+               if (shl == SRDIR)
+                       break;
+       }
+
+       if (num == 4) {
+               F2DEBUG(("finduni failed\n"));
+       } else
+               F2DEBUG(("finduni entry %d(%s)\n", idx, srtyp[num]));
+
+       if (num == 4) {
+               if (setuni(p, cookie))
+                       return FRETRY;
+               return FFAIL;
+       }
+       q = &table[idx];
+
+       sh = shswitch(-1, p->n_left, q->lshape, cookie,
+           q->rewrite & RLEFT, num);
+       if (sh == -1)
+               sh = ffs(cookie & q->visit & INREGS)-1;
+       if (sh == -1)
+               sh = 0;
+
+       F2DEBUG(("finduni: node %p (%s)\n", p, prcook(1 << sh)));
+       p->n_su = MKIDX(idx, 0);
+       SCLASS(p->n_su, sh);
+       return sh;
+}
+
+#ifdef FINDMOPS
+/*
+ * Try to find constructs like "a = a + 1;" and match them together
+ * with instructions like "incl a" or "addl $1,a".
+ *
+ * Level assignment for priority:
+ *     left    right   prio
+ *     -       -       -
+ *     direct  direct  1
+ *     direct  REG     2
+ *     direct  OREG    3
+ *     OREG    direct  4
+ *     OREG    REG     5
+ *     OREG    OREG    6
+ */
+int
+findmops(NODE *p, int cookie)
+{
+       extern int *qtable[];
+       struct optab *q;
+       int i, sh, shl, shr, lvl = 10;
+       NODE *l, *r;
+       int *ixp;
+       struct optab *qq = NULL; /* XXX gcc */
+       int idx = 0, gol = 0, gor = 0;
+
+       shl = shr = 0;
+
+       F2DEBUG(("findmops tree: %s\n", prcook(cookie)));
+       F2WALK(p);
+
+       l = getlr(p, 'L');
+       r = getlr(p, 'R');
+       /* See if this is a usable tree to work with */
+       /* Currently only check for leaves */
+       if (optype(r->n_op) != BITYPE || treecmp(l, r->n_left) == 0)
+               return FFAIL;
+
+       F2DEBUG(("findmops is useable\n"));
+
+       /* We can try to find a match.  Use right op */
+       ixp = qtable[r->n_op];
+       l = getlr(r, 'L');
+       r = getlr(r, 'R');
+
+       for (i = 0; ixp[i] >= 0; i++) {
+               q = &table[ixp[i]];
+
+               F2DEBUG(("findmops: ixp %d\n", ixp[i]));
+               if (!acceptable(q))             /* target-dependent filter */
+                       continue;
+
+               if (ttype(l->n_type, q->ltype) == 0 ||
+                   ttype(r->n_type, q->rtype) == 0)
+                       continue; /* Types must be correct */
+
+               F2DEBUG(("findmops got types\n"));
+
+               switch (cookie) {
+               case FOREFF:
+                       if ((q->visit & FOREFF) == 0)
+                               continue; /* Not only for side effects */
+                       break;
+               case FORCC:
+                       if ((q->visit & FORCC) == 0)
+                               continue; /* Not only for side effects */
+                       break;
+               default:
+                       if ((cookie & q->visit) == 0)
+                               continue; /* Won't match requested shape */
+                       if (((cookie & INREGS & q->lshape) == 0) || !isreg(l))
+                               continue; /* Bad return register */
+                       break;
+               }
+               F2DEBUG(("findmops cookie\n"));
+
+               /*
+                * left shape must match left node.
+                */
+               if ((shl = tshape(l, q->lshape)) != SRDIR && (shl != SROREG))
+                       continue;
+
+               F2DEBUG(("findmops lshape %s\n", srtyp[shl]));
+               F2WALK(l);
+
+               if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
+                       continue;
+
+               F2DEBUG(("findmops rshape %s\n", srtyp[shr]));
+
+               /*
+                * Only allow RLEFT. XXX
+                */
+               if ((q->rewrite & (RLEFT|RRIGHT)) != RLEFT)
+                       continue;
+
+               F2DEBUG(("rewrite OK\n"));
+
+               F2WALK(r);
+               if (q->needs & REWRITE)
+                       break;  /* Done here */
+
+               if (lvl <= (shl + shr))
+                       continue;
+
+               lvl = shl + shr;
+               qq = q;
+               idx = ixp[i];
+               gol = shl;
+               gor = shr;
+       }
+
+       if (lvl == 10)
+               return FFAIL;
+       F2DEBUG(("findmops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+       /*
+        * Now we're here and have a match. left is semi-direct and 
+        * right may be anything.
+        */
+
+       sh = -1;
+       sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+           qq->rewrite & RLEFT, gol);
+       sh = shswitch(sh, r, qq->rshape, cookie, 0, gor);
+
+       if (sh == -1) {
+               if (cookie & (FOREFF|FORCC))
+                       sh = 0;
+               else
+                       sh = ffs(cookie & qq->visit & INREGS)-1;
+       }
+       F2DEBUG(("findmops done: node %p class %d\n", p, sh));
+
+       /* Trickery:  Set table index on assign to op instead */
+       /* gencode() will remove useless nodes */
+       p->n_su = MKIDX(idx, 0);
+       p->n_su |= ISMOPS; /* XXX tell gencode to reduce the right tree */
+       SCLASS(p->n_su, sh);
+
+       return sh;
+}
+
+/*
+ * Compare two trees; return 1 if equal and 0 if not.
+ */
+int
+treecmp(NODE *p1, NODE *p2)
+{
+       if (p1->n_op != p2->n_op)
+               return 0;
+
+       switch (p1->n_op) {
+       case SCONV:
+       case UMUL:
+               return treecmp(p1->n_left, p2->n_left);
+
+       case OREG:
+               if (getlval(p1) != getlval(p2) || p1->n_rval != p2->n_rval)
+                       return 0;
+               break;
+
+       case NAME:
+       case ICON:
+               if (strcmp(p1->n_name, p2->n_name))
+                       return 0;
+               /* FALLTHROUGH */
+               if (getlval(p1) != getlval(p2))
+                       return 0;
+               break;
+
+       case TEMP:
+#ifdef notyet
+               /* SSA will put assignment in separate register */
+               /* Help out by accepting different regs here */
+               if (xssa)
+                       break;
+#endif
+       case REG:
+               if (p1->n_rval != p2->n_rval)
+                       return 0;
+               break;
+       case LS:
+       case RS:
+       case PLUS:
+       case MINUS:
+       case MUL:
+       case DIV:
+               if (treecmp(p1->n_left, p2->n_left) == 0 ||
+                   treecmp(p1->n_right, p2->n_right) == 0)
+                       return 0;
+               break;
+
+       default:
+               return 0;
+       }
+       return 1;
+}
+#endif
diff --git a/lang/pcc/pcc/mip/mkext.c b/lang/pcc/pcc/mip/mkext.c
new file mode 100644 (file)
index 0000000..4d966bd
--- /dev/null
@@ -0,0 +1,477 @@
+/*     $Id: mkext.c,v 1.52 2014/03/11 21:32:18 ragge Exp $     */
+
+/*
+ * Generate defines for the needed hardops.
+ */
+#include "pass2.h"
+#include <stdlib.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_C99_FORMAT
+#define FMTdPTR "%td"
+#else
+#if defined(_WIN64) || defined(LP64)
+#define FMTdPTR "%ld"
+#else
+#define FMTdPTR "%d"
+#endif
+#endif
+
+int chkop[DSIZE];
+
+void mktables(void);
+
+char *ftitle;
+char *cname = "external.c";
+char *hname = "external.h";
+FILE *fc, *fh;
+
+/*
+ * masks for matching dope with shapes
+ */
+int mamask[] = {
+        SIMPFLG,                /* OPSIMP */
+        SIMPFLG|ASGFLG,         /* ASG OPSIMP */
+        COMMFLG,        /* OPCOMM */
+        COMMFLG|ASGFLG, /* ASG OPCOMM */
+        MULFLG,         /* OPMUL */
+        MULFLG|ASGFLG,  /* ASG OPMUL */
+        DIVFLG,         /* OPDIV */
+        DIVFLG|ASGFLG,  /* ASG OPDIV */
+        UTYPE,          /* OPUNARY */
+        TYFLG,          /* ASG OPUNARY is senseless */
+        LTYPE,          /* OPLEAF */
+        TYFLG,          /* ASG OPLEAF is senseless */
+        0,              /* OPANY */
+        ASGOPFLG|ASGFLG,        /* ASG OPANY */
+        LOGFLG,         /* OPLOG */
+        TYFLG,          /* ASG OPLOG is senseless */
+        FLOFLG,         /* OPFLOAT */
+        FLOFLG|ASGFLG,  /* ASG OPFLOAT */
+        SHFFLG,         /* OPSHFT */
+        SHFFLG|ASGFLG,  /* ASG OPSHIFT */
+        SPFLG,          /* OPLTYPE */
+        TYFLG,          /* ASG OPLTYPE is senseless */
+        };
+
+
+struct checks {
+       int op, type;
+       char *name;
+} checks[] = {
+       { MUL, TLONGLONG, "SMULLL", },
+       { DIV, TLONGLONG, "SDIVLL", },
+       { MOD, TLONGLONG, "SMODLL", },
+       { PLUS, TLONGLONG, "SPLUSLL", },
+       { MINUS, TLONGLONG, "SMINUSLL", },
+       { MUL, TULONGLONG, "UMULLL", },
+       { DIV, TULONGLONG, "UDIVLL", },
+       { MOD, TULONGLONG, "UMODLL", },
+       { PLUS, TULONGLONG, "UPLUSLL", },
+       { MINUS, TULONGLONG, "UMINUSLL", },
+       { 0, 0, 0, },
+};
+
+int rstatus[] = { RSTATUS };
+int roverlay[MAXREGS][MAXREGS] = { ROVERLAP };
+int regclassmap[CLASSG][MAXREGS]; /* CLASSG is highest class */
+
+static void
+compl(struct optab *q, char *str)
+{
+       int op = q->op;
+       char *s;
+
+       if (op < OPSIMP) {
+               s = opst[op];
+       } else
+               switch (op) {
+               default:        s = "Special op";       break;
+               case OPSIMP:    s = "OPLSIMP";  break;
+               case OPCOMM:    s = "OPCOMM";   break;
+               case OPMUL:     s = "OPMUL";    break;
+               case OPDIV:     s = "OPDIV";    break;
+               case OPUNARY:   s = "OPUNARY";  break;
+               case OPLEAF:    s = "OPLEAF";   break;
+               case OPANY:     s = "OPANY";    break;
+               case OPLOG:     s = "OPLOG";    break;
+               case OPFLOAT:   s = "OPFLOAT";  break;
+               case OPSHFT:    s = "OPSHFT";   break;
+               case OPLTYPE:   s = "OPLTYPE";  break;
+               }
+
+       printf("table entry " FMTdPTR ", op %s: %s\n", q - table, s, str);
+}
+
+static int
+getrcl(struct optab *q)
+{
+       int v = q->needs &
+           (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT);
+       int r = q->rewrite & RESC1 ? 1 : q->rewrite & RESC2 ? 2 : 3;
+       int i = 0;
+
+#define INCK(c) while (v & c##COUNT) { \
+       v -= c##REG, i++; if (i == r) return I##c##REG; }
+       INCK(NA)
+       INCK(NB)
+       INCK(NC)
+       INCK(ND)
+       INCK(NE)
+       INCK(NF)
+       INCK(NG)
+       return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct optab *q;
+       struct checks *ch;
+       int i, j, areg, breg, creg, dreg, mx, ereg, freg, greg;
+       char *bitary;
+       int bitsz, rval, nelem;
+
+       if (argc == 2) {
+               i = atoi(argv[1]);
+               printf("Entry %d:\n%s\n", i, table[i].cstring);
+               return 0;
+       }
+
+       mkdope();
+
+       for (q = table; q->op != FREE; q++) {
+               if (q->op >= OPSIMP)
+                       continue;
+               if ((q->ltype & TLONGLONG) &&
+                   (q->rtype & TLONGLONG))
+                       chkop[q->op] |= TLONGLONG;
+               if ((q->ltype & TULONGLONG) &&
+                   (q->rtype & TULONGLONG))
+                       chkop[q->op] |= TULONGLONG;
+       }
+       if ((fc = fopen(cname, "w")) == NULL) {
+               perror("open cfile");
+               return(1);
+       }
+       if ((fh = fopen(hname, "w")) == NULL) {
+               perror("open hfile");
+               return(1);
+       }
+       fprintf(fh, "#ifndef _EXTERNAL_H_\n#define _EXTERNAL_H_\n");
+
+       for (ch = checks; ch->op != 0; ch++) {
+               if ((chkop[ch->op] & ch->type) == 0)
+                       fprintf(fh, "#define NEED_%s\n", ch->name);
+       }
+
+       fprintf(fc, "#include \"pass2.h\"\n");
+       /* create fast-lookup tables */
+       mktables();
+
+       /* create efficient bitset sizes */
+       if (sizeof(long) == 8) { /* 64-bit arch */
+               bitary = "long";
+               bitsz = 64;
+       } else {
+               bitary = "int";
+               bitsz = sizeof(int) == 4 ? 32 : 16;
+       }
+       fprintf(fh, "#define NUMBITS %d\n", bitsz);
+       fprintf(fh, "#define BIT2BYTE(bits) "
+            "((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))\n");
+       fprintf(fh, "#define BITSET(arr, bit) "
+            "(arr[bit/NUMBITS] |= ((%s)1 << (bit & (NUMBITS-1))))\n",
+            bitary);
+       fprintf(fh, "#define BITCLEAR(arr, bit) "
+            "(arr[bit/NUMBITS] &= ~((%s)1 << (bit & (NUMBITS-1))))\n",
+            bitary);
+       fprintf(fh, "#define TESTBIT(arr, bit) "
+            "(arr[bit/NUMBITS] & ((%s)1 << (bit & (NUMBITS-1))))\n",
+            bitary);
+       fprintf(fh, "typedef %s bittype;\n", bitary);
+
+       /* register class definitions, used by graph-coloring */
+       /* TODO */
+
+       /* Sanity-check the table */
+       rval = 0;
+       for (q = table; q->op != FREE; q++) {
+               switch (q->op) {
+               case ASSIGN:
+#define        F(x) (q->visit & x && q->rewrite & (RLEFT|RRIGHT) && \
+                   q->lshape & ~x && q->rshape & ~x)
+                       if (F(INAREG) || F(INBREG) || F(INCREG) || F(INDREG) ||
+                           F(INEREG) || F(INFREG) || F(INGREG)) {
+                               compl(q, "may match without result register");
+                               rval++;
+                       }
+#undef F
+                       /* FALLTHROUGH */
+               case STASG:
+                       if ((q->visit & INREGS) && !(q->rewrite & RDEST)) {
+                               compl(q, "ASSIGN/STASG reclaim must be RDEST");
+                               rval++;
+                       }
+                       break;
+               }
+               /* check that reclaim is not the wrong class */
+               if ((q->rewrite & (RESC1|RESC2|RESC3)) && 
+                   !(q->needs & REWRITE)) {
+                       if ((q->visit & getrcl(q)) == 0) {
+                               compl(q, "wrong RESCx class");
+                               rval++;
+                       }
+               }
+               if (q->rewrite & (RESC1|RESC2|RESC3) && q->visit & FOREFF)
+                       compl(q, "FOREFF may cause reclaim of wrong class");
+       }
+
+       /* print out list of scratched and permanent registers */
+       fprintf(fh, "extern int tempregs[], permregs[];\n");
+       fprintf(fc, "int tempregs[] = { ");
+       for (i = j = 0; i < MAXREGS; i++)
+               if (rstatus[i] & TEMPREG)
+                       fprintf(fc, "%d, ", i), j++;
+       fprintf(fc, "-1 };\n");
+       fprintf(fh, "#define NTEMPREG %d\n", j+1);
+       fprintf(fh, "#define FREGS %d\n", j);   /* XXX - to die */
+       fprintf(fc, "int permregs[] = { ");
+       for (i = j = 0; i < MAXREGS; i++)
+               if (rstatus[i] & PERMREG)
+                       fprintf(fc, "%d, ", i), j++;
+       fprintf(fc, "-1 };\n");
+       fprintf(fh, "#define NPERMREG %d\n", j+1);
+       fprintf(fc, "bittype validregs[] = {\n");
+
+if (bitsz == 64) {
+       for (j = 0; j < MAXREGS; j += bitsz) {
+               long cbit = 0;
+               for (i = 0; i < bitsz; i++) {
+                       if (i+j == MAXREGS)
+                               break;
+                       if (rstatus[i+j] & INREGS)
+                               cbit |= ((long)1 << i);
+               }
+               fprintf(fc, "\t0x%lx,\n", cbit);
+       }
+} else {
+       for (j = 0; j < MAXREGS; j += bitsz) {
+               int cbit = 0;
+               for (i = 0; i < bitsz; i++) {
+                       if (i+j == MAXREGS)
+                               break;
+                       if (rstatus[i+j] & INREGS)
+                               cbit |= (1 << i);
+               }
+               fprintf(fc, "\t0x%08x,\n", cbit);
+       }
+}
+
+       fprintf(fc, "};\n");
+       fprintf(fh, "extern bittype validregs[];\n");
+
+       /*
+        * The register allocator uses bitmasks of registers for each class.
+        */
+       areg = breg = creg = dreg = ereg = freg = greg = 0;
+       for (i = 0; i < MAXREGS; i++) {
+               for (j = 0; j < NUMCLASS; j++)
+                       regclassmap[j][i] = -1;
+               if (rstatus[i] & SAREG) regclassmap[0][i] = areg++;
+               if (rstatus[i] & SBREG) regclassmap[1][i] = breg++;
+               if (rstatus[i] & SCREG) regclassmap[2][i] = creg++;
+               if (rstatus[i] & SDREG) regclassmap[3][i] = dreg++;
+               if (rstatus[i] & SEREG) regclassmap[4][i] = ereg++;
+               if (rstatus[i] & SFREG) regclassmap[5][i] = freg++;
+               if (rstatus[i] & SGREG) regclassmap[6][i] = greg++;
+       }
+       fprintf(fh, "#define AREGCNT %d\n", areg);
+       fprintf(fh, "#define BREGCNT %d\n", breg);
+       fprintf(fh, "#define CREGCNT %d\n", creg);
+       fprintf(fh, "#define DREGCNT %d\n", dreg);
+       fprintf(fh, "#define EREGCNT %d\n", ereg);
+       fprintf(fh, "#define FREGCNT %d\n", freg);
+       fprintf(fh, "#define GREGCNT %d\n", greg);
+       if (areg > bitsz)
+               printf("%d regs in class A (max %d)\n", areg, bitsz), rval++;
+       if (breg > bitsz)
+               printf("%d regs in class B (max %d)\n", breg, bitsz), rval++;
+       if (creg > bitsz)
+               printf("%d regs in class C (max %d)\n", creg, bitsz), rval++;
+       if (dreg > bitsz)
+               printf("%d regs in class D (max %d)\n", dreg, bitsz), rval++;
+       if (ereg > bitsz)
+               printf("%d regs in class E (max %d)\n", ereg, bitsz), rval++;
+       if (freg > bitsz)
+               printf("%d regs in class F (max %d)\n", freg, bitsz), rval++;
+       if (greg > bitsz)
+               printf("%d regs in class G (max %d)\n", greg, bitsz), rval++;
+
+       fprintf(fc, "static int amap[MAXREGS][NUMCLASS] = {\n");
+       for (i = 0; i < MAXREGS; i++) {
+               int ba, bb, bc, bd, r, be, bf, bg;
+               ba = bb = bc = bd = be = bf = bg = 0;
+               if (rstatus[i] & SAREG) ba = (1 << regclassmap[0][i]);
+               if (rstatus[i] & SBREG) bb = (1 << regclassmap[1][i]);
+               if (rstatus[i] & SCREG) bc = (1 << regclassmap[2][i]);
+               if (rstatus[i] & SDREG) bd = (1 << regclassmap[3][i]);
+               if (rstatus[i] & SEREG) be = (1 << regclassmap[4][i]);
+               if (rstatus[i] & SFREG) bf = (1 << regclassmap[5][i]);
+               if (rstatus[i] & SGREG) bg = (1 << regclassmap[6][i]);
+               for (j = 0; roverlay[i][j] >= 0; j++) {
+                       r = roverlay[i][j];
+                       if (rstatus[r] & SAREG)
+                               ba |= (1 << regclassmap[0][r]);
+                       if (rstatus[r] & SBREG)
+                               bb |= (1 << regclassmap[1][r]);
+                       if (rstatus[r] & SCREG)
+                               bc |= (1 << regclassmap[2][r]);
+                       if (rstatus[r] & SDREG)
+                               bd |= (1 << regclassmap[3][r]);
+                       if (rstatus[r] & SEREG)
+                               be |= (1 << regclassmap[4][r]);
+                       if (rstatus[r] & SFREG)
+                               bf |= (1 << regclassmap[5][r]);
+                       if (rstatus[r] & SGREG)
+                               bg |= (1 << regclassmap[6][r]);
+               }
+               fprintf(fc, "\t/* %d */{ 0x%x", i, ba);
+               if (NUMCLASS > 1) fprintf(fc, ",0x%x", bb);
+               if (NUMCLASS > 2) fprintf(fc, ",0x%x", bc);
+               if (NUMCLASS > 3) fprintf(fc, ",0x%x", bd);
+               if (NUMCLASS > 4) fprintf(fc, ",0x%x", be);
+               if (NUMCLASS > 5) fprintf(fc, ",0x%x", bf);
+               if (NUMCLASS > 6) fprintf(fc, ",0x%x", bg);
+               fprintf(fc, " },\n");
+       }
+       fprintf(fc, "};\n");
+
+       fprintf(fh, "int aliasmap(int class, int regnum);\n");
+       fprintf(fc, "int\naliasmap(int class, int regnum)\n{\n");
+       fprintf(fc, "   return amap[regnum][class-1];\n}\n");
+
+       /* routines to convert back from color to regnum */
+       mx = areg;
+       if (breg > mx) mx = breg;
+       if (creg > mx) mx = creg;
+       if (dreg > mx) mx = dreg;
+       if (ereg > mx) mx = ereg;
+       if (freg > mx) mx = freg;
+       if (greg > mx) mx = greg;
+       if (mx > (int)(sizeof(int)*8)-1) {
+               printf("too many regs in a class, use two classes instead\n");
+#ifdef HAVE_C99_FORMAT
+               printf("%d > %zu\n", mx, (sizeof(int)*8)-1);
+#else
+               printf("%d > %d\n", mx, (int)(sizeof(int)*8)-1);
+#endif
+               rval++;
+       }
+       fprintf(fc, "static int rmap[NUMCLASS][%d] = {\n", mx);
+       for (j = 0; j < NUMCLASS; j++) {
+               int cl = SAREG << j;
+               if (j > 3)
+                       cl = SEREG << (j - 4);
+               fprintf(fc, "\t{ ");
+               for (i = 0; i < MAXREGS; i++)
+                       if (rstatus[i] & cl) fprintf(fc, "%d, ", i);
+               fprintf(fc, "},\n");
+       }
+       fprintf(fc, "};\n\n");
+
+       fprintf(fh, "int color2reg(int color, int class);\n");
+       fprintf(fc, "int\ncolor2reg(int color, int class)\n{\n");
+       fprintf(fc, "   return rmap[class-1][color];\n}\n");
+
+       /* used by register allocator */
+       fprintf(fc, "int regK[] = { 0, %d, %d, %d, %d, %d, %d, %d };\n",
+           areg, breg, creg, dreg, ereg, freg, greg);
+       fprintf(fc, "int\nclassmask(int class)\n{\n");
+       fprintf(fc, "\tif(class == CLASSA) return 0x%x;\n", (1 << areg)-1);
+       fprintf(fc, "\tif(class == CLASSB) return 0x%x;\n", (1 << breg)-1);
+       fprintf(fc, "\tif(class == CLASSC) return 0x%x;\n", (1 << creg)-1);
+       fprintf(fc, "\tif(class == CLASSD) return 0x%x;\n", (1 << dreg)-1);
+       fprintf(fc, "\tif(class == CLASSE) return 0x%x;\n", (1 << ereg)-1);
+       fprintf(fc, "\tif(class == CLASSF) return 0x%x;\n", (1 << freg)-1);
+       fprintf(fc, "\treturn 0x%x;\n}\n", (1 << greg)-1);
+
+       fprintf(fh, "int interferes(int reg1, int reg2);\n");
+       nelem = (MAXREGS+bitsz-1)/bitsz;
+       fprintf(fc, "static bittype ovlarr[MAXREGS][%d] = {\n", nelem);
+       for (i = 0; i < MAXREGS; i++) {
+               int el[10];
+               memset(el, 0, sizeof(el));
+               el[i/bitsz] = 1 << (i % bitsz);
+               for (j = 0; roverlay[i][j] >= 0; j++) {
+                       int k = roverlay[i][j];
+                       el[k/bitsz] |= (1 << (k % bitsz));
+               }
+               fprintf(fc, "{ ");
+               for (j = 0; j < MAXREGS; j += bitsz)
+                       fprintf(fc, "0x%x, ", el[j/bitsz]);
+               fprintf(fc, " },\n");
+       }
+       fprintf(fc, "};\n");
+
+       fprintf(fc, "int\ninterferes(int reg1, int reg2)\n{\n");
+       fprintf(fc, "return (TESTBIT(ovlarr[reg1], reg2)) != 0;\n}\n");
+       fclose(fc);
+       fprintf(fh, "#endif /* _EXTERNAL_H_ */\n");
+       fclose(fh);
+       return rval;
+}
+
+#define        P(x)    fprintf x
+
+void
+mktables(void)
+{
+       struct optab *op;
+       int mxalen = 0, curalen;
+       int i;
+
+#if 0
+       P((fc, "#include \"pass2.h\"\n\n"));
+#endif
+       for (i = 0; i <= MAXOP; i++) {
+               curalen = 0;
+               P((fc, "static int op%d[] = { ", i));
+               if (dope[i] != 0)
+               for (op = table; op->op != FREE; op++) {
+                       if (op->op < OPSIMP) {
+                               if (op->op == i) {
+                                       P((fc, FMTdPTR ", ", op - table));
+                                       curalen++;
+                               }
+                       } else {
+                               int opmtemp;
+                               if ((opmtemp=mamask[op->op - OPSIMP])&SPFLG) {
+                                       if (i==NAME || i==ICON || i==TEMP ||
+                                           i==OREG || i == REG || i == FCON) {
+                                               P((fc, FMTdPTR ", ",
+                                                   op - table));
+                                               curalen++;
+                                       }
+                               } else if ((dope[i]&(opmtemp|ASGFLG))==opmtemp){
+                                       P((fc, FMTdPTR ", ", op - table));
+                                       curalen++;
+                               }
+                       }
+               }
+               if (curalen > mxalen)
+                       mxalen = curalen;
+               P((fc, "-1 };\n"));
+       }
+       P((fc, "\n"));
+
+       P((fc, "int *qtable[] = { \n"));
+       for (i = 0; i <= MAXOP; i++) {
+               P((fc, "        op%d,\n", i));
+       }
+       P((fc, "};\n"));
+       P((fh, "#define MAXOPLEN %d\n", mxalen+1));
+}
diff --git a/lang/pcc/pcc/mip/node.h b/lang/pcc/pcc/mip/node.h
new file mode 100644 (file)
index 0000000..d8a47ed
--- /dev/null
@@ -0,0 +1,227 @@
+/*     $Id: node.h,v 1.43 2015/11/17 19:19:40 ragge Exp $      */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NODE_H
+#define NODE_H
+
+/*
+ * The attribute struct contains stuff that might be useful in
+ * both passes; but currently it's only legal to use it in pass1.
+ */
+union aarg {
+       int iarg;
+       char *sarg;
+       void *varg;
+};
+
+struct attr {
+       struct attr *next;
+       unsigned int atype:12, sz:2;
+       union aarg aa[];
+};
+
+#define iarg(x) aa[x].iarg
+#define sarg(x) aa[x].sarg
+#define varg(x) aa[x].varg
+
+/*
+ * The node structure is the basic element in the compiler.
+ * Depending on the operator, it may be one of several types.
+ *
+ * This is rewritten to be a struct instead of a union as it
+ * was in the old compiler.
+ */
+typedef unsigned int TWORD;
+#define NIL (NODE *)0
+
+struct regw;
+
+typedef struct node {
+       int     n_op;
+       union {
+               int _reg;
+               struct regw *_regw;
+       } n_3;
+#define        n_reg   n_3._reg
+#define        n_regw  n_3._regw
+       TWORD   n_type;
+       TWORD   n_qual;
+       int     n_su;
+       union {
+               char *  _name;
+               int     _label;
+#ifdef LANG_CXX
+               union   dimfun *_df;
+#endif
+       } n_5;
+       struct attr *n_ap;
+       union {
+               struct {
+                       union {
+                               struct node *_left;
+                               CONSZ _val;
+                       } n_l;
+                       union {
+                               struct node *_right;
+                               int _rval;
+#ifdef LANG_CXX
+                               struct symtab *_sp;
+#endif
+                       } n_r;
+               } n_u;
+               void *_dcon;
+#if 0
+#ifdef SOFTFLOAT
+#ifdef FDFLOAT
+               /* To store F- or D-floats */
+               struct softfloat {
+                       unsigned short fd1, fd2, fd3, fd4;
+               } _dcon;
+#else
+#error missing softfloat structure definition
+#endif
+#else
+               long double     _dcon;
+#endif
+#endif
+       } n_f;
+} NODE;
+
+#define        n_name  n_5._name
+#define        n_df    n_5._df
+#define        n_label n_5._label
+
+#define        n_left  n_f.n_u.n_l._left
+#define        n_val   n_f.n_u.n_l._val
+#define        n_slval n_f.n_u.n_l._slval
+#define        n_right n_f.n_u.n_r._right
+#define        n_rval  n_f.n_u.n_r._rval
+#define        n_sp    n_f.n_u.n_r._sp
+#define        n_dcon  n_f._dcon
+#define        getlval(p)      ((p)->n_f.n_u.n_l._val)
+#define        setlval(p,v)    ((p)->n_f.n_u.n_l._val = (v))
+
+#define        NLOCAL1 010000
+#define        NLOCAL2 020000
+#define        NLOCAL3 040000
+/*
+ * Node types.
+ *
+ * MAXOP is the highest number used by the backend.
+ */
+
+#define FREE   1
+/*
+ * Value nodes.
+ */
+#define NAME   2
+#define ICON   4
+#define FCON   5
+#define REG    6
+#define OREG   7
+#define TEMP   8
+#define XARG   9
+
+/*
+ * Arithmetic nodes.
+ */
+#define PLUS   10
+#define MINUS  11
+#define DIV    12
+#define MOD    13
+#define MUL    14
+
+/*
+ * Bitwise operations.
+ */
+#define AND    15
+#define OR     16
+#define ER     17
+#define LS     18
+#define RS     19
+#define COMPL  20
+
+#define UMUL   23
+#define UMINUS 24
+
+/*
+ * Logical compare nodes.
+ */
+#define EQ     25
+#define NE     26
+#define LE     27
+#define LT     28
+#define GE     29
+#define GT     30
+#define ULE    31
+#define ULT    32
+#define UGE    33
+#define UGT    34
+
+/*
+ * Branch nodes.
+ */
+#define CBRANCH        35
+
+/*
+ * Convert types.
+ */
+#define FLD    36
+#define SCONV  37
+#define PCONV  38
+#define PMCONV 39
+#define PVCONV 40
+
+/*
+ * Function calls.
+ */
+#define CALL   41
+#define        UCALL   42
+#define FORTCALL 43
+#define UFORTCALL 44
+#define STCALL 45
+#define USTCALL        46
+
+/*
+ *  Other used nodes.
+ */
+#define CCODES 47
+#define CM     48
+#define ASSIGN 49
+#define STASG  50
+#define STARG  51
+#define FORCE  52
+#define XASM   53
+#define        GOTO    54
+#define        RETURN  55
+#define        FUNARG  57
+#define        ADDROF  58
+
+#define        MAXOP   58
+
+#endif
diff --git a/lang/pcc/pcc/mip/optim2.c b/lang/pcc/pcc/mip/optim2.c
new file mode 100644 (file)
index 0000000..6d78463
--- /dev/null
@@ -0,0 +1,2202 @@
+/*     $Id: optim2.c,v 1.92 2015/11/17 19:19:40 ragge Exp $    */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#define        BDEBUG(x)       if (b2debug) printf x
+
+#define        mktemp(n, t)    mklnode(TEMP, 0, n, t)
+
+#define        CHADD(bb,c)     { if (bb->ch[0] == 0) bb->ch[0] = c; \
+                         else if (bb->ch[1] == 0) bb->ch[1] = c; \
+                         else comperr("triple cfnodes"); }
+#define        FORCH(cn, chp)  \
+       for (cn = &chp[0]; cn < &chp[2] && cn[0]; cn++)
+
+/* main switch for new things not yet ready for all-day use */
+/* #define ENABLE_NEW */
+
+
+static int dfsnum;
+
+void saveip(struct interpass *ip);
+void deljumps(struct p2env *);
+void optdump(struct interpass *ip);
+void printip(struct interpass *pole);
+
+static struct varinfo defsites;
+
+void bblocks_build(struct p2env *);
+void cfg_build(struct p2env *);
+void cfg_dfs(struct basicblock *bb, unsigned int parent, 
+            struct bblockinfo *bbinfo);
+void dominators(struct p2env *);
+struct basicblock *
+ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo);
+void computeDF(struct p2env *, struct basicblock *bblock);
+void printDF(struct p2env *p2e);
+void findTemps(struct interpass *ip);
+void placePhiFunctions(struct p2env *);
+void renamevar(struct p2env *p2e,struct basicblock *bblock);
+void removephi(struct p2env *p2e);
+void remunreach(struct p2env *);
+static void liveanal(struct p2env *p2e);
+static void printip2(struct interpass *);
+
+/* create "proper" basic blocks, add labels where needed (so bblocks have labels) */
+/* run before bb generate */
+static void add_labels(struct p2env*) ;
+
+/* Perform trace scheduling, try to get rid of gotos as much as possible */
+void TraceSchedule(struct p2env*) ;
+
+#ifdef ENABLE_NEW
+static void do_cse(struct p2env* p2e) ;
+#endif
+
+/* Walk the complete set, performing a function on each node. 
+ * if type is given, apply function on only that type */
+void WalkAll(struct p2env* p2e, void (*f) (NODE*, void*), void* arg, int type) ;
+
+void BBLiveDead(struct basicblock* bblock, int what, unsigned int variable) ;
+
+/* Fill the live/dead code */
+void LiveDead(struct p2env* p2e, int what, unsigned int variable) ;
+
+#ifdef PCC_DEBUG
+void printflowdiagram(struct p2env *, char *);
+#endif
+
+void
+optimize(struct p2env *p2e)
+{
+       struct interpass *ipole = &p2e->ipole;
+
+       if (b2debug) {
+               printf("initial links\n");
+               printip(ipole);
+       }
+
+       if (xdeljumps)
+               deljumps(p2e); /* Delete redundant jumps and dead code */
+
+       if (xssa)
+               add_labels(p2e) ;
+#ifdef ENABLE_NEW
+       do_cse(p2e);
+#endif
+
+#ifdef PCC_DEBUG
+       if (b2debug) {
+               printf("links after deljumps\n");
+               printip(ipole);
+       }
+#endif
+       if (xssa || xtemps) {
+               bblocks_build(p2e);
+               BDEBUG(("Calling cfg_build\n"));
+               cfg_build(p2e);
+       
+#ifdef PCC_DEBUG
+               printflowdiagram(p2e, "first");
+#endif
+       }
+       if (xssa) {
+               BDEBUG(("Calling liveanal\n"));
+               liveanal(p2e);
+               BDEBUG(("Calling dominators\n"));
+               dominators(p2e);
+               BDEBUG(("Calling computeDF\n"));
+               computeDF(p2e, DLIST_NEXT(&p2e->bblocks, bbelem));
+
+               if (b2debug) {
+                       printDF(p2e);
+               }
+
+               BDEBUG(("Calling placePhiFunctions\n"));
+
+               placePhiFunctions(p2e);
+
+               BDEBUG(("Calling renamevar\n"));
+
+               renamevar(p2e,DLIST_NEXT(&p2e->bblocks, bbelem));
+
+               BDEBUG(("Calling removephi\n"));
+
+#ifdef PCC_DEBUG
+               printflowdiagram(p2e, "ssa");
+#endif
+
+               removephi(p2e);
+
+               BDEBUG(("Calling remunreach\n"));
+/*             remunreach(p2e); */
+               
+               /*
+                * Recalculate basic blocks and cfg that was destroyed
+                * by removephi
+                */
+               /* first, clean up all what deljumps should have done, and more */
+
+               /* TODO: add the basic blocks done by the ssa code by hand. 
+                * The trace scheduler should not change the order in
+                * which blocks are executed or what data is calculated.
+                * Thus, the BBlock order should remain correct.
+                */
+
+#ifdef ENABLE_NEW
+               bblocks_build(p2e);
+               BDEBUG(("Calling cfg_build\n"));
+               cfg_build(p2e);
+
+               TraceSchedule(p2e);
+#ifdef PCC_DEBUG
+               printflowdiagram(p2e, "sched_trace");
+
+               if (b2debug) {
+                       printf("after tracesched\n");
+                       printip(ipole);
+                       fflush(stdout) ;
+               }
+#endif
+#endif
+
+               /* Now, clean up the gotos we do not need any longer */
+               if (xdeljumps)
+                       deljumps(p2e); /* Delete redundant jumps and dead code */
+
+               bblocks_build(p2e);
+               BDEBUG(("Calling cfg_build\n"));
+               cfg_build(p2e);
+
+#ifdef PCC_DEBUG
+               printflowdiagram(p2e, "no_phi");
+
+               if (b2debug) {
+                       printf("new tree\n");
+                       printip(ipole);
+               }
+#endif
+       }
+
+#ifdef PCC_DEBUG
+       {
+               int i;
+               for (i = NIPPREGS; i--; )
+                       if (p2e->epp->ipp_regs[i] != 0)
+                               comperr("register error");
+       }
+#endif
+
+       myoptim(ipole);
+}
+
+/*
+ * Delete unused labels, excess of labels, gotos to gotos.
+ * This routine can be made much more efficient.
+ *
+ * Layout of the statement list here (_must_ look this way!):
+ *     PROLOG
+ *     LABEL   - states beginning of function argument moves
+ *     ...code to save/move arguments
+ *     LABEL   - states beginning of execution code
+ *     ...code + labels in function in function
+ *     EPILOG
+ *
+ * This version of deljumps is based on the c2 implementation
+ * that were included in 2BSD.
+ */
+#define        LABEL 1
+#define        JBR     2
+#define        CBR     3
+#define        STMT    4
+#define        EROU    5
+struct dlnod {
+       int op;
+       struct interpass *dlip;
+       struct dlnod *forw;
+       struct dlnod *back;
+       struct dlnod *ref;
+       int labno;
+       int refc;
+};
+
+#ifdef DLJDEBUG
+static void
+dumplink(struct dlnod *dl)
+{
+       printf("dumplink %p\n", dl);
+       for (; dl; dl = dl->forw) {
+               if (dl->op == STMT) {
+                       printf("STMT(%p)\n", dl);
+                       fwalk(dl->dlip->ip_node, e2print, 0);
+               } else if (dl->op == EROU) {
+                       printf("EROU(%p)\n", dl);
+               } else {
+                       static char *str[] = { 0, "LABEL", "JBR", "CBR" };
+                       printf("%s(%p) %d refc %d ref %p\n", str[dl->op], 
+                           dl, dl->labno, dl->refc, dl->ref);
+               }
+       }
+       printf("end dumplink\n");
+}
+#endif
+
+/*
+ * Create the linked list that we can work on.
+ */
+static void
+listsetup(struct interpass *ipole, struct dlnod *dl)
+{
+       struct interpass *ip = DLIST_NEXT(ipole, qelem);
+       struct interpass *nip;
+       struct dlnod *p, *lastp;
+       NODE *q;
+
+       lastp = dl;
+       while (ip->type != IP_DEFLAB)
+               ip = DLIST_NEXT(ip,qelem);
+       ip = DLIST_NEXT(ip,qelem);
+       while (ip->type != IP_DEFLAB)
+               ip = DLIST_NEXT(ip,qelem);
+       /* Now ip is at the beginning */
+       for (;;) {
+               ip = DLIST_NEXT(ip,qelem);
+               if (ip == ipole)
+                       break;
+               p = tmpalloc(sizeof(struct dlnod));
+               p->labno = 0;
+               p->dlip = ip;
+               switch (ip->type) {
+               case IP_DEFLAB:
+                       p->op = LABEL;
+                       p->labno = ip->ip_lbl;
+                       break;
+
+               case IP_NODE:
+                       q = ip->ip_node;
+                       switch (q->n_op) {
+                       case GOTO:
+                               if (q->n_left->n_op == ICON) {
+                                       p->op = JBR;
+                                       p->labno = getlval(q->n_left);
+                               } else 
+                                       p->op = STMT;
+                               break;
+                       case CBRANCH:
+                               p->op = CBR;
+                               p->labno = getlval(q->n_right);
+                               break;
+                       case ASSIGN:
+                               /* remove ASSIGN to self for regs */
+                               if (q->n_left->n_op == REG && 
+                                   q->n_right->n_op == REG &&
+                                   regno(q->n_left) == regno(q->n_right)) {
+                                       nip = DLIST_PREV(ip, qelem);
+                                       tfree(q);
+                                       DLIST_REMOVE(ip, qelem);
+                                       ip = nip;
+                                       continue;
+                               }
+                               /* FALLTHROUGH */
+                       default:
+                               p->op = STMT;
+                               break;
+                       }
+                       break;
+
+               case IP_ASM:
+                       p->op = STMT;
+                       break;
+
+               case IP_EPILOG:
+                       p->op = EROU;
+                       break;
+
+               default:
+                       comperr("listsetup: bad ip node %d", ip->type);
+               }
+               p->forw = 0;
+               p->back = lastp;
+               lastp->forw = p;
+               lastp = p;
+               p->ref = 0;
+       }
+}
+
+/*
+ * Traverse to the first statement behind a label.
+ */
+static struct dlnod *
+nonlab(struct dlnod *p)
+{
+       while (p && p->op==LABEL)
+               p = p->forw;
+       return(p);
+}
+
+static void
+iprem(struct dlnod *p)
+{
+       if (p->dlip->type == IP_NODE)
+               tfree(p->dlip->ip_node);
+       DLIST_REMOVE(p->dlip, qelem);
+}
+
+static void
+decref(struct dlnod *p)
+{
+       if (--p->refc <= 0) {
+               iprem(p);
+               p->back->forw = p->forw;
+               p->forw->back = p->back;
+       }
+}
+
+/*
+ * Change a label number for jump/branch instruction to labno.
+ */
+static void
+setlab(struct dlnod *p, int labno)
+{
+       p->labno = labno;
+       if (p->op == JBR)
+               setlval(p->dlip->ip_node->n_left, labno);
+       else if (p->op == CBR) {
+               setlval(p->dlip->ip_node->n_right, labno);
+               p->dlip->ip_node->n_left->n_label = labno;
+       } else
+               comperr("setlab bad op %d", p->op);
+}
+
+/*
+ * See if a label is used outside of us.
+ */
+static int
+inuse(struct p2env *p2e, int lbl)
+{
+       int *l;
+
+       for (l = p2e->epp->ip_labels; *l; l++)
+               if (*l == lbl)
+                       return 1;
+       return 0;
+}
+
+/*
+ * Label reference counting and removal of unused labels.
+ */
+#define        LABHS 127
+static void
+refcount(struct p2env *p2e, struct dlnod *dl)
+{
+       struct dlnod *p, *lp;
+       struct dlnod *labhash[LABHS];
+       struct dlnod **hp, *tp;
+
+       /* Clear label hash */
+       for (hp = labhash; hp < &labhash[LABHS];)
+               *hp++ = 0;
+       /* Enter labels into hash.  Later overwrites earlier */
+       for (p = dl->forw; p!=0; p = p->forw) {
+               if (p->op==LABEL) {
+                       labhash[p->labno % LABHS] = p;
+                       p->refc = 0;
+                       if (inuse(p2e, p->labno))
+                               p->refc = 1000; /* never remove */
+               }
+       }
+       /* search for jumps to labels and fill in reference */
+       for (p = dl->forw; p!=0; p = p->forw) {
+               if (p->op==JBR || p->op==CBR) {
+                       p->ref = 0;
+                       lp = labhash[p->labno % LABHS];
+                       if (lp==0 || p->labno!=lp->labno)
+                           for (lp = dl->forw; lp!=0; lp = lp->forw) {
+                               if (lp->op==LABEL && p->labno==lp->labno)
+                                       break;
+                           }
+                       if (lp) {
+                               tp = nonlab(lp)->back;
+                               if (tp!=lp) {
+                                       setlab(p, tp->labno);
+                                       lp = tp;
+                               }
+                               p->ref = lp;
+                               lp->refc++;
+                       }
+               }
+       }
+       for (p = dl->forw; p!=0; p = p->forw)
+               if (p->op==LABEL && p->refc==0 && (lp = nonlab(p))->op)
+                       decref(p);
+}
+
+static int nchange;
+
+static struct dlnod *
+codemove(struct dlnod *p)
+{
+       struct dlnod *p1, *p2, *p3;
+#ifdef notyet
+       struct dlnod *t, *tl;
+       int n;
+#endif
+
+       p1 = p;
+       if (p1->op!=JBR || (p2 = p1->ref)==0)
+               return(p1);
+       while (p2->op == LABEL)
+               if ((p2 = p2->back) == 0)
+                       return(p1);
+       if (p2->op!=JBR)
+               goto ivloop;
+       if (p1==p2)
+               return(p1);
+       p2 = p2->forw;
+       p3 = p1->ref;
+       while (p3) {
+               if (p3->op==JBR) {
+                       if (p1==p3 || p1->forw==p3 || p1->back==p3)
+                               return(p1);
+                       nchange++;
+                       p1->back->forw = p2;
+                       p1->dlip->qelem.q_back->qelem.q_forw = p2->dlip;
+
+                       p1->forw->back = p3;
+                       p1->dlip->qelem.q_forw->qelem.q_back = p3->dlip;
+
+
+                       p2->back->forw = p3->forw;
+                       p2->dlip->qelem.q_back->qelem.q_forw = p3->forw->dlip;
+
+                       p3->forw->back = p2->back;
+                       p3->dlip->qelem.q_forw->qelem.q_back = p2->back->dlip;
+
+                       p2->back = p1->back;
+                       p2->dlip->qelem.q_back = p1->dlip->qelem.q_back;
+
+                       p3->forw = p1->forw;
+                       p3->dlip->qelem.q_forw = p1->forw->dlip;
+
+                       decref(p1->ref);
+                       if (p1->dlip->type == IP_NODE)
+                               tfree(p1->dlip->ip_node);
+
+                       return(p2);
+               } else
+                       p3 = p3->forw;
+       }
+       return(p1);
+
+ivloop:
+       if (p1->forw->op!=LABEL)
+               return(p1);
+       return(p1);
+
+#ifdef notyet
+       p3 = p2 = p2->forw;
+       n = 16;
+       do {
+               if ((p3 = p3->forw) == 0 || p3==p1 || --n==0)
+                       return(p1);
+       } while (p3->op!=CBR || p3->labno!=p1->forw->labno);
+       do 
+               if ((p1 = p1->back) == 0)
+                       return(p);
+       while (p1!=p3);
+       p1 = p;
+       tl = insertl(p1);
+       p3->subop = revbr[p3->subop];
+       decref(p3->ref);
+               p2->back->forw = p1;
+       p3->forw->back = p1;
+       p1->back->forw = p2;
+       p1->forw->back = p3;
+       t = p1->back;
+       p1->back = p2->back;
+       p2->back = t;
+       t = p1->forw;
+       p1->forw = p3->forw;
+       p3->forw = t;
+       p2 = insertl(p1->forw);
+       p3->labno = p2->labno;
+       p3->ref = p2;
+       decref(tl);
+       if (tl->refc<=0)
+               nrlab--;
+       nchange++;
+       return(p3);
+#endif
+}
+
+static void
+iterate(struct p2env *p2e, struct dlnod *dl)
+{
+       struct dlnod *p, *rp, *p1;
+       extern int negrel[];
+       extern size_t negrelsize;
+       int i;
+
+       nchange = 0;
+       for (p = dl->forw; p!=0; p = p->forw) {
+               if ((p->op==JBR||p->op==CBR) && p->ref) {
+                       /* Resolves:
+                        * jbr L7
+                        * ...
+                        * L7: jbr L8
+                        */
+                       rp = nonlab(p->ref);
+                       if (rp->op==JBR && rp->labno && p->labno!=rp->labno) {
+                               setlab(p, rp->labno);
+                               decref(p->ref);
+                               rp->ref->refc++;
+                               p->ref = rp->ref;
+                               nchange++;
+                       }
+               }
+               if (p->op==CBR && (p1 = p->forw)->op==JBR) {
+                       /* Resolves:
+                        * cbr L7
+                        * jbr L8
+                        * L7:
+                        */
+                       rp = p->ref;
+                       do
+                               rp = rp->back;
+                       while (rp->op==LABEL);
+                       if (rp==p1) {
+                               decref(p->ref);
+                               p->ref = p1->ref;
+                               setlab(p, p1->labno);
+
+                               iprem(p1);
+
+                               p1->forw->back = p;
+                               p->forw = p1->forw;
+
+                               i = p->dlip->ip_node->n_left->n_op;
+                               if (i < EQ || i - EQ >= (int)negrelsize)
+                                       comperr("deljumps: unexpected op");
+                               p->dlip->ip_node->n_left->n_op = negrel[i - EQ];
+                               nchange++;
+                       }
+               }
+               if (p->op == JBR) {
+                       /* Removes dead code */
+                       while (p->forw && p->forw->op!=LABEL &&
+                           p->forw->op!=EROU) {
+                               nchange++;
+                               if (p->forw->ref)
+                                       decref(p->forw->ref);
+
+                               iprem(p->forw);
+
+                               p->forw = p->forw->forw;
+                               p->forw->back = p;
+                       }
+                       rp = p->forw;
+                       while (rp && rp->op==LABEL) {
+                               if (p->ref == rp) {
+                                       p->back->forw = p->forw;
+                                       p->forw->back = p->back;
+                                       iprem(p);
+                                       p = p->back;
+                                       decref(rp);
+                                       nchange++;
+                                       break;
+                               }
+                               rp = rp->forw;
+                       }
+               }
+               if (p->op == JBR) {
+                       /* xjump(p); * needs tree rewrite; not yet */
+                       p = codemove(p);
+               }
+       }
+}
+
+void
+deljumps(struct p2env *p2e)
+{
+       struct interpass *ipole = &p2e->ipole;
+       struct dlnod dln;
+       MARK mark;
+
+       markset(&mark);
+
+       memset(&dln, 0, sizeof(dln));
+       listsetup(ipole, &dln);
+       do {
+               refcount(p2e, &dln);
+               do {
+                       iterate(p2e, &dln);
+               } while (nchange);
+#ifdef notyet
+               comjump();
+#endif
+       } while (nchange);
+
+       markfree(&mark);
+}
+
+void
+optdump(struct interpass *ip)
+{
+       static char *nm[] = { "node", "prolog", "newblk", "epilog", "locctr",
+               "deflab", "defnam", "asm" };
+       printf("type %s\n", nm[ip->type-1]);
+       switch (ip->type) {
+       case IP_NODE:
+#ifdef PCC_DEBUG
+               fwalk(ip->ip_node, e2print, 0);
+#endif
+               break;
+       case IP_DEFLAB:
+               printf("label " LABFMT "\n", ip->ip_lbl);
+               break;
+       case IP_ASM:
+               printf("%s", ip->ip_asm);
+               break;
+       }
+}
+
+/*
+ * Build the basic blocks, algorithm 9.1, pp 529 in Compilers.
+ *
+ * Also fills the labelinfo struct with information about which bblocks
+ * that contain which label.
+ */
+
+void
+bblocks_build(struct p2env *p2e)
+{
+       struct interpass *ipole = &p2e->ipole;
+       struct interpass *ip;
+       struct basicblock *bb = NULL;
+       int low, high;
+       int count = 0;
+       int i;
+
+       BDEBUG(("bblocks_build (%p, %p)\n", &p2e->labinfo, &p2e->bbinfo));
+       low = p2e->ipp->ip_lblnum;
+       high = p2e->epp->ip_lblnum;
+
+       /* 
+        * First statement is a leader.
+        * Any statement that is target of a jump is a leader.
+        * Any statement that immediately follows a jump is a leader.
+        */
+       DLIST_INIT(&p2e->bblocks, bbelem);
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (bb == NULL || (ip->type == IP_EPILOG) ||
+                   (ip->type == IP_DEFLAB) || (ip->type == IP_DEFNAM)) {
+                       bb = tmpalloc(sizeof(struct basicblock));
+                       bb->first = ip;
+                       SLIST_INIT(&bb->parents);
+                       SLIST_INIT(&bb->child);
+                       bb->dfnum = 0;
+                       bb->dfparent = 0;
+                       bb->semi = 0;
+                       bb->ancestor = 0;
+                       bb->idom = 0;
+                       bb->samedom = 0;
+                       bb->bucket = NULL;
+                       bb->df = NULL;
+                       bb->dfchildren = NULL;
+                       bb->Aorig = NULL;
+                       bb->Aphi = NULL;
+                       SLIST_INIT(&bb->phi);
+                       bb->bbnum = count;
+                       DLIST_INSERT_BEFORE(&p2e->bblocks, bb, bbelem);
+                       count++;
+               }
+               bb->last = ip;
+               if ((ip->type == IP_NODE) && (ip->ip_node->n_op == GOTO || 
+                   ip->ip_node->n_op == CBRANCH))
+                       bb = NULL;
+               if (ip->type == IP_PROLOG)
+                       bb = NULL;
+       }
+       p2e->nbblocks = count;
+
+       if (b2debug) {
+               printf("Basic blocks in func: %d, low %d, high %d\n",
+                   count, low, high);
+               DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+                       printf("bb(%d) %p: first %p last %p\n", bb->bbnum, bb,
+                           bb->first, bb->last);
+               }
+       }
+
+       p2e->labinfo.low = low;
+       p2e->labinfo.size = high - low + 1;
+       p2e->labinfo.arr = tmpalloc(p2e->labinfo.size * sizeof(struct basicblock *));
+       for (i = 0; i < p2e->labinfo.size; i++) {
+               p2e->labinfo.arr[i] = NULL;
+       }
+       
+       p2e->bbinfo.size = count + 1;
+       p2e->bbinfo.arr = tmpalloc(p2e->bbinfo.size * sizeof(struct basicblock *));
+       for (i = 0; i < p2e->bbinfo.size; i++) {
+               p2e->bbinfo.arr[i] = NULL;
+       }
+
+       /* Build the label table */
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               if (bb->first->type == IP_DEFLAB)
+                       p2e->labinfo.arr[bb->first->ip_lbl - low] = bb;
+       }
+
+       if (b2debug) {
+               DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+                       printf("bblock %d\n", bb->bbnum);
+                       for (ip = bb->first; ip != bb->last;
+                           ip = DLIST_NEXT(ip, qelem)) {
+                               printip2(ip);
+                       }
+                       printip2(ip);
+               }
+
+               printf("Label table:\n");
+               for (i = 0; i < p2e->labinfo.size; i++)
+                       if (p2e->labinfo.arr[i])
+                               printf("Label %d bblock %p\n", i+low,
+                                   p2e->labinfo.arr[i]);
+       }
+}
+
+/*
+ * Build the control flow graph.
+ */
+
+void
+cfg_build(struct p2env *p2e)
+{
+       /* Child and parent nodes */
+       struct cfgnode *cnode; 
+       struct cfgnode *pnode;
+       struct basicblock *bb;
+       NODE *p;
+
+#ifdef notyet
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               if (bb->first->type == IP_EPILOG)
+                       break;
+
+               if (bb->last->type == IP_NODE) {
+                       p = bb->last->ip_node;
+                       switch (p->n_op) {
+                       case GOTO:
+                               if (p->n_left->n_op == ICON) {
+                                       lbchk(p2e, p->n_left->n_lval);
+                                       fillcnode(p2e, p->n_left->n_lval, bb);
+                               } else {
+                               }
+                               break;
+
+                       case CBRANCH:
+                               lbchk(p2e, p->n_right->n_lval);
+                               fillcnode(p2e, p->n_right->n_lval, bb);
+                               ...
+
+                       default:
+                               ...
+                       }
+               } else {
+                       ...
+               }
+       }
+#endif
+
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               if (bb->first->type == IP_EPILOG)
+                       break;
+       
+               cnode = tmpalloc(sizeof(struct cfgnode));
+               pnode = tmpalloc(sizeof(struct cfgnode));
+               pnode->bblock = bb;
+
+               p = bb->last->ip_node;
+               if (bb->last->type == IP_NODE && p->n_op == GOTO) {
+                       if (p->n_left->n_op == ICON) {
+                               if (getlval(p->n_left) - p2e->labinfo.low > p2e->labinfo.size)
+                                       comperr("Label out of range: %d, base %d", 
+                                           getlval(p->n_left), p2e->labinfo.low);
+                               cnode->bblock = p2e->labinfo.arr[getlval(p->n_left) - p2e->labinfo.low];
+                               SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+                               SLIST_INSERT_LAST(&bb->child, cnode, chld);
+                       } else {
+                               int *l;
+                               /* XXX assume all labels are valid as dest */
+                               for (l = p2e->epp->ip_labels; *l; l++) {
+                                       cnode->bblock = p2e->labinfo.arr[*l - p2e->labinfo.low];
+                                       SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+                                       SLIST_INSERT_LAST(&bb->child, cnode, chld);
+                                       cnode = tmpalloc(sizeof(struct cfgnode));
+                                       pnode = tmpalloc(sizeof(struct cfgnode));
+                                       pnode->bblock = bb;
+                               }
+                       }
+                       continue;
+               }
+               if ((bb->last->type == IP_NODE) && p->n_op == CBRANCH) {
+                       if (getlval(p->n_right) - p2e->labinfo.low > p2e->labinfo.size) 
+                               comperr("Label out of range: %d", getlval(p->n_left));
+
+                       cnode->bblock = p2e->labinfo.arr[getlval(p->n_right) - p2e->labinfo.low];
+                       SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+                       SLIST_INSERT_LAST(&bb->child, cnode, chld);
+                       cnode = tmpalloc(sizeof(struct cfgnode));
+                       pnode = tmpalloc(sizeof(struct cfgnode));
+                       pnode->bblock = bb;
+               }
+
+               cnode->bblock = DLIST_NEXT(bb, bbelem);
+               SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+               SLIST_INSERT_LAST(&bb->child, cnode, chld);
+       }
+}
+
+void
+cfg_dfs(struct basicblock *bb, unsigned int parent, struct bblockinfo *bbinfo)
+{
+       struct cfgnode *cn;
+
+       if (bb->dfnum != 0)
+               return;
+
+       bb->dfnum = ++dfsnum;
+       bb->dfparent = parent;
+       bbinfo->arr[bb->dfnum] = bb;
+       SLIST_FOREACH(cn, &bb->child, chld)
+               cfg_dfs(cn->bblock, bb->dfnum, bbinfo);
+       /* Don't bring in unreachable nodes in the future */
+       bbinfo->size = dfsnum + 1;
+}
+
+static bittype *
+setalloc(int nelem)
+{
+       bittype *b;
+       int sz = (nelem+NUMBITS-1)/NUMBITS;
+
+       b = tmpalloc(sz * sizeof(bittype));
+       memset(b, 0, sz * sizeof(bittype));
+       return b;
+}
+
+/*
+ * Algorithm 19.9, pp 414 from Appel.
+ */
+
+void
+dominators(struct p2env *p2e)
+{
+       struct cfgnode *cnode;
+       struct basicblock *bb, *y, *v;
+       struct basicblock *s, *sprime, *p;
+       int h, i;
+
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               bb->bucket = setalloc(p2e->bbinfo.size);
+               bb->df = setalloc(p2e->bbinfo.size);
+               bb->dfchildren = setalloc(p2e->bbinfo.size);
+       }
+
+       dfsnum = 0;
+       cfg_dfs(DLIST_NEXT(&p2e->bblocks, bbelem), 0, &p2e->bbinfo);
+
+       if (b2debug) {
+               struct basicblock *bbb;
+               struct cfgnode *ccnode, *cn;
+
+               DLIST_FOREACH(bbb, &p2e->bblocks, bbelem) {
+                       printf("Basic block %d, parents: ", bbb->dfnum);
+                       SLIST_FOREACH(ccnode, &bbb->parents, cfgelem) {
+                               printf("%d, ", ccnode->bblock->dfnum);
+                       }
+                       printf("\nChildren: ");
+                       SLIST_FOREACH(cn, &bbb->child, chld)
+                               printf("%d, ", cn->bblock->dfnum);
+                       printf("\n");
+               }
+       }
+
+       for(h = p2e->bbinfo.size - 1; h > 1; h--) {
+               bb = p2e->bbinfo.arr[h];
+               p = s = p2e->bbinfo.arr[bb->dfparent];
+               SLIST_FOREACH(cnode, &bb->parents, cfgelem) {
+                       if (cnode->bblock->dfnum ==0)
+                               continue; /* Ignore unreachable code */
+
+                       if (cnode->bblock->dfnum <= bb->dfnum) 
+                               sprime = cnode->bblock;
+                       else 
+                               sprime = p2e->bbinfo.arr[ancestorwithlowestsemi
+                                             (cnode->bblock, &p2e->bbinfo)->semi];
+                       if (sprime->dfnum < s->dfnum)
+                               s = sprime;
+               }
+               bb->semi = s->dfnum;
+               BITSET(s->bucket, bb->dfnum);
+               bb->ancestor = p->dfnum;
+               for (i = 1; i < p2e->bbinfo.size; i++) {
+                       if(TESTBIT(p->bucket, i)) {
+                               v = p2e->bbinfo.arr[i];
+                               y = ancestorwithlowestsemi(v, &p2e->bbinfo);
+                               if (y->semi == v->semi) 
+                                       v->idom = p->dfnum;
+                               else
+                                       v->samedom = y->dfnum;
+                       }
+               }
+               memset(p->bucket, 0, (p2e->bbinfo.size + 7)/8);
+       }
+
+       if (b2debug) {
+               printf("Num\tSemi\tAncest\tidom\n");
+               DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+                       printf("%d\t%d\t%d\t%d\n", bb->dfnum, bb->semi,
+                           bb->ancestor, bb->idom);
+               }
+       }
+
+       for(h = 2; h < p2e->bbinfo.size; h++) {
+               bb = p2e->bbinfo.arr[h];
+               if (bb->samedom != 0) {
+                       bb->idom = p2e->bbinfo.arr[bb->samedom]->idom;
+               }
+       }
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               if (bb->idom != 0 && bb->idom != bb->dfnum) {
+                       BDEBUG(("Setting child %d of %d\n",
+                           bb->dfnum, p2e->bbinfo.arr[bb->idom]->dfnum));
+                       BITSET(p2e->bbinfo.arr[bb->idom]->dfchildren, bb->dfnum);
+               }
+       }
+}
+
+
+struct basicblock *
+ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo)
+{
+       struct basicblock *u = bblock;
+       struct basicblock *v = bblock;
+
+       while (v->ancestor != 0) {
+               if (bbinfo->arr[v->semi]->dfnum < 
+                   bbinfo->arr[u->semi]->dfnum) 
+                       u = v;
+               v = bbinfo->arr[v->ancestor];
+       }
+       return u;
+}
+
+void
+computeDF(struct p2env *p2e, struct basicblock *bblock)
+{
+       struct cfgnode *cn;
+       int h, i;
+       
+       SLIST_FOREACH(cn, &bblock->child, chld) {
+               if (cn->bblock->idom != bblock->dfnum)
+                       BITSET(bblock->df, cn->bblock->dfnum);
+       }
+       for (h = 1; h < p2e->bbinfo.size; h++) {
+               if (!TESTBIT(bblock->dfchildren, h))
+                       continue;
+               computeDF(p2e, p2e->bbinfo.arr[h]);
+               for (i = 1; i < p2e->bbinfo.size; i++) {
+                       if (TESTBIT(p2e->bbinfo.arr[h]->df, i) && 
+                           (p2e->bbinfo.arr[i] == bblock ||
+                            (bblock->dfnum != p2e->bbinfo.arr[i]->idom))) 
+                           BITSET(bblock->df, i);
+               }
+       }
+}
+
+void printDF(struct p2env *p2e)
+{
+       struct basicblock *bb;
+       int i;
+
+       printf("Dominance frontiers:\n");
+    
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               printf("bb %d : ", bb->dfnum);
+       
+               for (i=1; i < p2e->bbinfo.size;i++) {
+                       if (TESTBIT(bb->df,i)) {
+                               printf("%d ",i);
+                       }
+               }
+           
+               printf("\n");
+       }
+    
+}
+
+
+
+static struct basicblock *currbb;
+
+/* Helper function for findTemps, Find assignment nodes. */
+static void
+searchasg(NODE *p, void *arg)
+{
+       struct pvarinfo *pv;
+       int tempnr;
+       struct varstack *stacke;
+    
+       if (p->n_op != ASSIGN)
+               return;
+
+       if (p->n_left->n_op != TEMP)
+               return;
+
+       tempnr=regno(p->n_left)-defsites.low;
+    
+       BITSET(currbb->Aorig, tempnr);
+       
+       pv = tmpcalloc(sizeof(struct pvarinfo));
+       pv->next = defsites.arr[tempnr];
+       pv->bb = currbb;
+       pv->n_type = p->n_left->n_type;
+       
+       defsites.arr[tempnr] = pv;
+       
+       
+       if (SLIST_FIRST(&defsites.stack[tempnr])==NULL) {
+               stacke=tmpcalloc(sizeof (struct varstack));
+               stacke->tmpregno=0;
+               SLIST_INSERT_FIRST(&defsites.stack[tempnr],stacke,varstackelem);
+       }
+}
+
+/* Walk the interpass looking for assignment nodes. */
+void findTemps(struct interpass *ip)
+{
+       if (ip->type != IP_NODE)
+               return;
+
+       walkf(ip->ip_node, searchasg, 0);
+}
+
+/*
+ * Algorithm 19.6 from Appel.
+ */
+
+void
+placePhiFunctions(struct p2env *p2e)
+{
+       struct basicblock *bb;
+       struct basicblock *y;
+       struct interpass *ip;
+       int maxtmp, i, j, k;
+       struct pvarinfo *n;
+       struct cfgnode *cnode;
+       TWORD ntype;
+       struct pvarinfo *pv;
+       struct phiinfo *phi;
+       int phifound;
+
+       bb = DLIST_NEXT(&p2e->bblocks, bbelem);
+       defsites.low = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
+       bb = DLIST_PREV(&p2e->bblocks, bbelem);
+       maxtmp = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
+       defsites.size = maxtmp - defsites.low + 1;
+       defsites.arr = tmpcalloc(defsites.size*sizeof(struct pvarinfo *));
+       defsites.stack = tmpcalloc(defsites.size*sizeof(SLIST_HEAD(, varstack)));
+       
+       for (i=0;i<defsites.size;i++)
+               SLIST_INIT(&defsites.stack[i]); 
+       
+       /* Find all defsites */
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               currbb = bb;
+               ip = bb->first;
+               bb->Aorig = setalloc(defsites.size);
+               bb->Aphi = setalloc(defsites.size);
+               
+               while (ip != bb->last) {
+                       findTemps(ip);
+                       ip = DLIST_NEXT(ip, qelem);
+               }
+               /* Make sure we get the last statement in the bblock */
+               findTemps(ip);
+       }
+
+       /* For each variable */
+       for (i = 0; i < defsites.size; i++) {
+               /* While W not empty */
+               while (defsites.arr[i] != NULL) {
+                       /* Remove some node n from W */
+                       n = defsites.arr[i];
+                       defsites.arr[i] = n->next;
+                       /* For each y in n->bb->df */
+                       for (j = 0; j < p2e->bbinfo.size; j++) {
+                               if (!TESTBIT(n->bb->df, j))
+                                       continue;
+                               
+                               if (TESTBIT(p2e->bbinfo.arr[j]->Aphi, i))
+                                       continue;
+
+                               y=p2e->bbinfo.arr[j];
+                               ntype = n->n_type;
+                               k = 0;
+                               /* Amount of predecessors for y */
+                               SLIST_FOREACH(cnode, &y->parents, cfgelem) 
+                                       k++;
+                               /* Construct phi(...) 
+                               */
+                           
+                               phifound=0;
+                           
+                               SLIST_FOREACH(phi, &y->phi, phielem) {
+                                   if (phi->tmpregno==i+defsites.low)
+                                       phifound++;
+                               }
+                           
+                               if (phifound==0) {
+                                       if (b2debug)
+                                           printf("Phi in %d(%d) (%p) for %d\n",
+                                           y->dfnum,y->bbnum,y,i+defsites.low);
+
+                                       /* If no live in, no phi node needed */
+                                       if (!TESTBIT(y->in,
+                                           (i+defsites.low-p2e->ipp->ip_tmpnum+MAXREGS))) {
+                                       if (b2debug)
+                                       printf("tmp %d bb %d unused, no phi\n",
+                                           i+defsites.low, y->bbnum);
+                                               /* No live in */
+                                               BITSET(p2e->bbinfo.arr[j]->Aphi, i);
+                                               continue;
+                                       }
+
+                                       phi = tmpcalloc(sizeof(struct phiinfo));
+                           
+                                       phi->tmpregno=i+defsites.low;
+                                       phi->size=k;
+                                       phi->n_type=ntype;
+                                       phi->intmpregno=tmpcalloc(k*sizeof(int));
+                           
+                                       SLIST_INSERT_LAST(&y->phi,phi,phielem);
+                               } else {
+                                   if (b2debug)
+                                       printf("Phi already in %d for %d\n",y->dfnum,i+defsites.low);
+                               }
+
+                               BITSET(p2e->bbinfo.arr[j]->Aphi, i);
+                               if (!TESTBIT(p2e->bbinfo.arr[j]->Aorig, i)) {
+                                       pv = tmpalloc(sizeof(struct pvarinfo));
+                                       pv->bb = y;
+                                       pv->n_type=ntype;
+                                       pv->next = defsites.arr[i];
+                                       defsites.arr[i] = pv;
+                               }
+                       }
+               }
+       }
+}
+
+/* Helper function for renamevar. */
+static void
+renamevarhelper(struct p2env *p2e,NODE *t,void *poplistarg)
+{      
+       SLIST_HEAD(, varstack) *poplist=poplistarg;
+       int opty;
+       int tempnr;
+       int newtempnr;
+       int x;
+       struct varstack *stacke;
+       
+       if (t->n_op == ASSIGN && t->n_left->n_op == TEMP) {
+               renamevarhelper(p2e,t->n_right,poplist);
+                               
+               tempnr=regno(t->n_left)-defsites.low;
+               
+               newtempnr=p2e->epp->ip_tmpnum++;
+               regno(t->n_left)=newtempnr;
+               
+               stacke=tmpcalloc(sizeof (struct varstack));
+               stacke->tmpregno=newtempnr;
+               SLIST_INSERT_FIRST(&defsites.stack[tempnr],stacke,varstackelem);
+               
+               stacke=tmpcalloc(sizeof (struct varstack));
+               stacke->tmpregno=tempnr;
+               SLIST_INSERT_FIRST(poplist,stacke,varstackelem);
+       } else {
+               if (t->n_op == TEMP) {
+                       tempnr=regno(t)-defsites.low;
+               
+                       if (SLIST_FIRST(&defsites.stack[tempnr])!=NULL) {
+                               x=SLIST_FIRST(&defsites.stack[tempnr])->tmpregno;
+                               regno(t)=x;
+                       }
+               }
+               
+               opty = optype(t->n_op);
+               
+               if (opty != LTYPE)
+                       renamevarhelper(p2e, t->n_left,poplist);
+               if (opty == BITYPE)
+                       renamevarhelper(p2e, t->n_right,poplist);
+       }
+}
+
+
+void
+renamevar(struct p2env *p2e,struct basicblock *bb)
+{
+       struct interpass *ip;
+       int h,j;
+       SLIST_HEAD(, varstack) poplist;
+       struct varstack *stacke;
+       struct cfgnode *cfgn2, *cn;
+       int tmpregno,newtmpregno;
+       struct phiinfo *phi;
+
+       SLIST_INIT(&poplist);
+
+       SLIST_FOREACH(phi,&bb->phi,phielem) {
+               tmpregno=phi->tmpregno-defsites.low;
+               
+               newtmpregno=p2e->epp->ip_tmpnum++;
+               phi->newtmpregno=newtmpregno;
+
+               stacke=tmpcalloc(sizeof (struct varstack));
+               stacke->tmpregno=newtmpregno;
+               SLIST_INSERT_FIRST(&defsites.stack[tmpregno],stacke,varstackelem);
+               
+               stacke=tmpcalloc(sizeof (struct varstack));
+               stacke->tmpregno=tmpregno;
+               SLIST_INSERT_FIRST(&poplist,stacke,varstackelem);               
+       }
+
+
+       ip=bb->first;
+
+       while (1) {             
+               if ( ip->type == IP_NODE) {
+                       renamevarhelper(p2e,ip->ip_node,&poplist);
+               }
+
+               if (ip==bb->last)
+                       break;
+
+               ip = DLIST_NEXT(ip, qelem);
+       }
+
+       SLIST_FOREACH(cn, &bb->child, chld) {
+               j=0;
+
+               SLIST_FOREACH(cfgn2, &cn->bblock->parents, cfgelem) { 
+                       if (cfgn2->bblock->dfnum==bb->dfnum)
+                               break;
+                       
+                       j++;
+               }
+
+               SLIST_FOREACH(phi,&cn->bblock->phi,phielem) {
+                       phi->intmpregno[j]=SLIST_FIRST(&defsites.stack[phi->tmpregno-defsites.low])->tmpregno;
+               }
+       }
+
+       for (h = 1; h < p2e->bbinfo.size; h++) {
+               if (!TESTBIT(bb->dfchildren, h))
+                       continue;
+
+               renamevar(p2e,p2e->bbinfo.arr[h]);
+       }
+
+       SLIST_FOREACH(stacke,&poplist,varstackelem) {
+               tmpregno=stacke->tmpregno;
+               
+               defsites.stack[tmpregno].q_forw=defsites.stack[tmpregno].q_forw->varstackelem.q_forw;
+       }
+}
+
+enum pred_type {
+    pred_unknown    = 0,
+    pred_goto       = 1,
+    pred_cond       = 2,
+    pred_falltrough = 3,
+} ;
+
+void
+removephi(struct p2env *p2e)
+{
+       struct basicblock *bb,*bbparent;
+       struct cfgnode *cfgn;
+       struct phiinfo *phi;
+       int i;
+       struct interpass *ip;
+       struct interpass *pip;
+       TWORD n_type;
+
+       enum pred_type complex = pred_unknown ;
+
+       int label=0;
+       int newlabel;
+
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {              
+               SLIST_FOREACH(phi,&bb->phi,phielem) {
+                       /* Look at only one, notice break at end */
+                       i=0;
+                       
+                       SLIST_FOREACH(cfgn, &bb->parents, cfgelem) { 
+                               bbparent=cfgn->bblock;
+                               
+                               pip=bbparent->last;
+                               
+                               complex = pred_unknown ;
+                               
+                               BDEBUG(("removephi: %p in %d",pip,bb->dfnum));
+
+                               if (pip->type == IP_NODE && pip->ip_node->n_op == GOTO) {
+                                       BDEBUG((" GOTO "));
+                                       label = (int)getlval(pip->ip_node->n_left);
+                                       complex = pred_goto ;
+                               } else if (pip->type == IP_NODE && pip->ip_node->n_op == CBRANCH) {
+                                       BDEBUG((" CBRANCH "));
+                                       label = (int)getlval(pip->ip_node->n_right);
+                                       
+                                       if (bb==p2e->labinfo.arr[label - p2e->ipp->ip_lblnum])
+                                               complex = pred_cond ;
+                                       else
+                                               complex = pred_falltrough ;
+
+                               } else if (DLIST_PREV(bb, bbelem) == bbparent) {
+                                       complex = pred_falltrough ;
+                               } else {
+                                           /* PANIC */
+                                       comperr("Assumption blown in rem-phi") ;
+                               }
+       
+                               BDEBUG((" Complex: %d ",complex)) ;
+
+                               switch (complex) {
+                                 case pred_goto:
+                                       /* gotos can only go to this place. No bounce tab needed */
+                                       SLIST_FOREACH(phi,&bb->phi,phielem) {
+                                               if (phi->intmpregno[i]>0) {
+                                                       n_type=phi->n_type;
+                                                       ip = ipnode(mkbinode(ASSIGN,
+                                                            mktemp(phi->newtmpregno, n_type),
+                                                            mktemp(phi->intmpregno[i],n_type),
+                                                            n_type));
+                                                       BDEBUG(("(%p, %d -> %d) ", ip, phi->intmpregno[i], phi->newtmpregno));
+                               
+                                                       DLIST_INSERT_BEFORE((bbparent->last), ip, qelem);
+                                               }
+                                       }
+                                       break ;
+                                 case pred_cond:
+                                       /* Here, we need a jump pad */
+                                       newlabel=getlab2();
+                       
+                                       ip = tmpalloc(sizeof(struct interpass));
+                                       ip->type = IP_DEFLAB;
+                                       /* Line number?? ip->lineno; */
+                                       ip->ip_lbl = newlabel;
+                                       DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+
+                                       SLIST_FOREACH(phi,&bb->phi,phielem) {
+                                               if (phi->intmpregno[i]>0) {
+                                                       n_type=phi->n_type;
+                                                       ip = ipnode(mkbinode(ASSIGN,
+                                                            mktemp(phi->newtmpregno, n_type),
+                                                            mktemp(phi->intmpregno[i],n_type),
+                                                            n_type));
+
+                                                       BDEBUG(("(%p, %d -> %d) ", ip, phi->intmpregno[i], phi->newtmpregno));
+                                                       DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+                                               }
+                                       }
+                                       /* add a jump to us */
+                                       ip = ipnode(mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT));
+                                       DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+                                       setlval(pip->ip_node->n_right,newlabel);
+                                       if (!logop(pip->ip_node->n_left->n_op))
+                                               comperr("SSA not logop");
+                                       pip->ip_node->n_left->n_label=newlabel;
+                                       break ;
+                                 case pred_falltrough:
+                                       if (bb->first->type == IP_DEFLAB) { 
+                                               label = bb->first->ip_lbl; 
+                                               BDEBUG(("falltrough label %d\n", label));
+                                       } else {
+                                               comperr("BBlock has no label?") ;
+                                       }
+
+                                       /* 
+                                        * add a jump to us. We _will_ be, or already have, added code in between.
+                                        * The code is created in the wrong order and switched at the insert, thus
+                                        * comming out correctly
+                                        */
+
+                                       ip = ipnode(mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT));
+                                       DLIST_INSERT_AFTER((bbparent->last), ip, qelem);
+
+                                       /* Add the code to the end, add a jump to us. */
+                                       SLIST_FOREACH(phi,&bb->phi,phielem) {
+                                               if (phi->intmpregno[i]>0) {
+                                                       n_type=phi->n_type;
+                                                       ip = ipnode(mkbinode(ASSIGN,
+                                                               mktemp(phi->newtmpregno, n_type),
+                                                               mktemp(phi->intmpregno[i],n_type),
+                                                               n_type));
+
+                                                       BDEBUG(("(%p, %d -> %d) ", ip, phi->intmpregno[i], phi->newtmpregno));
+                                                       DLIST_INSERT_AFTER((bbparent->last), ip, qelem);
+                                               }
+                                       }
+                                       break ;
+                               default:
+                                       comperr("assumption blown, complex is %d\n", complex) ;
+                               }
+                               BDEBUG(("\n"));
+                               i++;
+                       }
+                       break;
+               }
+       }
+}
+
+    
+/*
+ * Remove unreachable nodes in the CFG.
+ */ 
+
+void
+remunreach(struct p2env *p2e)
+{
+       struct basicblock *bb, *nbb;
+       struct interpass *next, *ctree;
+
+       bb = DLIST_NEXT(&p2e->bblocks, bbelem);
+       while (bb != &p2e->bblocks) {
+               nbb = DLIST_NEXT(bb, bbelem);
+
+               /* Code with dfnum 0 is unreachable */
+               if (bb->dfnum != 0) {
+                       bb = nbb;
+                       continue;
+               }
+
+               /* Need the epilogue node for other parts of the
+                  compiler, set its label to 0 and backend will
+                  handle it. */ 
+               if (bb->first->type == IP_EPILOG) {
+                       bb->first->ip_lbl = 0;
+                       bb = nbb;
+                       continue;
+               }
+
+               next = bb->first;
+               do {
+                       ctree = next;
+                       next = DLIST_NEXT(ctree, qelem);
+                       
+                       if (ctree->type == IP_NODE)
+                               tfree(ctree->ip_node);
+                       DLIST_REMOVE(ctree, qelem);
+               } while (ctree != bb->last);
+                       
+               DLIST_REMOVE(bb, bbelem);
+               bb = nbb;
+       }
+}
+
+static void
+printip2(struct interpass *ip)
+{
+       static char *foo[] = {
+          0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+       struct interpass_prolog *ipplg, *epplg;
+       unsigned i;
+       int *l;
+
+       if (ip->type > MAXIP)
+               printf("IP(%d) (%p): ", ip->type, ip);
+       else
+               printf("%s (%p): ", foo[ip->type], ip);
+       switch (ip->type) {
+       case IP_NODE: printf("\n");
+#ifdef PCC_DEBUG
+       fwalk(ip->ip_node, e2print, 0); break;
+#endif
+       case IP_PROLOG:
+               ipplg = (struct interpass_prolog *)ip;
+               printf("%s %s regs",
+                   ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "");
+               for (i = 0; i < NIPPREGS; i++)
+                       printf("%s0x%lx", i? ":" : " ",
+                           (long) ipplg->ipp_regs[i]);
+               printf(" autos %d mintemp %d minlbl %d\n",
+                   ipplg->ipp_autos, ipplg->ip_tmpnum, ipplg->ip_lblnum);
+               break;
+       case IP_EPILOG:
+               epplg = (struct interpass_prolog *)ip;
+               printf("%s %s regs",
+                   epplg->ipp_name, epplg->ipp_vis ? "(local)" : "");
+               for (i = 0; i < NIPPREGS; i++)
+                       printf("%s0x%lx", i? ":" : " ",
+                           (long) epplg->ipp_regs[i]);
+               printf(" autos %d mintemp %d minlbl %d\ncgoto labels: ",
+                   epplg->ipp_autos, epplg->ip_tmpnum, epplg->ip_lblnum);
+               for (l = epplg->ip_labels; *l; l++)
+                       printf("%d ", *l);
+               printf("\n");
+               break;
+       case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
+       case IP_DEFNAM: printf("\n"); break;
+       case IP_ASM: printf("%s\n", ip->ip_asm); break;
+       default:
+               break;
+       }
+}
+
+void
+printip(struct interpass *pole)
+{
+       struct interpass *ip;
+
+       DLIST_FOREACH(ip, pole, qelem)
+               printip2(ip);
+}
+
+#ifdef PCC_DEBUG
+void flownodeprint(NODE *p,FILE *flowdiagramfile);
+
+void
+flownodeprint(NODE *p,FILE *flowdiagramfile)
+{      
+       struct attr *ap;
+       int opty;
+       char *o;
+
+       fprintf(flowdiagramfile,"{");
+
+       o=opst[p->n_op];
+       
+       while (*o != 0) {
+               if (*o=='<' || *o=='>')
+                       fputc('\\',flowdiagramfile);
+               
+               fputc(*o,flowdiagramfile);
+               o++;
+       }
+       
+       
+       switch( p->n_op ) {                     
+               case REG:
+                       fprintf(flowdiagramfile, " %s", rnames[p->n_rval] );
+                       break;
+                       
+               case TEMP:
+                       fprintf(flowdiagramfile, " %d", regno(p));
+                       break;
+                       
+               case XASM:
+               case XARG:
+                       fprintf(flowdiagramfile, " '%s'", p->n_name);
+                       break;
+                       
+               case ICON:
+               case NAME:
+               case OREG:
+                       fprintf(flowdiagramfile, " " );
+                       adrput(flowdiagramfile, p );
+                       break;
+                       
+               case STCALL:
+               case USTCALL:
+               case STARG:
+               case STASG:
+                       ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+                       fprintf(flowdiagramfile, " size=%d", ap->iarg(0));
+                       fprintf(flowdiagramfile, " align=%d", ap->iarg(1));
+                       break;
+       }
+       
+       opty = optype(p->n_op);
+       
+       if (opty != LTYPE) {
+               fprintf(flowdiagramfile,"| {");
+       
+               flownodeprint(p->n_left,flowdiagramfile);
+       
+               if (opty == BITYPE) {
+                       fprintf(flowdiagramfile,"|");
+                       flownodeprint(p->n_right,flowdiagramfile);
+               }
+               fprintf(flowdiagramfile,"}");
+       }
+       
+       fprintf(flowdiagramfile,"}");
+}
+
+void
+printflowdiagram(struct p2env *p2e, char *type) {
+       struct basicblock *bbb;
+       struct cfgnode *cn;
+       struct interpass *ip;
+       struct interpass_prolog *plg;
+       struct phiinfo *phi;
+       char *name;
+       char *filename;
+       int filenamesize;
+       char *ext=".dot";
+       FILE *flowdiagramfile;
+       
+       if (!g2debug)
+               return;
+       
+       bbb=DLIST_NEXT(&p2e->bblocks, bbelem);
+       ip=bbb->first;
+
+       if (ip->type != IP_PROLOG)
+               return;
+       plg = (struct interpass_prolog *)ip;
+
+       name=plg->ipp_name;
+       
+       filenamesize=strlen(name)+1+strlen(type)+strlen(ext)+1;
+       filename=tmpalloc(filenamesize);
+       snprintf(filename,filenamesize,"%s-%s%s",name,type,ext);
+       
+       flowdiagramfile=fopen(filename,"w");
+       
+       fprintf(flowdiagramfile,"digraph {\n");
+       fprintf(flowdiagramfile,"rankdir=LR\n");
+       
+       DLIST_FOREACH(bbb, &p2e->bblocks, bbelem) {
+               ip=bbb->first;
+               
+               fprintf(flowdiagramfile,"bb%p [shape=record ",bbb);
+               
+               if (ip->type==IP_PROLOG)
+                       fprintf(flowdiagramfile,"root ");
+
+               fprintf(flowdiagramfile,"label=\"");
+               
+               SLIST_FOREACH(phi,&bbb->phi,phielem) {
+                       fprintf(flowdiagramfile,"Phi %d|",phi->tmpregno);
+               }               
+               
+               
+               while (1) {
+                       switch (ip->type) {
+                               case IP_NODE: 
+                                       flownodeprint(ip->ip_node,flowdiagramfile);
+                                       break;
+                                       
+                               case IP_DEFLAB: 
+                                       fprintf(flowdiagramfile,"Label: %d", ip->ip_lbl);
+                                       break;
+                                       
+                               case IP_PROLOG:
+                                       plg = (struct interpass_prolog *)ip;
+       
+                                       fprintf(flowdiagramfile,"%s %s",plg->ipp_name,type);
+                                       break;
+                       }
+                       
+                       fprintf(flowdiagramfile,"|");
+                       fprintf(flowdiagramfile,"|");
+                       
+                       if (ip==bbb->last)
+                               break;
+                       
+                       ip = DLIST_NEXT(ip, qelem);
+               }
+               fprintf(flowdiagramfile,"\"]\n");
+               
+               SLIST_FOREACH(cn, &bbb->child, chld) {
+                       char *color="black";
+                       struct interpass *pip=bbb->last;
+
+                       if (pip->type == IP_NODE && pip->ip_node->n_op == CBRANCH) {
+                               int label = (int)getlval(pip->ip_node->n_right);
+                               
+                               if (cn->bblock==p2e->labinfo.arr[label - p2e->ipp->ip_lblnum])
+                                       color="red";
+                       }
+                       
+                       fprintf(flowdiagramfile,"bb%p -> bb%p [color=%s]\n", bbb,cn->bblock,color);
+               }
+       }
+       
+       fprintf(flowdiagramfile,"}\n");
+       fclose(flowdiagramfile);
+}
+
+#endif
+
+/* walk all the programm */
+void WalkAll(struct p2env* p2e, void (*f) (NODE*, void*), void* arg, int type)
+{
+       struct interpass *ipole = &p2e->ipole;
+       struct interpass *ip ;
+       if (0 != type) {
+               DLIST_FOREACH(ip, ipole, qelem) {
+                       if (ip->type == IP_NODE && ip->ip_node->n_op == type)
+                               walkf(ip->ip_node, f, arg) ;
+               }
+       } else {
+               DLIST_FOREACH(ip, ipole, qelem) {
+                       if (ip->type == IP_NODE)
+                               walkf(ip->ip_node, f, arg) ;
+               }
+       }
+}
+#if 0
+static int is_goto_label(struct interpass*g, struct interpass* l)
+{
+       if (!g || !l)
+               return 0 ;
+       if (g->type != IP_NODE) return 0 ;
+       if (l->type != IP_DEFLAB) return 0 ;
+       if (g->ip_node->n_op != GOTO) return 0 ;
+       if (g->ip_node->n_left->n_lval != l->ip_lbl) return 0 ;
+       return 1 ;
+}
+#endif
+
+/*
+ * iterate over the basic blocks. 
+ * In case a block has only one successor and that one has only one pred, and the link is a goto:
+ * place the second one immediately behind the first one (in terms of nodes, means cut&resplice). 
+ * This should take care of a lot of jumps.
+ * one problem: Cannot move the first or last basic block (prolog/epilog). This is taken care of by
+ * moving block #1 to #2, not #2 to #1
+ * More complex (on the back cooker;) : first coalesc the inner loops (L1 cache), then go from inside out.
+ */
+
+static unsigned long count_blocks(struct p2env* p2e)
+{
+       struct basicblock* bb ;
+       unsigned long count = 0 ;
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               ++count ;
+       }
+       return count ;
+}
+
+struct block_map {
+       struct basicblock* block ;
+       unsigned long index ;
+       unsigned long thread ;
+} ;
+
+static unsigned long map_blocks(struct p2env* p2e, struct block_map* map, unsigned long count)
+{
+       struct basicblock* bb ;
+       unsigned long indx = 0 ;
+       int ignore = 2 ;
+       unsigned long thread ;
+       unsigned long changes ;
+
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               map[indx].block = bb ;
+               map[indx].index = indx ;
+
+               /* ignore the first 2 labels, maybe up to 3 BBs */
+               if (ignore) {
+                       if (bb->first->type == IP_DEFLAB) 
+                               --ignore;
+
+                       map[indx].thread = 1 ;  /* these are "fixed" */
+               } else
+                       map[indx].thread = 0 ;
+
+               indx++ ;
+       }
+
+       thread = 1 ;
+       do {
+               changes = 0 ;
+               
+               for (indx=0; indx < count; indx++) {
+                       /* find block without trace */
+                       if (map[indx].thread == 0) {
+                               /* do new thread */
+                               struct cfgnode *cn ;
+                               struct basicblock *block2 = 0;
+                               unsigned long i ;
+                               unsigned long added ;
+                               
+                               BDEBUG (("new thread %ld at block %ld\n", thread, indx)) ;
+
+                               bb = map[indx].block ;
+                               do {
+                                       added = 0 ;
+
+                                       for (i=0; i < count; i++) {
+                                               if (map[i].block == bb && map[i].thread == 0) {
+                                                       map[i].thread = thread ;
+
+                                                       BDEBUG(("adding block %ld to trace %ld\n", i, thread)) ;
+
+                                                       changes ++ ;
+                                                       added++ ;
+
+                                                       /* 
+                                                        * pick one from followers. For now (simple), pick the 
+                                                        * one who is directly following us. If none of that exists,
+                                                        * this code picks the last one.
+                                                        */
+
+                                                       SLIST_FOREACH(cn, &bb->child, chld) {
+                                                               block2=cn->bblock ;
+#if 1
+                                                               if (i+1 < count && map[i+1].block == block2)
+                                                                       break ; /* pick that one */
+#else
+                                                               if (block2) break ;
+#endif
+                                                       }
+
+                                                       if (block2)
+                                                               bb = block2 ;
+                                               }
+                                       }
+                               } while (added) ;
+                               thread++ ;
+                       }
+               }
+       } while (changes);
+
+       /* Last block is also a thread on it's own, and the highest one. */
+/*
+       thread++ ;
+       map[count-1].thread = thread ;
+*/
+       if (b2debug) {
+               printf("Threads\n");
+               for (indx=0; indx < count; indx++) {
+                       printf("Block #%ld (lbl %d) Thread %ld\n", indx, map[indx].block->first->ip_lbl, map[indx].thread);
+               }
+       }
+       return thread ;
+}
+
+
+void TraceSchedule(struct p2env* p2e)
+{
+       struct block_map* map ;
+       unsigned long block_count = count_blocks(p2e);
+       unsigned long i ;
+       struct interpass *front, *back ;
+
+       map = tmpalloc(block_count * sizeof(struct block_map));
+
+       (void)map_blocks(p2e, map, block_count);
+
+       back = map[0].block->last ;
+       for (i=1; i < block_count; i++) {
+               /* collect the trace */
+               unsigned long j ;
+               unsigned long thread = map[i].thread ;
+               if (thread) {
+                       BDEBUG(("Thread %ld\n", thread)) ;
+                       for (j=i; j < block_count; j++) {
+                               if (map[j].thread == thread) {
+                                       front = map[j].block->first ;
+
+                                       BDEBUG(("Trace %ld, old BB %ld, next BB %ld\t",
+                                               thread, i, j)) ;
+                                       BDEBUG(("Label %d\n", front->ip_lbl)) ;
+                                       DLIST_NEXT(back, qelem) = front ;
+                                       DLIST_PREV(front, qelem) = back ;
+                                       map[j].thread = 0 ;     /* done */
+                                       back = map[j].block->last ;
+                                       DLIST_NEXT(back, qelem) = 0 ;
+                               }
+                       }
+               }
+       }
+       DLIST_NEXT(back, qelem) = &(p2e->ipole) ;
+       DLIST_PREV(&p2e->ipole, qelem) = back ;
+}
+
+static void add_labels(struct p2env* p2e)
+{
+       struct interpass *ipole = &p2e->ipole ;
+       struct interpass *ip ;
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type == IP_NODE && ip->ip_node->n_op == CBRANCH) {
+                       struct interpass *n = DLIST_NEXT(ip, qelem);
+                       if (n && n->type != IP_DEFLAB) {
+                               struct interpass* lab;
+                               int newlabel=getlab2() ;
+
+                               BDEBUG(("add_label L%d\n", newlabel));
+
+                               lab = tmpalloc(sizeof(struct interpass));
+                               lab->type = IP_DEFLAB;
+                               /* Line number?? ip->lineno; */
+                               lab->ip_lbl = newlabel;
+                               DLIST_INSERT_AFTER(ip, lab, qelem);
+                       }
+               }
+       }
+}
+
+/* node map */
+#ifdef ENABLE_NEW
+struct node_map {
+       NODE* node ;            /* the node */
+       unsigned int node_num ; /* node is equal to that one */
+       unsigned int var_num ;  /* node computes this variable */
+} ;
+
+static unsigned long nodes_counter ;
+static void node_map_count_walker(NODE* n, void* x)
+{
+       nodes_counter ++ ;
+}
+
+static void do_cse(struct p2env* p2e)
+{
+       nodes_counter = 0 ;
+       WalkAll(p2e, node_map_count_walker, 0, 0) ;
+       BDEBUG(("Found %ld nodes\n", nodes_counter)) ;
+}
+#endif
+
+#define BITALLOC(ptr,all,sz) { \
+       int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
+#define VALIDREG(p)    (p->n_op == REG && TESTBIT(validregs, regno(p)))
+#define XCHECK(x) if (x < 0 || x >= xbits) printf("x out of range %d\n", x)
+#define RUP(x) (((x)+NUMBITS-1)/NUMBITS)
+#define SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
+#define SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
+#define SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
+#define SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
+       if (t[i] != f[i]) v = 1
+
+static int xxx, xbits;
+/*
+ * Set/clear long term liveness for regs and temps.
+ */
+static void
+unionize(NODE *p, struct basicblock *bb, int suboff)
+{
+       int o, ty;
+
+       if ((o = p->n_op) == TEMP || VALIDREG(p)) {
+               int b = regno(p);
+               if (o == TEMP)
+                       b = b - suboff + MAXREGS;
+XCHECK(b);
+               BITSET(bb->gen, b);
+       }
+       if (asgop(o)) {
+               if (p->n_left->n_op == TEMP || VALIDREG(p)) {
+                       int b = regno(p->n_left);
+                       if (p->n_left->n_op == TEMP)
+                               b = b - suboff + MAXREGS;
+XCHECK(b);
+                       BITCLEAR(bb->gen, b);
+                       BITSET(bb->killed, b);
+                       unionize(p->n_right, bb, suboff);
+                       return;
+               }
+       }
+       ty = optype(o);
+       if (ty != LTYPE)
+               unionize(p->n_left, bb, suboff);
+       if (ty == BITYPE)
+               unionize(p->n_right, bb, suboff);
+}
+
+/*
+ * Found an extended assembler node, so growel out gen/killed nodes.
+ */
+static void
+xasmionize(NODE *p, void *arg)
+{
+       struct basicblock *bb = arg;
+       int cw, b;
+
+       if (p->n_op == ICON && p->n_type == STRTY)
+               return; /* dummy end marker */
+
+       cw = xasmcode(p->n_name);
+       if (XASMVAL(cw) == 'n' || XASMVAL(cw) == 'm')
+               return; /* no flow analysis */
+       p = p->n_left;
+       if (XASMVAL(cw) == 'g' && p->n_op != TEMP && p->n_op != REG)
+               return; /* no flow analysis */
+
+       b = regno(p);
+#if 0
+       if (XASMVAL(cw) == 'r' && p->n_op == TEMP)
+               addnotspill(b);
+#endif
+#define MKTOFF(r)      ((r) - xxx)
+       if (XASMISOUT(cw)) {
+               if (p->n_op == TEMP) {
+                       BITCLEAR(bb->gen, MKTOFF(b));
+                       BITSET(bb->killed, MKTOFF(b));
+               } else if (p->n_op == REG) {
+                       BITCLEAR(bb->gen, b);
+                       BITSET(bb->killed, b);   
+               } else
+                       uerror("bad xasm node type %d", p->n_op);
+       }
+       if (XASMISINP(cw)) {
+               if (p->n_op == TEMP) {
+                       BITSET(bb->gen, MKTOFF(b));
+               } else if (p->n_op == REG) {
+                       BITSET(bb->gen, b);
+               } else if (optype(p->n_op) != LTYPE) {
+                       if (XASMVAL(cw) == 'r')
+                               uerror("couldn't find available register");
+                       else
+                               uerror("bad xasm node type2");
+               }
+       }
+}
+
+/*
+ * Do variable liveness analysis.  Only analyze the long-lived
+ * variables, and save the live-on-exit temporaries in a bit-field
+ * at the end of each basic block. This bit-field is later used
+ * when doing short-range liveness analysis in Build().
+ */
+void
+liveanal(struct p2env *p2e)
+{
+       struct basicblock *bb;
+       struct interpass *ip;
+       bittype *saved;
+       int mintemp, again;
+
+       xbits = p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum + MAXREGS;
+       mintemp = p2e->ipp->ip_tmpnum;
+
+       /* Just fetch space for the temporaries from heap */
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               BITALLOC(bb->gen,tmpalloc,xbits);
+               BITALLOC(bb->killed,tmpalloc,xbits);
+               BITALLOC(bb->in,tmpalloc,xbits);
+               BITALLOC(bb->out,tmpalloc,xbits);
+       }
+       BITALLOC(saved,tmpalloc,xbits);
+
+       xxx = mintemp;
+       /*
+        * generate the gen-killed sets for all basic blocks.
+        */
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+                       /* gen/killed is 'p', this node is 'n' */
+                       if (ip->type == IP_NODE) {
+                               if (ip->ip_node->n_op == XASM)
+                                       flist(ip->ip_node->n_left,
+                                           xasmionize, bb);
+                               else
+                                       unionize(ip->ip_node, bb, mintemp);
+                       }
+                       if (ip == bb->first)
+                               break;
+               }
+               memcpy(bb->in, bb->gen, BIT2BYTE(xbits));
+#ifdef PCC_DEBUG
+#define PRTRG(x) printf("%d ", x < MAXREGS ? x : x + p2e->ipp->ip_tmpnum-MAXREGS)
+               if (b2debug > 1) {
+                       int i;
+
+                       printf("basic block %d\ngen: ", bb->bbnum);
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(bb->gen, i))
+                                       PRTRG(i);
+                       printf("\nkilled: ");
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(bb->killed, i))
+                                       PRTRG(i);
+                       printf("\n");
+               }
+#endif
+       }
+       /* do liveness analysis on basic block level */
+       do {
+               struct cfgnode *cn;
+               int j;
+
+               again = 0;
+               /* XXX - loop should be in reversed execution-order */
+               DLIST_FOREACH_REVERSE(bb, &p2e->bblocks, bbelem) {
+                       SETCOPY(saved, bb->out, j, xbits);
+                       SLIST_FOREACH(cn, &bb->child, chld) {
+                               SETSET(bb->out, cn->bblock->in, j, xbits);
+                       }
+                       SETCMP(again, saved, bb->out, j, xbits);
+                       SETCOPY(saved, bb->in, j, xbits);
+                       SETCOPY(bb->in, bb->out, j, xbits);
+                       SETCLEAR(bb->in, bb->killed, j, xbits);
+                       SETSET(bb->in, bb->gen, j, xbits);
+                       SETCMP(again, saved, bb->in, j, xbits);
+               }
+       } while (again);
+
+#ifdef PCC_DEBUG
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               if (b2debug) {
+                       int i;
+
+                       printf("all basic block %d\nin: ", bb->bbnum);
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(bb->in, i))
+                                       PRTRG(i);
+                       printf("\nout: ");
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(bb->out, i))
+                                       PRTRG(i);
+                       printf("\n");
+               }
+       }
+#endif
+}
diff --git a/lang/pcc/pcc/mip/pass2.h b/lang/pcc/pcc/mip/pass2.h
new file mode 100644 (file)
index 0000000..dafa400
--- /dev/null
@@ -0,0 +1,545 @@
+/*     $Id: pass2.h,v 1.142 2015/08/13 11:56:03 ragge Exp $    */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+
+#ifndef MKEXT
+#include "external.h"
+#else
+typedef unsigned int bittype; /* XXX - for basicblock */
+#define        BIT2BYTE(a)     (((a) + 31) / 32)
+#endif
+#include "manifest.h"
+
+/* cookies, used as arguments to codgen */
+#define FOREFF 01              /* compute for effects only */
+#define INAREG 02              /* compute into a register */
+#define INBREG 04              /* compute into a register */
+#define INCREG 010             /* compute into a register */
+#define INDREG 020             /* compute into a register */
+#define        INREGS  (INAREG|INBREG|INCREG|INDREG)
+#define FORCC  040             /* compute for condition codes only */
+#define QUIET  0100            /* tell geninsn() to not complain if fail */
+#define INTEMP 010000          /* compute into a temporary location */
+#define FORREW 040000          /* search the table for a rewrite rule */
+#define INEREG 0x10000         /* compute into a register, > 16 bits */
+#define INFREG 0x20000         /* compute into a register, > 16 bits */
+#define INGREG 0x40000         /* compute into a register, > 16 bits */
+
+/*
+ * OP descriptors,
+ * the ASG operator may be used on some of these
+ */
+#define OPSIMP 010000          /* +, -, &, |, ^ */
+#define OPCOMM 010002          /* +, &, |, ^ */
+#define OPMUL  010004          /* *, / */
+#define OPDIV  010006          /* /, % */
+#define OPUNARY        010010          /* unary ops */
+#define OPLEAF 010012          /* leaves */
+#define OPANY  010014          /* any op... */
+#define OPLOG  010016          /* logical ops */
+#define OPFLOAT        010020          /* +, -, *, or / (for floats) */
+#define OPSHFT 010022          /* <<, >> */
+#define OPLTYPE        010024          /* leaf type nodes (e.g, NAME, ICON, etc.) */
+
+/* shapes */
+#define SANY   01              /* same as FOREFF */
+#define SAREG  02              /* same as INAREG */
+#define SBREG  04              /* same as INBREG */
+#define SCREG  010             /* same as INCREG */
+#define SDREG  020             /* same as INDREG */
+#define SCC    040             /* same as FORCC */
+#define SNAME  0100
+#define SCON   0200
+#define SFLD   0400
+#define SOREG  01000
+#define STARNM 02000
+#define STARREG        04000
+#define SWADD  040000
+#define SPECIAL        0100000
+#define SZERO  SPECIAL
+#define SONE   (SPECIAL|1)
+#define SMONE  (SPECIAL|2)
+#define SCCON  (SPECIAL|3)     /* -256 <= constant < 256 */
+#define SSCON  (SPECIAL|4)     /* -32768 <= constant < 32768 */
+#define SSOREG (SPECIAL|5)     /* non-indexed OREG */
+#define        MAXSPECIAL      (SPECIAL|5)
+#define SEREG  0x10000         /* same as INEREG */
+#define SFREG  0x20000         /* same as INFREG */
+#define SGREG  0x40000         /* same as INGREG */
+
+/* These are used in rstatus[] in conjunction with SxREG */
+#define        TEMPREG 01000
+#define        PERMREG 02000
+
+/* tshape() return values */
+#define        SRNOPE  0               /* Cannot match any shape */
+#define        SRDIR   1               /* Direct match */
+#define        SROREG  2               /* Can convert into OREG */
+#define        SRREG   3               /* Must put into REG */
+
+/* find*() return values */
+#define        FRETRY  -2
+#define        FFAIL   -1
+
+/* INTEMP is carefully not conflicting with shapes */
+
+/* types */
+#define TCHAR          01      /* char */
+#define TSHORT         02      /* short */
+#define TINT           04      /* int */
+#define TLONG          010     /* long */
+#define TFLOAT         020     /* float */
+#define TDOUBLE                040     /* double */
+#define TPOINT         0100    /* pointer to something */
+#define TUCHAR         0200    /* unsigned char */
+#define TUSHORT                0400    /* unsigned short */
+#define TUNSIGNED      01000   /* unsigned int */
+#define TULONG         02000   /* unsigned long */
+#define TPTRTO         04000   /* pointer to one of the above */
+#define TANY           010000  /* matches anything within reason */
+#define TSTRUCT                020000  /* structure or union */
+#define        TLONGLONG       040000  /* long long */
+#define        TULONGLONG      0100000 /* unsigned long long */
+#define        TLDOUBLE        0200000 /* long double; exceeds 16 bit */
+#define        TFTN            0400000 /* function pointer; exceeds 16 bit */
+
+/* reclamation cookies */
+#define RNULL          0       /* clobber result */
+#define RLEFT          01
+#define RRIGHT         02
+#define RESC1          04
+#define RESC2          010
+#define RESC3          020
+#define RDEST          040
+#define RESCC          04000
+#define RNOP           010000  /* DANGER: can cause loops.. */
+
+/* needs */
+#define NASL           0x0001  /* may share left register */
+#define NASR           0x0002  /* may share right register */
+#define NAREG          0x0004
+#define NACOUNT                0x000c
+#define NBSL           0x0010
+#define NBSR           0x0020
+#define NBREG          0x0040
+#define NBCOUNT                0x00c0
+#define        NCSL            0x0100
+#define        NCSR            0x0200
+#define        NCREG           0x0400
+#define        NCCOUNT         0x0c00
+#define NTEMP          0x1000
+#define NTMASK         0x3000
+#define NSPECIAL       0x4000  /* need special register treatment */
+#define REWRITE                0x8000
+#define        NDSL            0x00010000      /* Above 16 bit */
+#define        NDSR            0x00020000      /* Above 16 bit */
+#define        NDREG           0x00040000      /* Above 16 bit */
+#define        NDCOUNT         0x000c0000
+#define        NESL            0x00100000      /* Above 16 bit */
+#define        NESR            0x00200000      /* Above 16 bit */
+#define        NEREG           0x00400000      /* Above 16 bit */
+#define        NECOUNT         0x00c00000
+#define        NFSL            0x01000000      /* Above 16 bit */
+#define        NFSR            0x02000000      /* Above 16 bit */
+#define        NFREG           0x04000000      /* Above 16 bit */
+#define        NFCOUNT         0x0c000000
+#define        NGSL            0x10000000      /* Above 16 bit */
+#define        NGSR            0x20000000      /* Above 16 bit */
+#undef NGREG   /* XXX - linux exposes NGREG to public */
+#define        NGREG           0x40000000      /* Above 16 bit */
+#define        NGCOUNT         0xc0000000
+
+/* special treatment */
+#define        NLEFT           (0001)  /* left leg register (moveadd) */
+#define        NOLEFT          (0002)  /* avoid regs for left (addedge) */
+#define        NRIGHT          (0004)  /* right leg register */
+#define        NORIGHT         (0010)  /* avoid reg for right */
+#define        NEVER           (0020)  /* registers trashed (addalledges) */
+#define        NRES            (0040)  /* result register (moveadd) */
+#define        NMOVTO          (0100)  /* move between classes */
+
+
+#define MUSTDO         010000  /* force register requirements */
+#define NOPREF         020000  /* no preference for register assignment */
+
+#define        isreg(p)        (p->n_op == REG || p->n_op == TEMP)
+
+extern int fregs;
+
+/* code tables */
+extern struct optab {
+       int     op;
+       int     visit;
+       int     lshape;
+       int     ltype;
+       int     rshape;
+       int     rtype;
+       int     needs;
+       int     rewrite;
+       char    *cstring;
+} table[];
+
+/* Special needs for register allocations */
+struct rspecial {
+       int op, num;
+#if 0
+       int left;       /* left leg register */
+       int noleft;     /* avoid regs for left */
+       int right;      /* right leg register */
+       int noright;    /* avoid right leg register */
+       int *rmask;     /* array of destroyed registers */
+       int res;        /* Result ends up here */
+//     void (*rew)(struct optab *, NODE *);    /* special rewrite */
+#endif
+};
+
+struct p2env;
+#define        NRESC 4
+extern NODE resc[];
+extern int p2autooff, p2maxautooff;
+
+extern NODE
+       *talloc(void),
+       *eread(void),
+       *mklnode(int, CONSZ, int, TWORD),
+       *mkbinode(int, NODE *, NODE *, TWORD),
+       *mkunode(int, NODE *, int, TWORD),
+       *getlr(NODE *p, int);
+
+void eoftn(struct interpass_prolog *);
+void prologue(struct interpass_prolog *);
+void e2print(NODE *p, int down, int *a, int *b);
+void myoptim(struct interpass *);
+void cbgen(int op, int label);
+int match(NODE *p, int cookie);
+int acceptable(struct optab *);
+int special(NODE *, int);
+int setasg(NODE *, int);
+int setuni(NODE *, int);
+int sucomp(NODE *);
+int nsucomp(NODE *);
+int setorder(NODE *);
+int geninsn(NODE *, int cookie);
+void adrput(FILE *, NODE *);
+void comperr(char *str, ...);
+void genregs(NODE *p);
+void ngenregs(struct p2env *);
+NODE *store(NODE *);
+struct interpass *ipnode(NODE *);
+void deflab(int);
+void rmove(int, int, TWORD);
+int rspecial(struct optab *, int);
+struct rspecial *nspecial(struct optab *q);
+void printip(struct interpass *pole);
+int findops(NODE *p, int);
+int findasg(NODE *p, int);
+int finduni(NODE *p, int);
+int findumul(NODE *p, int);
+int findleaf(NODE *p, int);
+int relops(NODE *p);
+#ifdef FINDMOPS
+int findmops(NODE *p, int);
+int treecmp(NODE *p1, NODE *p2);
+#endif
+void offstar(NODE *p, int shape);
+int gclass(TWORD);
+void lastcall(NODE *);
+void myreader(struct interpass *pole);
+int oregok(NODE *p, int sharp);
+void myormake(NODE *);
+int *livecall(NODE *);
+void prtreg(NODE *);
+char *prcook(int);
+int myxasm(struct interpass *ip, NODE *p);
+int xasmcode(char *s);
+int freetemp(int k);
+NODE *storenode(TWORD t, int k);
+void storemod(NODE *, int k, int reg);
+int rewfld(NODE *p);
+void canon(NODE *);
+void mycanon(NODE *);
+void oreg2(NODE *p, void *);
+int shumul(NODE *p, int);
+NODE *deluseless(NODE *p);
+int getlab2(void);
+int tshape(NODE *, int);
+void conput(FILE *, NODE *);
+int shtemp(NODE *p);
+int ttype(TWORD t, int tword);
+void expand(NODE *, int, char *);
+void hopcode(int, int);
+void adrcon(CONSZ);
+void zzzcode(NODE *, int);
+void insput(NODE *);
+void upput(NODE *, int);
+int tlen(NODE *p);
+int setbin(NODE *);
+int notoff(TWORD, int, CONSZ, char *);
+int fldexpand(NODE *, int, char **);
+int flshape(NODE *p);
+int ncnt(int needs);
+void mainp2(void);
+
+extern char *rnames[];
+
+extern int classmask(int), tclassmask(int);
+extern void cmapinit(void);
+extern int aliasmap(int adjclass, int regnum);
+extern int regK[];
+#define        CLASSA  1
+#define        CLASSB  2
+#define        CLASSC  3
+#define        CLASSD  4
+#define        CLASSE  5
+#define        CLASSF  6
+#define        CLASSG  7
+
+/* used when parsing xasm codes */
+#define        XASMVAL(x)      ((x) & 0377)            /* get val from codeword */
+#define        XASMVAL1(x)     (((x) >> 16) & 0377)    /* get val from codeword */
+#define        XASMVAL2(x)     (((x) >> 24) & 0377)    /* get val from codeword */
+#define        XASMASG         0x100   /* = */
+#define        XASMCONSTR      0x200   /* & */
+#define        XASMINOUT       0x400   /* + */
+#define XASMALL                (XASMASG|XASMCONSTR|XASMINOUT)
+#define        XASMISINP(cw)   (((cw) & XASMASG) == 0)         /* input operand */
+#define        XASMISOUT(cw)   ((cw) & (XASMASG|XASMINOUT))    /* output operand */
+
+/* routines to handle double indirection */
+#ifdef R2REGS
+void makeor2(NODE *p, NODE *q, int, int);
+int base(NODE *);
+int offset(NODE *p, int);
+#endif
+
+extern int lineno;
+extern int ndebug;
+extern int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug;
+extern int r2debug, s2debug, t2debug, u2debug, x2debug;
+
+extern int dope[];     /* a vector containing operator information */
+extern char *opst[];   /* a vector containing names for ops */
+
+#ifdef PCC_DEBUG
+
+static inline int
+optype(int o)
+{
+       if (o >= MAXOP+1)
+               cerror("optype");
+       return (dope[o]&TYFLG);
+}
+
+static inline int
+asgop(int o)
+{
+       if (o >= MAXOP+1)
+               cerror("asgop");
+       return (dope[o]&ASGFLG);
+}
+
+static inline int
+logop(int o)
+{
+       if (o >= MAXOP+1)
+               cerror("logop");
+       return (dope[o]&LOGFLG);
+}
+
+static inline int
+callop(int o)
+{
+       if (o >= MAXOP+1)
+               cerror("callop");
+       return (dope[o]&CALLFLG);
+}
+
+#else
+
+#define optype(o)      (dope[o]&TYFLG)
+#define asgop(o)       (dope[o]&ASGFLG) 
+#define logop(o)       (dope[o]&LOGFLG)
+#define callop(o)      (dope[o]&CALLFLG)
+
+#endif
+
+       /* macros for doing double indexing */
+#define R2PACK(x,y,z)  (0200*((x)+1)+y+040000*z)
+#define R2UPK1(x)      ((((x)>>7)-1)&0177)
+#define R2UPK2(x)      ((x)&0177)
+#define R2UPK3(x)      (x>>14)
+#define R2TEST(x)      ((x)>=0200)
+
+/*
+ * Layout of findops() return value:
+ *      bit 0 whether left shall go into a register.
+ *      bit 1 whether right shall go into a register.
+ *      bit 2 entry is only used for side effects.
+ *      bit 3 if condition codes are used.
+ *
+ * These values should be synced with FOREFF/FORCC.
+ */
+#define ISMOPS         001
+#define RREG           002
+#define        RVEFF           004
+#define        RVCC            010
+#define DORIGHT                020
+#define        SCLASS(v,x)     ((v) |= ((x) << 5))
+#define        TCLASS(x)       (((x) >> 5) & 7)
+#define        TBSH            8
+#define TBLIDX(idx)    ((idx) >> TBSH)
+#define MKIDX(tbl,mod) (((tbl) << TBSH) | (mod))
+
+#ifndef        BREGS
+#define        BREGS   0
+#define        TBREGS  0
+#endif
+#define        REGBIT(x) (1 << (x))
+#ifndef PERMTYPE
+#define        PERMTYPE(a)     (INT)
+#endif
+
+/* Flags for the dataflow code */
+/* do the live/dead analysis */
+#define DO_LIVEDEAD  0x01
+/* compute avail expressions */
+#define DO_AVAILEXPR 0x02
+/* Do an update on the live/dead. One variable only */
+#define DO_UPDATELD  0x04
+/* Do an update on available expressions, one variable has changed */
+#define DO_UPDATEEX  0x08
+
+void emit(struct interpass *);
+void optimize(struct p2env *);
+
+struct basicblock {
+       DLIST_ENTRY(basicblock) bbelem;
+       SLIST_HEAD(, cfgnode) parents;  /* CFG - parents to this node */
+       SLIST_HEAD(, cfgnode) child;    /* Children, usually max 2 of them */
+       int bbnum;      /* this basic block number */
+       unsigned int dfnum; /* DFS-number */
+       unsigned int dfparent; /* Parent in DFS */
+       unsigned int semi;
+       unsigned int ancestor;
+       unsigned int idom;
+       unsigned int samedom;
+       bittype *bucket;
+       bittype *df;
+       bittype *dfchildren;
+       bittype *Aorig;
+       bittype *Aphi;
+       SLIST_HEAD(, phiinfo) phi;
+
+       bittype *gen, *killed, *in, *out;       /* Liveness analysis */
+
+       struct interpass *first; /* first element of basic block */
+       struct interpass *last;  /* last element of basic block */
+};
+
+struct labelinfo {
+       struct basicblock **arr;
+       int size;
+       unsigned int low;
+};
+
+struct bblockinfo {
+       int size;
+       struct basicblock **arr;
+};
+
+struct varinfo {
+       struct pvarinfo **arr;
+       SLIST_HEAD(, varstack) *stack;
+       int size;
+       int low;
+};
+
+struct pvarinfo {
+       struct pvarinfo *next;
+       struct basicblock *bb;
+       TWORD n_type;
+};
+
+struct varstack {
+       SLIST_ENTRY(varstack) varstackelem;
+       int tmpregno;
+};
+
+
+struct cfgnode {
+       SLIST_ENTRY(cfgnode) cfgelem;
+       SLIST_ENTRY(cfgnode) chld;
+       struct basicblock *bblock;
+};
+
+struct phiinfo {
+       SLIST_ENTRY(phiinfo) phielem;
+       int tmpregno;
+       int newtmpregno;
+       TWORD n_type;
+       int size;
+       int *intmpregno;
+};
+
+/*
+ * Description of the pass2 environment.
+ * There will be only one of these structs.  It is used to keep
+ * all state descriptions during the compilation of a function
+ * in one place.
+ */
+struct p2env {
+       struct interpass ipole;                 /* all statements */
+       struct interpass_prolog *ipp, *epp;     /* quick references */
+       struct bblockinfo bbinfo;
+       struct labelinfo labinfo;
+       struct basicblock bblocks;
+       int nbblocks;
+};
+
+extern struct p2env p2env;
+
+/*
+ * C compiler second pass extra defines.
+ */
+#define PHI (MAXOP + 1)                /* Used in SSA trees */
+
+enum {
+       ATTR_P2_FIRST = ATTR_MI_MAX + 1,
+       ATTR_P2STRUCT,
+#ifdef ATTR_P2_TARGET
+       ATTR_P2_TARGET,
+#endif
+       ATTR_P2_MAX
+};
diff --git a/lang/pcc/pcc/mip/reader.c b/lang/pcc/pcc/mip/reader.c
new file mode 100644 (file)
index 0000000..b710f74
--- /dev/null
@@ -0,0 +1,1915 @@
+/*     $Id: reader.c,v 1.299 2015/11/17 19:19:40 ragge Exp $   */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *     This product includes software developed or owned by Caldera
+ *     International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Everything is entered via pass2_compile().  No functions are 
+ * allowed to recurse back into pass2_compile().
+ */
+
+# include "pass2.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+/*     some storage declarations */
+int nrecur;
+int thisline;
+int fregs;
+int p2autooff, p2maxautooff;
+
+NODE *nodepole;
+struct interpass prepole;
+
+void saveip(struct interpass *ip);
+void deltemp(NODE *p, void *);
+static void cvtemps(struct interpass *ipole, int op, int off);
+static void fixxasm(struct p2env *);
+
+static void gencode(NODE *p, int cookie);
+static void genxasm(NODE *p);
+static void afree(void);
+
+struct p2env p2env;
+
+int crslab2 = 11; 
+/*
+ * Return a number for internal labels.
+ */
+int
+getlab2(void)
+{
+        crslab2++;
+       if (crslab2 < p2env.ipp->ip_lblnum)
+               comperr("getlab2 %d outside boundaries %d-%d",
+                   crslab2, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+       if (crslab2 >= p2env.epp->ip_lblnum)
+               p2env.epp->ip_lblnum = crslab2+1;
+        return crslab2++;
+}
+
+
+#ifdef PCC_DEBUG
+static int *lbldef, *lbluse;
+static void
+cktree(NODE *p, void *arg)
+{
+       int i;
+
+       if (p->n_op > MAXOP)
+               cerror("%p) op %d slipped through", p, p->n_op);
+#ifndef FIELDOPS
+       if (p->n_op == FLD)
+               cerror("%p) FLD slipped through", p);
+#endif
+       if (BTYPE(p->n_type) > MAXTYPES)
+               cerror("%p) type %x slipped through", p, p->n_type);
+       if (p->n_op == CBRANCH) {
+                if (!logop(p->n_left->n_op))
+                       cerror("%p) not logop branch", p);
+               i = (int)getlval(p->n_right);
+               if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
+                       cerror("%p) label %d outside boundaries %d-%d",
+                           p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+               lbluse[i-p2env.ipp->ip_lblnum] = 1;
+       }
+       if ((dope[p->n_op] & ASGOPFLG) && p->n_op != RETURN)
+               cerror("%p) asgop %d slipped through", p, p->n_op);
+       if (p->n_op == TEMP &&
+           (regno(p) < p2env.ipp->ip_tmpnum || regno(p) >= p2env.epp->ip_tmpnum))
+               cerror("%p) temporary %d outside boundaries %d-%d",
+                   p, regno(p), p2env.ipp->ip_tmpnum, p2env.epp->ip_tmpnum);
+       if (p->n_op == GOTO && p->n_left->n_op == ICON) {
+               i = (int)getlval(p->n_left);
+               if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
+                       cerror("%p) label %d outside boundaries %d-%d",
+                           p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+               lbluse[i-p2env.ipp->ip_lblnum] = 1;
+       }
+}
+
+/*
+ * Check that the trees are in a suitable state for pass2.
+ */
+static void
+sanitychecks(struct p2env *p2e)
+{
+       struct interpass *ip;
+       int i, sz;
+
+       sz = sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum);
+       lbldef = xcalloc(sz, 1);
+       lbluse = xcalloc(sz, 1);
+
+       DLIST_FOREACH(ip, &p2env.ipole, qelem) {
+               if (ip->type == IP_DEFLAB) {
+                       i = ip->ip_lbl;
+                       if (i < p2e->ipp->ip_lblnum || i >= p2e->epp->ip_lblnum)
+                               cerror("label %d outside boundaries %d-%d",
+                                   i, p2e->ipp->ip_lblnum, p2e->epp->ip_lblnum);
+                       lbldef[i-p2e->ipp->ip_lblnum] = 1;
+               }
+               if (ip->type == IP_NODE)
+                       walkf(ip->ip_node, cktree, 0);
+       }
+       for (i = 0; i < (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum); i++)
+               if (lbluse[i] != 0 && lbldef[i] == 0)
+                       cerror("internal label %d not defined",
+                           i + p2e->ipp->ip_lblnum);
+
+       free(lbldef);
+       free(lbluse);
+}
+#endif
+
+/*
+ * Look if a temporary comes from a on-stack argument, in that case
+ * use the already existing stack position instead of moving it to
+ * a new place, and remove the move-to-temp statement.
+ */
+static int
+stkarg(int tnr, int (*soff)[2])
+{
+       struct p2env *p2e = &p2env;
+       struct interpass *ip;
+       NODE *p;
+
+       ip = DLIST_NEXT((struct interpass *)p2e->ipp, qelem);
+       while (ip->type != IP_DEFLAB) /* search for first DEFLAB */
+               ip = DLIST_NEXT(ip, qelem);
+
+       ip = DLIST_NEXT(ip, qelem); /* first NODE */
+
+       for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
+               if (ip->type != IP_NODE)
+                       continue;
+
+               p = ip->ip_node;
+               if (p->n_op == XASM)
+                       continue; /* XXX - hack for x86 PIC */
+#ifdef notdef
+               if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+                       comperr("temparg");
+#endif
+               if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+                       continue; /* unknown tree */
+
+               if (p->n_right->n_op != OREG && p->n_right->n_op != UMUL)
+                       continue; /* arg in register */
+               if (tnr != regno(p->n_left))
+                       continue; /* wrong assign */
+               p = p->n_right;
+               if (p->n_op == UMUL &&
+                   p->n_left->n_op == PLUS &&
+                   p->n_left->n_left->n_op == REG &&
+                   p->n_left->n_right->n_op == ICON) {
+                       soff[0][0] = regno(p->n_left->n_left);
+                       soff[0][1] = (int)getlval(p->n_left->n_right);
+               } else if (p->n_op == OREG) {
+                       soff[0][0] = regno(p);
+                       soff[0][1] = (int)getlval(p);
+               } else
+                       comperr("stkarg: bad arg");
+               tfree(ip->ip_node);
+               DLIST_REMOVE(ip, qelem);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * See if an ADDROF is somewhere inside the expression tree.
+ * If so, fill in the offset table.
+ */
+static void
+findaof(NODE *p, void *arg)
+{
+       int (*aof)[2] = arg;
+       int tnr;
+
+       if (p->n_op != ADDROF || p->n_left->n_op != TEMP)
+               return;
+       tnr = regno(p->n_left);
+       if (aof[tnr][0])
+               return; /* already gotten stack address */
+       if (stkarg(tnr, &aof[tnr]))
+               return; /* argument was on stack */
+       aof[tnr][0] = FPREG;
+       aof[tnr][1] = freetemp(szty(p->n_left->n_type));
+}
+
+/*
+ * Check if a node has side effects.
+ */
+static int
+isuseless(NODE *n)
+{
+       switch (n->n_op) {
+       case XASM:
+       case FUNARG:
+       case UCALL:
+       case UFORTCALL:
+       case FORCE:
+       case ASSIGN:
+       case CALL:
+       case FORTCALL:
+       case CBRANCH:
+       case RETURN:
+       case GOTO:
+       case STCALL:
+       case USTCALL:
+       case STASG:
+       case STARG:
+               return 0;
+       default:
+               return 1;
+       }
+}
+
+/*
+ * Delete statements with no meaning (like a+b; or 513.4;)
+ */
+NODE *
+deluseless(NODE *p)
+{
+       struct interpass *ip;
+       NODE *l, *r;
+
+       if (optype(p->n_op) == LTYPE) {
+               nfree(p);
+               return NULL;
+       }
+       if (isuseless(p) == 0)
+               return p;
+
+       if (optype(p->n_op) == UTYPE) {
+               l = p->n_left;
+               nfree(p);
+               return deluseless(l);
+       }
+
+       /* Be sure that both leaves may be valid */
+       l = deluseless(p->n_left);
+       r = deluseless(p->n_right);
+       nfree(p);
+       if (l && r) {
+               ip = ipnode(l);
+               DLIST_INSERT_AFTER(&prepole, ip, qelem);
+               return r;
+       } else if (l)
+               return l;
+       else if (r)
+               return r;
+       return NULL;
+}
+
+#ifdef PASS2
+
+#define        SKIPWS(p) while (*p == ' ') p++
+#define        SZIBUF  256
+static int inpline;
+static char inpbuf[SZIBUF];
+static char *
+rdline(void)
+{
+       int l;
+
+       if (fgets(inpbuf, sizeof(inpbuf), stdin) == NULL)
+               return NULL;
+       inpline++;
+       l = strlen(inpbuf);
+       if (inpbuf[0] < 33 || inpbuf[1] != ' ' || inpbuf[l-1] != '\n')
+               comperr("sync error in-line %d string '%s'", inpline, inpbuf);
+       inpbuf[l-1] = 0;
+       return inpbuf;
+}
+
+/*
+ * Read an int and traverse over it. count up s.
+ */
+static int
+rdint(char **s)
+{
+       char *p = *s;
+       int rv;
+
+       SKIPWS(p);
+       rv = atoi(p);
+       if (*p == '-' || *p == '+') p++;
+       while (*p >= '0' && *p <= '9') p++;
+       *s = p;
+       return rv;
+}
+
+static struct attr *
+rdattr(char **p)
+{
+       struct attr *ap, *app = NULL;
+       int i, a, sz;
+
+       (*p)++; /* skip + */
+onemore:
+       a = rdint(p);
+       sz = rdint(p);
+       ap = attr_new(a, sz);
+       for (i = 0; i < sz; i++)
+               ap->iarg(i) = rdint(p);
+       ap->next = app;
+       app = ap;
+       SKIPWS((*p));
+       if (**p != 0)
+               goto onemore;
+
+       return app;
+}
+
+/*
+ * Read in an indentifier and save on tmp heap.  Return saved string.
+ */
+static char *
+rdstr(char **p)
+{
+       char *t, *s = *p;
+       int sz;
+
+       SKIPWS(s);
+       *p = s;
+       for (sz = 0; *s && *s != ' '; s++, sz++)
+               ;
+       t = tmpalloc(sz+1);
+       memcpy(t, *p, sz);
+       t[sz] = 0;
+       *p = s;
+       return t;
+}
+
+/*
+ * Read and check node structs from pass1.
+ */
+static NODE *
+rdnode(char *s)
+{
+       NODE *p = talloc();
+       int ty;
+
+       if (s[0] != '"')
+               comperr("rdnode sync error");
+       s++; s++;
+       p->n_regw = NULL;
+       p->n_ap = NULL;
+       p->n_su = p->n_lval = p->n_rval = 0;
+       p->n_op = rdint(&s);
+       p->n_type = rdint(&s);
+       p->n_qual = rdint(&s);
+       p->n_name = "";
+       SKIPWS(s);
+       ty = optype(p->n_op);
+       if (p->n_op == XASM) {
+               int i = strlen(s);
+               p->n_name = tmpalloc(i+1);
+               memcpy(p->n_name, s, i);
+               p->n_name[i] = 0;
+               s += i;
+       }
+       if (ty == UTYPE) {
+               p->n_rval = rdint(&s);
+       } else if (ty == LTYPE) {
+               p->n_lval = strtoll(s, &s, 10);
+               if (p->n_op == NAME || p->n_op == ICON) {
+                       SKIPWS(s);
+                       if (*s && *s != '+')
+                               p->n_name = rdstr(&s);
+               } else
+                       p->n_rval = rdint(&s);
+       }
+       SKIPWS(s);
+       if (p->n_op == XARG) {
+               int i = strlen(s);
+               p->n_name = tmpalloc(i+1);
+               memcpy(p->n_name, s, i);
+               p->n_name[i] = 0;
+               s += i;
+       }
+       if (*s == '+')
+               p->n_ap = rdattr(&s);
+       SKIPWS(s);
+       if (*s)
+               comperr("in-line %d failed read, buf '%s'", inpline, inpbuf);
+       if (ty != LTYPE)
+               p->n_left = rdnode(rdline());
+       if (ty == BITYPE)
+               p->n_right = rdnode(rdline());
+       return p;
+}
+
+/*
+ * Read everything from pass1.
+ */
+void
+mainp2()
+{
+       static int foo[] = { 0 };
+       struct interpass_prolog *ipp;
+       struct interpass *ip;
+       char nam[SZIBUF], *p, *b;
+       extern char *ftitle;
+
+       while ((p = rdline()) != NULL) {
+               b = p++;
+               p++;
+
+               switch (*b) {
+               case '*': /* pass thru line */
+                       printf("%s\n", p);
+                       break;
+               case '&': /* current filename */
+                       free(ftitle);
+                       ftitle = xstrdup(p);
+                       break;
+               case '#':
+                       lineno = atoi(p);
+                       break;
+               case '"':
+                       ip = malloc(sizeof(struct interpass));
+                       ip->type = IP_NODE;
+                       ip->ip_node = rdnode(b);
+                       pass2_compile(ip);
+                       break;
+               case '^':
+                       ip = malloc(sizeof(struct interpass));
+                       ip->type = IP_DEFLAB;
+                       ip->ip_lbl = atoi(p);
+                       pass2_compile(ip);
+                       break;
+               case '!': /* prolog */
+                       ipp = malloc(sizeof(struct interpass_prolog));
+                       ip = (void *)ipp;
+                       ip->type = IP_PROLOG;
+                       sscanf(p, "%d %d %d %d %d %s", &ipp->ipp_type,
+                           &ipp->ipp_vis, &ip->ip_lbl, &ipp->ip_tmpnum,
+                           &ipp->ip_lblnum, nam);
+                       ipp->ipp_name = xstrdup(nam);
+                       memset(ipp->ipp_regs, -1, sizeof(ipp->ipp_regs));
+                       ipp->ipp_autos = -1;
+                       ipp->ip_labels = foo;
+#ifdef TARGET_IPP_MEMBERS
+                       if (*(p = rdline()) != '(')
+                               comperr("target member error");
+                       p += 2;
+                       target_members_read_prolog(ipp);
+                       SKIPWS(p);
+                       if (*p)
+                               comperr("bad prolog '%s' '%s'", p, inpbuf);
+#endif
+                       pass2_compile((struct interpass *)ipp);
+                       break;
+
+               case '%': /* epilog */
+                       ipp = malloc(sizeof(struct interpass_prolog));
+                       ip = (void *)ipp;
+                       ip->type = IP_EPILOG;
+                       ipp->ipp_autos = rdint(&p);
+                       ip->ip_lbl = rdint(&p);
+                       ipp->ip_tmpnum = rdint(&p);
+                       ipp->ip_lblnum = rdint(&p);
+                       ipp->ipp_name = rdstr(&p);
+                       memset(ipp->ipp_regs, 0, sizeof(ipp->ipp_regs));
+                       SKIPWS(p);
+                       if (*p == '+') {
+                               int num, i;
+                               p++;
+                               num = rdint(&p) + 1;
+                               ipp->ip_labels = tmpalloc(sizeof(int)*num);
+                               for (i = 0; i < num; i++)
+                                       ipp->ip_labels[i] = rdint(&p);
+                               ipp->ip_labels[num] = 0;
+                       } else
+                               ipp->ip_labels = foo;
+                       SKIPWS(p);
+                       if (*p)
+                               comperr("bad epilog '%s' '%s'", p, inpbuf);
+#ifdef TARGET_IPP_MEMBERS
+                       if (*(p = rdline()) != ')')
+                               comperr("target epi member error");
+                       p += 2;
+                       target_members_read_epilog(ipp);
+                       SKIPWS(p);
+                       if (*p)
+                               comperr("bad epilog2 '%s' '%s'", p, inpbuf);
+#endif
+                       pass2_compile((struct interpass *)ipp);
+                       break;
+
+               default:
+                       comperr("bad string %s", b);
+               }
+       }
+}
+
+
+#endif
+
+/*
+ * Receives interpass structs from pass1.
+ */
+void
+pass2_compile(struct interpass *ip)
+{
+       void deljumps(struct p2env *);
+       struct p2env *p2e = &p2env;
+       int (*addrp)[2];
+
+       if (ip->type == IP_PROLOG) {
+               memset(p2e, 0, sizeof(struct p2env));
+               p2e->ipp = (struct interpass_prolog *)ip;
+               if (crslab2 < p2e->ipp->ip_lblnum)
+                       crslab2 = p2e->ipp->ip_lblnum;
+               DLIST_INIT(&p2e->ipole, qelem);
+       }
+       DLIST_INSERT_BEFORE(&p2e->ipole, ip, qelem);
+       if (ip->type != IP_EPILOG)
+               return;
+
+#ifdef PCC_DEBUG
+       if (e2debug) {
+               printf("Entering pass2\n");
+               printip(&p2e->ipole);
+       }
+#endif
+
+       afree();
+       p2e->epp = (struct interpass_prolog *)DLIST_PREV(&p2e->ipole, qelem);
+       p2maxautooff = p2autooff = p2e->epp->ipp_autos;
+
+#ifdef PCC_DEBUG
+       sanitychecks(p2e);
+#endif
+       myreader(&p2e->ipole); /* local massage of input */
+
+       /*
+        * Do initial modification of the trees.  Two loops;
+        * - first, search for ADDROF of TEMPs, these must be
+        *   converterd to OREGs on stack.
+        * - second, do the actual conversions, in case of not xtemps
+        *   convert all temporaries to stack references.
+        */
+
+       if (p2e->epp->ip_tmpnum != p2e->ipp->ip_tmpnum) {
+               addrp = xcalloc(sizeof(*addrp),
+                   (p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum));
+               addrp -= p2e->ipp->ip_tmpnum;
+       } else
+               addrp = NULL;
+       if (xtemps) {
+               DLIST_FOREACH(ip, &p2e->ipole, qelem) {
+                       if (ip->type == IP_NODE)
+                               walkf(ip->ip_node, findaof, addrp);
+               }
+       }
+       DLIST_FOREACH(ip, &p2e->ipole, qelem)
+               if (ip->type == IP_NODE)
+                       walkf(ip->ip_node, deltemp, addrp);
+       if (addrp)
+               free(addrp + p2e->ipp->ip_tmpnum);
+
+#ifdef PCC_DEBUG
+       if (e2debug) {
+               printf("Efter ADDROF/TEMP\n");
+               printip(&p2e->ipole);
+       }
+#endif
+
+       DLIST_INIT(&prepole, qelem);
+       DLIST_FOREACH(ip, &p2e->ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               canon(ip->ip_node);
+               if ((ip->ip_node = deluseless(ip->ip_node)) == NULL) {
+                       DLIST_REMOVE(ip, qelem);
+               } else while (!DLIST_ISEMPTY(&prepole, qelem)) {
+                       struct interpass *tipp;
+
+                       tipp = DLIST_NEXT(&prepole, qelem);
+                       DLIST_REMOVE(tipp, qelem);
+                       DLIST_INSERT_BEFORE(ip, tipp, qelem);
+               }
+       }
+
+       fixxasm(p2e); /* setup for extended asm */
+
+       optimize(p2e);
+       ngenregs(p2e);
+
+       if (xtemps && xdeljumps)
+               deljumps(p2e);
+
+       DLIST_FOREACH(ip, &p2e->ipole, qelem)
+               emit(ip);
+}
+
+void
+emit(struct interpass *ip)
+{
+       NODE *p, *r;
+       struct optab *op;
+       int o;
+
+       switch (ip->type) {
+       case IP_NODE:
+               p = ip->ip_node;
+
+               nodepole = p;
+               canon(p); /* may convert stuff after genregs */
+#ifdef PCC_DEBUG
+               if (c2debug > 1) {
+                       printf("emit IP_NODE:\n");
+                       fwalk(p, e2print, 0);
+               }
+#endif
+               switch (p->n_op) {
+               case CBRANCH:
+                       /* Only emit branch insn if RESCC */
+                       /* careful when an OPLOG has been elided */
+                       if (p->n_left->n_su == 0 && p->n_left->n_left != NULL) {
+                               op = &table[TBLIDX(p->n_left->n_left->n_su)];
+                               r = p->n_left;
+                       } else {
+                               op = &table[TBLIDX(p->n_left->n_su)];
+                               r = p;
+                       }
+                       if (op->rewrite & RESCC) {
+                               o = p->n_left->n_op;
+                               gencode(r, FORCC);
+                               cbgen(o, getlval(p->n_right));
+                       } else {
+                               gencode(r, FORCC);
+                       }
+                       break;
+               case FORCE:
+                       gencode(p->n_left, INREGS);
+                       break;
+               case XASM:
+                       genxasm(p);
+                       break;
+               default:
+                       if (p->n_op != REG || p->n_type != VOID) /* XXX */
+                               gencode(p, FOREFF); /* Emit instructions */
+               }
+
+               tfree(p);
+               break;
+       case IP_PROLOG:
+               prologue((struct interpass_prolog *)ip);
+               break;
+       case IP_EPILOG:
+               eoftn((struct interpass_prolog *)ip);
+               p2maxautooff = p2autooff = AUTOINIT/SZCHAR;
+               break;
+       case IP_DEFLAB:
+               deflab(ip->ip_lbl);
+               break;
+       case IP_ASM:
+               printf("%s", ip->ip_asm);
+               break;
+       default:
+               cerror("emit %d", ip->type);
+       }
+}
+
+#ifdef PCC_DEBUG
+char *cnames[] = {
+       "SANY",
+       "SAREG",
+       "SBREG",
+       "SCREG",
+       "SDREG",
+       "SCC",
+       "SNAME",
+       "SCON",
+       "SFLD",
+       "SOREG",
+       "STARNM",
+       "STARREG",
+       "INTEMP",
+       "FORARG",
+       "SWADD",
+       0,
+};
+
+/*
+ * print a nice-looking description of cookie
+ */
+char *
+prcook(int cookie)
+{
+       static char buf[50];
+       int i, flag;
+
+       if (cookie & SPECIAL) {
+               switch (cookie) {
+               case SZERO:
+                       return "SZERO";
+               case SONE:
+                       return "SONE";
+               case SMONE:
+                       return "SMONE";
+               default:
+                       snprintf(buf, sizeof(buf), "SPECIAL+%d", cookie & ~SPECIAL);
+                       return buf;
+               }
+       }
+
+       flag = 0;
+       buf[0] = 0;
+       for (i = 0; cnames[i]; ++i) {
+               if (cookie & (1<<i)) {
+                       if (flag)
+                               strlcat(buf, "|", sizeof(buf));
+                       ++flag;
+                       strlcat(buf, cnames[i], sizeof(buf));
+               }
+       }
+       return buf;
+}
+#endif
+
+int
+geninsn(NODE *p, int cookie)
+{
+       NODE *p1, *p2;
+       int q, o, rv = 0;
+
+#ifdef PCC_DEBUG
+       if (o2debug) {
+               printf("geninsn(%p, %s)\n", p, prcook(cookie));
+               fwalk(p, e2print, 0);
+       }
+#endif
+
+       q = cookie & QUIET;
+       cookie &= ~QUIET; /* XXX - should not be necessary */
+
+again: switch (o = p->n_op) {
+       case EQ:
+       case NE:
+       case LE:
+       case LT:
+       case GE:
+       case GT:
+       case ULE:
+       case ULT:
+       case UGE:
+       case UGT:
+               p1 = p->n_left;
+               p2 = p->n_right;
+               if (p2->n_op == ICON && getlval(p2) == 0 && *p2->n_name == 0 &&
+                   (dope[p1->n_op] & (FLOFLG|DIVFLG|SIMPFLG|SHFFLG))) {
+#ifdef mach_pdp11 /* XXX all targets? */
+                       if ((rv = geninsn(p1, FORCC|QUIET)) != FFAIL)
+                               break;
+#else
+                       if (findops(p1, FORCC) > 0)
+                               break;
+#endif
+               }
+               rv = relops(p);
+               break;
+
+       case PLUS:
+       case MINUS:
+       case MUL:
+       case DIV:
+       case MOD:
+       case AND:
+       case OR:
+       case ER:
+       case LS:
+       case RS:
+               rv = findops(p, cookie);
+               break;
+
+       case ASSIGN:
+#ifdef FINDMOPS
+               if ((rv = findmops(p, cookie)) != FFAIL)
+                       break;
+               /* FALLTHROUGH */
+#endif
+       case STASG:
+               rv = findasg(p, cookie);
+               break;
+
+       case UMUL: /* May turn into an OREG */
+               rv = findumul(p, cookie);
+               break;
+
+       case REG:
+       case TEMP:
+       case NAME:
+       case ICON:
+       case FCON:
+       case OREG:
+               rv = findleaf(p, cookie);
+               break;
+
+       case STCALL:
+       case CALL:
+               /* CALL arguments are handled special */
+               for (p1 = p->n_right; p1->n_op == CM; p1 = p1->n_left)
+                       (void)geninsn(p1->n_right, FOREFF);
+               (void)geninsn(p1, FOREFF);
+               /* FALLTHROUGH */
+       case FLD:
+       case COMPL:
+       case UMINUS:
+       case PCONV:
+       case SCONV:
+/*     case INIT: */
+       case GOTO:
+       case FUNARG:
+       case STARG:
+       case UCALL:
+       case USTCALL:
+       case ADDROF:
+               rv = finduni(p, cookie);
+               break;
+
+       case CBRANCH:
+               p1 = p->n_left;
+               p2 = p->n_right;
+               p1->n_label = (int)getlval(p2);
+               (void)geninsn(p1, FORCC);
+               p->n_su = 0;
+               break;
+
+       case FORCE: /* XXX needed? */
+               (void)geninsn(p->n_left, INREGS);
+               p->n_su = 0; /* su calculations traverse left */
+               break;
+
+       case XASM:
+               for (p1 = p->n_left; p1->n_op == CM; p1 = p1->n_left)
+                       (void)geninsn(p1->n_right, FOREFF);
+               (void)geninsn(p1, FOREFF);
+               break;  /* all stuff already done? */
+
+       case XARG:
+               /* generate code for correct class here */
+               break;
+
+       default:
+               comperr("geninsn: bad op %s, node %p", opst[o], p);
+       }
+       if (rv == FFAIL && !q)
+               comperr("Cannot generate code, node %p op %s", p,opst[p->n_op]);
+       if (rv == FRETRY)
+               goto again;
+#ifdef PCC_DEBUG
+       if (o2debug) {
+               printf("geninsn(%p, %s) rv %d\n", p, prcook(cookie), rv);
+               fwalk(p, e2print, 0);
+       }
+#endif
+       return rv;
+}
+
+#ifdef PCC_DEBUG
+#define        CDEBUG(x) if (c2debug) printf x
+#else
+#define        CDEBUG(x)
+#endif
+
+/*
+ * Do a register-register move if necessary.
+ * Called if a RLEFT or RRIGHT is found.
+ */
+static void
+ckmove(NODE *p, NODE *q)
+{
+       struct optab *t = &table[TBLIDX(p->n_su)];
+       int reg;
+
+       if (q->n_op != REG || p->n_reg == -1)
+               return; /* no register */
+
+       /* do we have a need for special reg? */
+       if ((t->needs & NSPECIAL) &&
+           (reg = rspecial(t, p->n_left == q ? NLEFT : NRIGHT)) >= 0)
+               ;
+       else
+               reg = DECRA(p->n_reg, 0);
+
+       if (reg < 0 || reg == DECRA(q->n_reg, 0))
+               return; /* no move necessary */
+
+       CDEBUG(("rmove: node %p, %s -> %s\n", p, rnames[DECRA(q->n_reg, 0)],
+           rnames[reg]));
+       rmove(DECRA(q->n_reg, 0), reg, p->n_type);
+       q->n_reg = q->n_rval = reg;
+}
+
+/*
+ * Rewrite node to register after instruction emit.
+ */
+static void
+rewrite(NODE *p, int dorewrite, int cookie)
+{
+       NODE *l, *r;
+       int o;
+
+       l = getlr(p, 'L');
+       r = getlr(p, 'R');
+       o = p->n_op;
+       p->n_op = REG;
+       setlval(p, 0);
+       p->n_name = "";
+
+       if (o == ASSIGN || o == STASG) {
+               /* special rewrite care */
+               int reg = DECRA(p->n_reg, 0);
+#define        TL(x) (TBLIDX(x->n_su) || x->n_op == REG)
+               if (p->n_reg == -1)
+                       ;
+               else if (TL(l) && (DECRA(l->n_reg, 0) == reg))
+                       ;
+               else if (TL(r) && (DECRA(r->n_reg, 0) == reg))
+                       ;
+               else if (TL(l))
+                       rmove(DECRA(l->n_reg, 0), reg, p->n_type);
+               else if (TL(r))
+                       rmove(DECRA(r->n_reg, 0), reg, p->n_type);
+#if 0
+               else
+                       comperr("rewrite");
+#endif
+#undef TL
+       }
+       if (optype(o) != LTYPE)
+               tfree(l);
+       if (optype(o) == BITYPE)
+               tfree(r);
+       if (dorewrite == 0)
+               return;
+       CDEBUG(("rewrite: %p, reg %s\n", p,
+           p->n_reg == -1? "<none>" : rnames[DECRA(p->n_reg, 0)]));
+       p->n_rval = DECRA(p->n_reg, 0);
+}
+
+#ifndef XASM_TARGARG
+#define        XASM_TARGARG(x,y) 0
+#endif
+
+/*
+ * printout extended assembler.
+ */
+void
+genxasm(NODE *p)
+{
+       NODE *q, **nary;
+       int n = 1, o = 0, v = 0;
+       char *w;
+
+       if (p->n_left->n_op != ICON || p->n_left->n_type != STRTY) {
+               for (q = p->n_left; q->n_op == CM; q = q->n_left)
+                       n++;
+               nary = tmpcalloc(sizeof(NODE *)*(n+1));
+               o = n;
+               for (q = p->n_left; q->n_op == CM; q = q->n_left) {
+                       gencode(q->n_right->n_left, INREGS);
+                       nary[--o] = q->n_right;
+               }
+               gencode(q->n_left, INREGS);
+               nary[--o] = q;
+       } else
+               nary = 0;
+
+       w = p->n_name;
+       putchar('\t');
+       while (*w != 0) {
+               if (*w == '%') {
+                       if (w[1] == '%')
+                               putchar('%');
+                       else if (XASM_TARGARG(w, nary))
+                               ; /* handled by target */
+                       else if (w[1] == '=') {
+                               if (v == 0) v = getlab2();
+                               printf("%d", v);
+                       } else if (w[1] == 'c') {
+                               q = nary[(int)w[2]-'0']; 
+                               if (q->n_left->n_op != ICON)
+                                       uerror("impossible constraint");
+                               printf(CONFMT, getlval(q->n_left));
+                               w++;
+                       } else if (w[1] < '0' || w[1] > (n + '0'))
+                               uerror("bad xasm arg number %c", w[1]);
+                       else {
+                               if (w[1] == (n + '0'))
+                                       q = nary[(int)w[1]-'0' - 1]; /* XXX */
+                               else
+                                       q = nary[(int)w[1]-'0'];
+                               adrput(stdout, q->n_left);
+                       }
+                       w++;
+               } else if (*w == '\\') { /* Always 3-digit octal */
+                       int num = *++w - '0';
+                       num = (num << 3) + *++w - '0';
+                       num = (num << 3) + *++w - '0';
+                       putchar(num);
+               } else
+                       putchar(*w);
+               w++;
+       }
+       putchar('\n');
+}
+
+/*
+ * Allocate temporary registers for use while emitting this table entry.
+ */
+static void
+allo(NODE *p, struct optab *q)
+{
+       extern int stktemp;
+       int i, n = ncnt(q->needs);
+
+       for (i = 0; i < NRESC; i++)
+               if (resc[i].n_op != FREE)
+                       comperr("allo: used reg");
+       if (n == 0 && (q->needs & NTMASK) == 0)
+               return;
+       for (i = 0; i < n+1; i++) {
+               resc[i].n_op = REG;
+               resc[i].n_type = p->n_type; /* XXX should be correct type */
+               resc[i].n_rval = DECRA(p->n_reg, i);
+               resc[i].n_su = p->n_su; /* ??? */
+       }
+       if (i > NRESC)
+               comperr("allo: too many allocs");
+       if (q->needs & NTMASK) {
+#ifdef MYALLOTEMP
+               MYALLOTEMP(resc[i], stktemp);
+#else
+               resc[i].n_op = OREG;
+               setlval(&resc[i], stktemp);
+               resc[i].n_rval = FPREG;
+               resc[i].n_su = p->n_su; /* ??? */
+               resc[i].n_name = "";
+#endif
+       }
+}
+
+static void
+afree(void)
+{
+       int i;
+
+       for (i = 0; i < NRESC; i++)
+               resc[i].n_op = FREE;
+}
+
+void
+gencode(NODE *p, int cookie)
+{
+       struct optab *q = &table[TBLIDX(p->n_su)];
+       NODE *p1, *l, *r;
+       int o = optype(p->n_op);
+#ifdef FINDMOPS
+       int ismops = (p->n_op == ASSIGN && (p->n_su & ISMOPS));
+#endif
+
+       l = p->n_left;
+       r = p->n_right;
+
+       if (TBLIDX(p->n_su) == 0) {
+               if (o == BITYPE && (p->n_su & DORIGHT))
+                       gencode(r, 0);
+               if (optype(p->n_op) != LTYPE)
+                       gencode(l, 0);
+               if (o == BITYPE && !(p->n_su & DORIGHT))
+                       gencode(r, 0);
+               return;
+       }
+
+       CDEBUG(("gencode: node %p\n", p));
+
+       if (p->n_op == REG && DECRA(p->n_reg, 0) == p->n_rval)
+               return; /* meaningless move to itself */
+
+       if (callop(p->n_op))
+               lastcall(p); /* last chance before function args */
+       if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) {
+               /* Print out arguments first */
+               for (p1 = r; p1->n_op == CM; p1 = p1->n_left)
+                       gencode(p1->n_right, FOREFF);
+               gencode(p1, FOREFF);
+               o = UTYPE; /* avoid going down again */
+       }
+
+       if (o == BITYPE && (p->n_su & DORIGHT)) {
+               gencode(r, INREGS);
+               if (q->rewrite & RRIGHT)
+                       ckmove(p, r);
+       }
+       if (o != LTYPE) {
+               gencode(l, INREGS);
+#ifdef FINDMOPS
+               if (ismops)
+                       ;
+               else
+#endif
+                    if (q->rewrite & RLEFT)
+                       ckmove(p, l);
+       }
+       if (o == BITYPE && !(p->n_su & DORIGHT)) {
+               gencode(r, INREGS);
+               if (q->rewrite & RRIGHT)
+                       ckmove(p, r);
+       }
+
+#ifdef FINDMOPS
+       if (ismops) {
+               /* reduce right tree to make expand() work */
+               if (optype(r->n_op) != LTYPE) {
+                       p->n_op = r->n_op;
+                       r = tcopy(r->n_right);
+                       tfree(p->n_right);
+                       p->n_right = r;
+               }
+       }
+#endif
+
+       canon(p);
+
+       if (q->needs & NSPECIAL) {
+               int rr = rspecial(q, NRIGHT);
+               int lr = rspecial(q, NLEFT);
+
+               if (rr >= 0) {
+#ifdef PCC_DEBUG
+                       if (optype(p->n_op) != BITYPE)
+                               comperr("gencode: rspecial borked");
+#endif
+                       if (r->n_op != REG)
+                               comperr("gencode: rop != REG");
+                       if (rr != r->n_rval)
+                               rmove(r->n_rval, rr, r->n_type);
+                       r->n_rval = r->n_reg = rr;
+               }
+               if (lr >= 0) {
+                       if (l->n_op != REG)
+                               comperr("gencode: %p lop != REG", p);
+                       if (lr != l->n_rval)
+                               rmove(l->n_rval, lr, l->n_type);
+                       l->n_rval = l->n_reg = lr;
+               }
+               if (rr >= 0 && lr >= 0 && (l->n_reg == rr || r->n_reg == lr))
+                       comperr("gencode: cross-reg-move");
+       }
+
+       if (p->n_op == ASSIGN &&
+           p->n_left->n_op == REG && p->n_right->n_op == REG &&
+           p->n_left->n_rval == p->n_right->n_rval &&
+           (p->n_su & RVCC) == 0) { /* XXX should check if necessary */
+               /* do not emit anything */
+               CDEBUG(("gencode(%p) assign nothing\n", p));
+               rewrite(p, q->rewrite, cookie);
+               return;
+       }
+
+       CDEBUG(("emitting node %p\n", p));
+       if (TBLIDX(p->n_su) == 0)
+               return;
+
+       allo(p, q);
+       expand(p, cookie, q->cstring);
+
+#ifdef FINDMOPS
+       if (ismops && DECRA(p->n_reg, 0) != regno(l) && cookie != FOREFF) {
+               CDEBUG(("gencode(%p) rmove\n", p));
+               rmove(regno(l), DECRA(p->n_reg, 0), p->n_type);
+       } else
+#endif
+       if (callop(p->n_op) && cookie != FOREFF &&
+           DECRA(p->n_reg, 0) != RETREG(p->n_type)) {
+               CDEBUG(("gencode(%p) retreg\n", p));
+               rmove(RETREG(p->n_type), DECRA(p->n_reg, 0), p->n_type);
+       } else if (q->needs & NSPECIAL) {
+               int rr = rspecial(q, NRES);
+
+               if (rr >= 0 && DECRA(p->n_reg, 0) != rr) {
+                       CDEBUG(("gencode(%p) nspec retreg\n", p));
+                       rmove(rr, DECRA(p->n_reg, 0), p->n_type);
+               }
+       } else if ((q->rewrite & RESC1) &&
+           (DECRA(p->n_reg, 1) != DECRA(p->n_reg, 0))) {
+               CDEBUG(("gencode(%p) RESC1 retreg\n", p));
+               rmove(DECRA(p->n_reg, 1), DECRA(p->n_reg, 0), p->n_type);
+       }
+#if 0
+               /* XXX - kolla upp det h{r */
+          else if (p->n_op == ASSIGN) {
+               /* may need move added if RLEFT/RRIGHT */
+               /* XXX should be handled in sucomp() */
+               if ((q->rewrite & RLEFT) && (p->n_left->n_op == REG) &&
+                   (p->n_left->n_rval != DECRA(p->n_reg, 0)) &&
+                   TCLASS(p->n_su)) {
+                       rmove(p->n_left->n_rval, DECRA(p->n_reg, 0), p->n_type);
+               } else if ((q->rewrite & RRIGHT) && (p->n_right->n_op == REG) &&
+                   (p->n_right->n_rval != DECRA(p->n_reg, 0)) &&
+                   TCLASS(p->n_su)) {
+                       rmove(p->n_right->n_rval, DECRA(p->n_reg, 0), p->n_type);
+               }
+       }
+#endif
+       rewrite(p, q->rewrite, cookie);
+       afree();
+}
+
+int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ;  /* negatives of relationals */
+size_t negrelsize = sizeof negrel / sizeof negrel[0];
+
+#ifdef PCC_DEBUG
+#undef PRTABLE
+void
+e2print(NODE *p, int down, int *a, int *b)
+{
+       struct attr *ap;
+#ifdef PRTABLE
+       extern int tablesize;
+#endif
+
+       *a = *b = down+1;
+       while( down >= 2 ){
+               printf("\t");
+               down -= 2;
+               }
+       if( down-- ) printf("    " );
+
+
+       printf("%p) %s", p, opst[p->n_op] );
+       switch( p->n_op ) { /* special cases */
+
+       case FLD:
+               printf(" sz=%d, shift=%d",
+                   UPKFSZ(p->n_rval), UPKFOFF(p->n_rval));
+               break;
+
+       case REG:
+               printf(" %s", rnames[p->n_rval] );
+               break;
+
+       case TEMP:
+               printf(" %d", regno(p));
+               break;
+
+       case XASM:
+       case XARG:
+               printf(" '%s'", p->n_name);
+               break;
+
+       case ICON:
+       case NAME:
+       case OREG:
+               printf(" " );
+               adrput(stdout, p );
+               break;
+
+       case STCALL:
+       case USTCALL:
+       case STARG:
+       case STASG:
+               ap = attr_find(p->n_ap, ATTR_P2STRUCT);
+               printf(" size=%d", ap->iarg(0));
+               printf(" align=%d", ap->iarg(1));
+               break;
+               }
+
+       printf(", " );
+       tprint(p->n_type, p->n_qual);
+       printf(", " );
+
+       prtreg(p);
+       printf(", SU= %d(%cREG,%s,%s,%s,%s)\n",
+           TBLIDX(p->n_su), 
+           TCLASS(p->n_su)+'@',
+#ifdef PRTABLE
+           TBLIDX(p->n_su) >= 0 && TBLIDX(p->n_su) <= tablesize ?
+           table[TBLIDX(p->n_su)].cstring : "",
+#else
+           "",
+#endif
+           p->n_su & RVEFF ? "RVEFF" : "", p->n_su & RVCC ? "RVCC" : "",
+           p->n_su & DORIGHT ? "DORIGHT" : "");
+}
+#endif
+
+/*
+ * change left TEMPs into OREGs
+ */
+void
+deltemp(NODE *p, void *arg)
+{
+       int (*aor)[2] = arg;
+       NODE *l;
+
+       if (p->n_op == TEMP) {
+               if (aor[regno(p)][0] == 0) {
+                       if (xtemps)
+                               return;
+                       aor[regno(p)][0] = FPREG;
+                       aor[regno(p)][1] = freetemp(szty(p->n_type));
+               }
+               storemod(p, aor[regno(p)][1], aor[regno(p)][0]);
+       } else if (p->n_op == ADDROF && p->n_left->n_op == OREG) {
+               p->n_op = PLUS;
+               l = p->n_left;
+               l->n_op = REG;
+               l->n_type = INCREF(l->n_type);
+               p->n_right = mklnode(ICON, getlval(l), 0, INT);
+       } else if (p->n_op == ADDROF && p->n_left->n_op == UMUL) {
+               l = p->n_left;
+               *p = *p->n_left->n_left;
+               nfree(l->n_left);
+               nfree(l);
+       }
+}
+
+/*
+ * for pointer/integer arithmetic, set pointer at left node
+ */
+static void
+setleft(NODE *p, void *arg)
+{        
+       NODE *q;
+
+       /* only additions for now */
+       if (p->n_op != PLUS)
+               return;
+       if (ISPTR(p->n_right->n_type) && !ISPTR(p->n_left->n_type)) {
+               q = p->n_right;
+               p->n_right = p->n_left;
+               p->n_left = q;
+       }
+}
+
+/* It is OK to have these as externals */
+static int oregr;
+static CONSZ oregtemp;
+static char *oregcp;
+/*
+ * look for situations where we can turn * into OREG
+ * If sharp then do not allow temps.
+ */
+int
+oregok(NODE *p, int sharp)
+{
+
+       NODE *q;
+       NODE *ql, *qr;
+       int r;
+       CONSZ temp;
+       char *cp;
+
+       q = p->n_left;
+#if 0
+       if ((q->n_op == REG || (q->n_op == TEMP && !sharp)) &&
+           q->n_rval == DECRA(q->n_reg, 0)) {
+#endif
+       if (q->n_op == REG || (q->n_op == TEMP && !sharp)) {
+               temp = getlval(q);
+               r = q->n_rval;
+               cp = q->n_name;
+               goto ormake;
+       }
+
+       if (q->n_op != PLUS && q->n_op != MINUS)
+               return 0;
+       ql = q->n_left;
+       qr = q->n_right;
+
+#ifdef R2REGS
+
+       /* look for doubly indexed expressions */
+       /* XXX - fix checks */
+
+       if( q->n_op == PLUS) {
+               int i;
+               if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) {
+                       makeor2(p, ql, r, i);
+                       return 1;
+               } else if((r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) {
+                       makeor2(p, qr, r, i);
+                       return 1;
+               }
+       }
+
+
+#endif
+
+#if 0
+       if( (q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
+                       (ql->n_op==REG || (ql->n_op==TEMP && !sharp)) &&
+                       szty(qr->n_type)==1 &&
+                       (ql->n_rval == DECRA(ql->n_reg, 0) ||
+                       /* XXX */
+                        ql->n_rval == FPREG || ql->n_rval == STKREG)) {
+#endif
+       if ((q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
+           (ql->n_op==REG || (ql->n_op==TEMP && !sharp))) {
+           
+               temp = getlval(qr);
+               if( q->n_op == MINUS ) temp = -temp;
+               r = ql->n_rval;
+               temp += getlval(ql);
+               cp = qr->n_name;
+               if( *cp && ( q->n_op == MINUS || *ql->n_name ) )
+                       return 0;
+               if( !*cp ) cp = ql->n_name;
+
+               ormake:
+               if( notoff( p->n_type, r, temp, cp ))
+                       return 0;
+               oregtemp = temp;
+               oregr = r;
+               oregcp = cp;
+               return 1;
+       }
+       return 0;
+}
+
+static void
+ormake(NODE *p)
+{
+       NODE *q = p->n_left;
+
+       p->n_op = OREG;
+       p->n_rval = oregr;
+       setlval(p, oregtemp);
+       p->n_name = oregcp;
+       tfree(q);
+}
+
+/*
+ * look for situations where we can turn * into OREG
+ */
+void
+oreg2(NODE *p, void *arg)
+{
+       if (p->n_op != UMUL)
+               return;
+       if (oregok(p, 1))
+               ormake(p);
+       if (p->n_op == UMUL)
+               myormake(p);
+}
+
+void
+canon(NODE *p)
+{
+       /* put p in canonical form */
+
+       walkf(p, setleft, 0);   /* ptrs at left node for arithmetic */
+       walkf(p, oreg2, 0);     /* look for and create OREG nodes */
+       mycanon(p);             /* your own canonicalization routine(s) */
+}
+
+void
+comperr(char *str, ...)
+{
+       extern char *ftitle;
+       va_list ap;
+
+       if (nerrors) {
+               fprintf(stderr,
+                   "cannot recover from earlier errors: goodbye!\n");
+               exit(1);
+       }
+
+       va_start(ap, str);
+       fprintf(stderr, "%s, line %d: compiler error: ", ftitle, thisline);
+       vfprintf(stderr, str, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+
+#ifdef PCC_DEBUG
+       if (nodepole && nodepole->n_op != FREE)
+               fwalk(nodepole, e2print, 0);
+#endif
+       exit(1);
+}
+
+/*
+ * allocate k integers worth of temp space
+ * we also make the convention that, if the number of words is
+ * more than 1, it must be aligned for storing doubles...
+ * Returns bytes offset from base register.
+ */
+int
+freetemp(int k)
+{
+       int t, al, sz;
+
+       al = (k > 1 ? ALDOUBLE/ALCHAR : ALINT/ALCHAR);
+       sz = k * (SZINT/SZCHAR);
+
+#ifndef BACKTEMP
+       SETOFF(p2autooff, al);
+       t = p2autooff;
+       p2autooff += sz;
+#else
+       p2autooff += sz;
+       SETOFF(p2autooff, al);
+       t = ( -p2autooff );
+#endif
+       if (p2autooff > p2maxautooff)
+               p2maxautooff = p2autooff;
+       return (t);
+}
+
+NODE *
+storenode(TWORD t, int off)
+{
+       NODE *p;
+
+       p = talloc();
+       p->n_type = t;
+       storemod(p, off, FPREG); /* XXX */
+       return p;
+}
+
+#ifndef MYSTOREMOD
+void
+storemod(NODE *q, int off, int reg)
+{
+       NODE *l, *r, *p;
+
+       l = mklnode(REG, 0, reg, INCREF(q->n_type));
+       r = mklnode(ICON, off, 0, INT);
+       p = mkbinode(PLUS, l, r, INCREF(q->n_type));
+       q->n_op = UMUL;
+       q->n_left = p;
+       q->n_rval = q->n_su = 0;
+}
+#endif
+
+NODE *
+mklnode(int op, CONSZ lval, int rval, TWORD type)
+{
+       NODE *p = talloc();
+
+       p->n_name = "";
+       p->n_qual = 0;
+       p->n_ap = 0;
+       p->n_op = op;
+       setlval(p, lval);
+       p->n_rval = rval;
+       p->n_type = type;
+       p->n_regw = NULL;
+       p->n_su = 0;
+       return p;
+}
+
+NODE *
+mkbinode(int op, NODE *left, NODE *right, TWORD type)
+{
+       NODE *p = talloc();
+
+       p->n_name = "";
+       p->n_qual = 0;
+       p->n_ap = 0;
+       p->n_op = op;
+       p->n_left = left;
+       p->n_right = right;
+       p->n_type = type;
+       p->n_regw = NULL;
+       p->n_su = 0;
+       return p;
+}
+
+NODE *
+mkunode(int op, NODE *left, int rval, TWORD type)
+{
+       NODE *p = talloc();
+
+       p->n_name = "";
+       p->n_qual = 0;
+       p->n_ap = 0;
+       p->n_op = op;
+       p->n_left = left;
+       p->n_rval = rval;
+       p->n_type = type;
+       p->n_regw = NULL;
+       p->n_su = 0;
+       return p;
+}
+
+struct interpass *
+ipnode(NODE *p)
+{
+       struct interpass *ip = tmpalloc(sizeof(struct interpass));
+
+       ip->ip_node = p;
+       ip->type = IP_NODE;
+       ip->lineno = thisline;
+       return ip;
+}
+
+int
+rspecial(struct optab *q, int what)
+{
+       struct rspecial *r = nspecial(q);
+       while (r->op) {
+               if (r->op == what)
+                       return r->num;
+               r++;
+       }
+       return -1;
+}
+
+#ifndef XASM_NUMCONV
+#define        XASM_NUMCONV(x,y,z)     0
+#endif
+
+/*
+ * change numeric argument redirections to the correct node type after 
+ * cleaning up the other nodes.
+ * be careful about input operands that may have different value than output.
+ */
+static void
+delnums(NODE *p, void *arg)
+{
+       struct interpass *ip = arg, *ip2;
+       NODE *r = ip->ip_node->n_left;
+       NODE *q;
+       TWORD t;
+       int cnt, num;
+
+       /* gcc allows % in constraints, but we ignore it */
+       if (p->n_name[0] == '%' && p->n_name[1] >= '0' && p->n_name[1] <= '9')
+               p->n_name++;
+
+       if (p->n_name[0] < '0' || p->n_name[0] > '9')
+               return; /* not numeric */
+       if ((q = listarg(r, p->n_name[0] - '0', &cnt)) == NIL)
+               comperr("bad delnums");
+
+       /* target may have opinions whether to do this conversion */
+       if (XASM_NUMCONV(ip, p, q))
+               return;
+
+       /* Delete number by adding move-to/from-temp.  Later on */
+       /* the temps may be rewritten to other LTYPEs */
+       num = p2env.epp->ip_tmpnum++;
+
+       /* pre node */
+       t = p->n_left->n_type;
+       r = mklnode(TEMP, 0, num, t);
+       ip2 = ipnode(mkbinode(ASSIGN, tcopy(r), p->n_left, t));
+       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+       p->n_left = r;
+
+       /* post node */
+       t = q->n_left->n_type;
+       r = mklnode(TEMP, 0, num, t);
+       ip2 = ipnode(mkbinode(ASSIGN, q->n_left, tcopy(r), t));
+       DLIST_INSERT_AFTER(ip, ip2, qelem);
+       q->n_left = r;
+
+       p->n_name = tmpstrdup(q->n_name);
+       if (*p->n_name == '=')
+               p->n_name++;
+}
+
+/*
+ * Ensure that a node is correct for the destination.
+ */
+static void
+ltypify(NODE *p, void *arg)
+{
+       struct interpass *ip = arg;
+       struct interpass *ip2;
+       TWORD t = p->n_left->n_type;
+       NODE *q, *r;
+       int cw, ooff, ww;
+       char *c;
+
+again:
+       if (myxasm(ip, p))
+               return; /* handled by target-specific code */
+
+       cw = xasmcode(p->n_name);
+       switch (ww = XASMVAL(cw)) {
+       case 'p':
+               /* pointer */
+               /* just make register of it */
+               p->n_name = tmpstrdup(p->n_name);
+               c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
+               *c = 'r';
+               /* FALLTHROUGH */
+       case 'g':  /* general; any operand */
+               if (ww == 'g' && p->n_left->n_op == ICON) {
+                       /* should only be input */
+                       p->n_name = "i";
+                       break;
+               }
+               /* FALLTHROUGH */
+       case 'r': /* general reg */
+               /* set register class */
+               if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
+                       break;
+               q = p->n_left;
+               r = (cw & XASMINOUT ? tcopy(q) : q);
+               p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
+               if ((cw & XASMASG) == 0) {
+                       ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), r, t));
+                       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+               }
+               if (cw & (XASMASG|XASMINOUT)) {
+                       /* output parameter */
+                       ip2 = ipnode(mkbinode(ASSIGN, q, tcopy(p->n_left), t));
+                       DLIST_INSERT_AFTER(ip, ip2, qelem);
+               }
+               break;
+
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+               break;
+
+       case 'm': /* memory operand */
+               /* store and reload value */
+               q = p->n_left;
+               if (optype(q->n_op) == LTYPE) {
+                       if (q->n_op == TEMP) {
+                               ooff = freetemp(szty(t));
+                               cvtemps(ip, q->n_rval, ooff);
+                       } else if (q->n_op == REG)
+                               comperr("xasm m and reg");
+               } else if (q->n_op == UMUL && 
+                   (q->n_left->n_op != TEMP && q->n_left->n_op != REG)) {
+                       t = q->n_left->n_type;
+                       ooff = p2env.epp->ip_tmpnum++;
+                       ip2 = ipnode(mkbinode(ASSIGN,
+                           mklnode(TEMP, 0, ooff, t), q->n_left, t));
+                       q->n_left = mklnode(TEMP, 0, ooff, t);
+                       DLIST_INSERT_BEFORE(ip, ip2, qelem);
+               }
+               break;
+
+       case 'i': /* immediate constant */
+       case 'n': /* numeric constant */
+               if (p->n_left->n_op == ICON)
+                       break;
+               p->n_name = tmpstrdup(p->n_name);
+               c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
+               if (c[1]) {
+                       c[0] = c[1], c[1] = 0;
+                       goto again;
+               } else
+                       uerror("constant required");
+               break;
+
+       default:
+               uerror("unsupported xasm option string '%s'", p->n_name);
+       }
+}
+
+/* Extended assembler hacks */
+static void
+fixxasm(struct p2env *p2e)
+{
+       struct interpass *pole = &p2e->ipole;
+       struct interpass *ip;
+       NODE *p;
+
+       DLIST_FOREACH(ip, pole, qelem) {
+               if (ip->type != IP_NODE || ip->ip_node->n_op != XASM)
+                       continue;
+               thisline = ip->lineno;
+               p = ip->ip_node->n_left;
+
+               if (p->n_op == ICON && p->n_type == STRTY)
+                       continue;
+
+               /* replace numeric redirections with its underlying type */
+               flist(p, delnums, ip);
+
+               /*
+                * Ensure that the arg nodes can be directly addressable
+                * We decide that everything shall be LTYPE here.
+                */
+               flist(p, ltypify, ip);
+       }
+}
+
+/*
+ * Extract codeword from xasm string */
+int
+xasmcode(char *s)
+{
+       int cw = 0, nm = 0;
+
+       while (*s) {
+               switch ((int)*s) {
+               case '=': cw |= XASMASG; break;
+               case '&': cw |= XASMCONSTR; break;
+               case '+': cw |= XASMINOUT; break;
+               case '%': break;
+               default:
+                       if ((*s >= 'a' && *s <= 'z') ||
+                           (*s >= 'A' && *s <= 'Z') ||
+                           (*s >= '0' && *s <= '9')) {
+                               if (nm == 0)
+                                       cw |= *s;
+                               else
+                                       cw |= (*s << ((nm + 1) * 8));
+                               nm++;
+                               break;
+                       }
+                       uerror("bad xasm constraint %c", *s);
+               }
+               s++;
+       }
+       return cw;
+}
+
+static int xasnum, xoffnum;
+
+static void
+xconv(NODE *p, void *arg)
+{
+       if (p->n_op != TEMP || p->n_rval != xasnum)
+               return;
+       storemod(p, xoffnum, FPREG); /* XXX */
+}
+
+/*
+ * Convert nodes of type TEMP to op with lval off.
+ */
+static void
+cvtemps(struct interpass *ipl, int tnum, int off)
+{
+       struct interpass *ip;
+
+       xasnum = tnum;
+       xoffnum = off;
+
+       DLIST_FOREACH(ip, ipl, qelem)
+               if (ip->type == IP_NODE)
+                       walkf(ip->ip_node, xconv, 0);
+       walkf(ipl->ip_node, xconv, 0);
+}
diff --git a/lang/pcc/pcc/mip/regs.c b/lang/pcc/pcc/mip/regs.c
new file mode 100644 (file)
index 0000000..8ea2fc1
--- /dev/null
@@ -0,0 +1,3113 @@
+/*     $Id: regs.c,v 1.247 2015/11/17 19:19:40 ragge Exp $     */
+/*
+ * Copyright (c) 2005 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+
+#define        MAXLOOP 20 /* Max number of allocation loops XXX 3 should be enough */
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/*
+ * New-style register allocator using graph coloring.
+ * The design is based on the George and Appel paper
+ * "Iterated Register Coalescing", ACM Transactions, No 3, May 1996.
+ */
+
+#define        BITALLOC(ptr,all,sz) { \
+       int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
+
+#undef COMPERR_PERM_MOVE
+#ifdef PCC_DEBUG
+#define        RDEBUG(x)       if (r2debug) printf x
+#define        RRDEBUG(x)      if (r2debug > 1) printf x
+#define        RPRINTIP(x)     if (r2debug) printip(x)
+#define        RDEBUGX(x)              x
+#define        UDEBUG(x)       if (u2debug) printf x
+#define BDEBUG(x)      if (b2debug) printf x
+#define BBDEBUG(x)     if (b2debug > 1) printf x
+#else
+#define        RDEBUG(x)
+#define        RRDEBUG(x)
+#define        RPRINTIP(x)
+#define        RDEBUGX(x)
+#define UDEBUG(x)
+#define BDEBUG(x)
+#define BBDEBUG(x)
+#endif
+
+#define        VALIDREG(p)     (p->n_op == REG && TESTBIT(validregs, regno(p)))
+
+/*
+ * Data structure overview for this implementation of graph coloring:
+ *
+ * Each temporary (called "node") is described by the type REGW.  
+ * Space for all nodes is allocated initially as an array, so 
+ * the nodes can be can be referenced both by the node number and
+ * by pointer.
+ * 
+ * All moves are represented by the type REGM, allocated when needed. 
+ *
+ * The "live" set used during graph building is represented by a bitset.
+ *
+ * Interference edges are represented by struct AdjSet, hashed and linked
+ * from index into the edgehash array.
+ *
+ * A mapping from each node to the moves it is assiciated with is 
+ * maintained by an array moveList which for each node number has a linked
+ * list of MOVL types, each pointing to a REGM.
+ *
+ * Adjacency list is maintained by the adjList array, indexed by the
+ * node number. Each adjList entry points to an ADJL type, and is a
+ * single-linked list for all adjacent nodes.
+ *
+ * degree, alias and color are integer arrays indexed by node number.
+ */
+
+/*
+ * linked list of adjacent nodes.
+ */
+typedef struct regw3 {
+       struct regw3 *r_next;
+       struct regw *a_temp;
+} ADJL;
+
+/*
+ * Structure describing a move.
+ */
+typedef struct regm {
+       DLIST_ENTRY(regm) link;
+       struct regw *src, *dst;
+       int queue;
+} REGM;
+
+typedef struct movlink {
+       struct movlink *next;
+       REGM *regm;
+} MOVL;
+
+/*
+ * Structure describing a temporary.
+ */
+typedef struct regw {
+       DLIST_ENTRY(regw) link;
+       ADJL *r_adjList;        /* linked list of adjacent nodes */
+       int r_class;            /* this nodes class */
+       int r_nclass[NUMCLASS+1];       /* count of adjacent classes */
+       struct regw *r_alias;           /* aliased temporary */
+       int r_color;            /* final node color */
+       struct regw *r_onlist;  /* which work list this node belongs to */
+       MOVL *r_moveList;       /* moves associated with this node */
+       int nodnum;             /* Human-readable node number */
+} REGW;
+
+/*
+ * Worklists, a node is always on exactly one of these lists.
+ */
+static REGW precolored, simplifyWorklist, freezeWorklist, spillWorklist,
+       spilledNodes, coalescedNodes, coloredNodes, selectStack;
+static REGW initial, *nblock;
+static void insnwalk(NODE *p);
+#ifdef PCC_DEBUG
+int use_regw;
+#endif
+int nodnum = 100;
+int ntsz, stktemp;
+#define        SETNUM(x)       (x)->nodnum = nodnum++
+#define        ASGNUM(x)       (x)->nodnum
+
+#define        ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT)
+
+/* XXX */
+REGW *ablock;
+
+static int tempmin, tempmax, basetemp, xbits;
+/*
+ * nsavregs is an array that matches the permregs array.
+ * Each entry in the array may have the values:
+ * 0   : register coalesced, just ignore.
+ * 1   : save register on stack
+ * If the entry is 0 but the resulting color differs from the 
+ * corresponding permregs index, add moves.
+ * XXX - should be a bitfield!
+ */
+static int *nsavregs, *ndontregs;
+
+/*
+ * Return the REGW struct for a temporary.
+ * If first time touched, enter into list for existing vars.
+ * Only called from sucomp().
+ */
+static REGW *
+newblock(NODE *p)
+{
+       REGW *nb;
+
+#ifdef PCC_DEBUG
+       if (regno(p) < tempmin || regno(p) >= tempmax)
+               comperr("temp %p(%d) outside limits (%d-%d)",
+                   p, regno(p), tempmin, tempmax);
+#endif
+       nb = &nblock[regno(p)];
+       if (nb->link.q_forw == 0) {
+               DLIST_INSERT_AFTER(&initial, nb, link);
+#ifdef PCC_DEBUG
+               ASGNUM(nb) = regno(p);
+               RDEBUG(("Adding longtime %d for tmp %d\n",
+                   nb->nodnum, regno(p)));
+#endif
+       }
+       if (nb->r_class == 0)
+               nb->r_class = gclass(p->n_type);
+#ifdef PCC_DEBUG
+       RDEBUG(("newblock: p %p, node %d class %d\n",
+           p, nb->nodnum, nb->r_class));
+#endif
+       return nb;
+}
+
+/*
+ * Count the number of registers needed to evaluate a tree.
+ * This is only done to find the evaluation order of the tree.
+ * While here, assign temp numbers to the registers that will
+ * be needed when the tree is evaluated.
+ *
+ * While traversing the tree, assign REGW nodes to the registers
+ * used by all instructions:
+ *     - n_regw[0] is always set to the outgoing node. If the
+ *       instruction is 2-op (addl r0,r1) then an implicit move
+ *       is inserted just before the left (clobbered) operand.
+ *     - if the instruction has needs then REGW nodes are
+ *       allocated as n_regw[1] etc.
+ */
+int
+nsucomp(NODE *p)
+{
+       struct optab *q;
+       int left, right;
+       int nreg, need, i, nxreg, o;
+       int nareg, nbreg, ncreg, ndreg, nereg, nfreg, ngreg;
+       REGW *w;
+
+       o = optype(p->n_op);
+
+       UDEBUG(("entering nsucomp, node %p\n", p));
+
+       if (TBLIDX(p->n_su) == 0) {
+               int a = 0, b;
+
+               p->n_regw = NULL;
+               if (o == LTYPE ) {
+                       if (p->n_op == TEMP) {
+                               p->n_regw = newblock(p);
+                               a = 1;
+                       } else if (p->n_op == REG)
+                               p->n_regw = &ablock[regno(p)];
+               } else
+                       a = nsucomp(p->n_left);
+               if (o == BITYPE) {
+                       b = nsucomp(p->n_right);
+                       if (b > a)
+                               p->n_su |= DORIGHT;
+                       a = MAX(a, b);
+               }
+               return a;
+       }
+
+       q = &table[TBLIDX(p->n_su)];
+
+#define        NNEEDS(a,b) ((q->needs & a)/b)
+       for (i = (q->needs & NACOUNT), nareg = 0; i; i -= NAREG)
+               nareg++;
+       for (i = (q->needs & NBCOUNT), nbreg = 0; i; i -= NBREG)
+               nbreg++;
+       for (i = (q->needs & NCCOUNT), ncreg = 0; i; i -= NCREG)
+               ncreg++;
+       for (i = (q->needs & NDCOUNT), ndreg = 0; i; i -= NDREG)
+               ndreg++;
+       for (i = (q->needs & NECOUNT), nereg = 0; i; i -= NEREG)
+               nereg++;
+       for (i = (q->needs & NFCOUNT), nfreg = 0; i; i -= NFREG)
+               nfreg++;
+       for (i = (q->needs & NGCOUNT), ngreg = 0; i; i -= NGREG)
+               ngreg++;
+
+       if (ntsz < NNEEDS(NTMASK, NTEMP) * szty(p->n_type))
+               ntsz = NNEEDS(NTMASK, NTEMP) * szty(p->n_type);
+
+       nxreg = nareg + nbreg + ncreg + ndreg + nereg + nfreg + ngreg;
+       nreg = nxreg;
+       if (callop(p->n_op))
+               nreg = MAX(fregs, nreg);
+
+       if (o == BITYPE) {
+               right = nsucomp(p->n_right);
+       } else
+               right = 0;
+
+       if (o != LTYPE)
+               left = nsucomp(p->n_left);
+       else
+               left = 0;
+
+       UDEBUG(("node %p left %d right %d\n", p, left, right));
+
+       if (o == BITYPE) {
+               /* Two children */
+               if (right == left) {
+                       need = left + MAX(nreg, 1);
+               } else {
+                       need = MAX(right, left);
+                       need = MAX(need, nreg);
+               }
+               if (setorder(p) == 0) {
+                       /* XXX - should take care of overlapping needs */
+                       if (right > left) {
+                               p->n_su |= DORIGHT;
+                       } else if (right == left) {
+#if 0
+       /* XXX - need something more clever when large left trees */
+                               /* A favor to 2-operand architectures */
+                               if ((q->rewrite & RRIGHT) == 0)
+                                       p->n_su |= DORIGHT;
+#endif
+                       }
+               }
+       } else if (o != LTYPE) {
+               /* One child */
+               need = MAX(right, left) + nreg;
+       } else
+               need = nreg;
+
+       if (p->n_op == TEMP)
+               (void)newblock(p);
+
+       if (TCLASS(p->n_su) == 0 && nxreg == 0) {
+               UDEBUG(("node %p no class\n", p));
+               p->n_regw = NULL; /* may be set earlier */
+               return need;
+       }
+
+#ifdef PCC_DEBUG
+#define        ADCL(n, cl)     \
+       for (i = 0; i < n; i++, w++) {  w->r_class = cl; \
+               DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
+               UDEBUG(("Adding " #n " %d\n", w->nodnum)); \
+       }
+#else
+#define        ADCL(n, cl)     \
+       for (i = 0; i < n; i++, w++) {  w->r_class = cl; \
+               DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
+       }
+#endif
+
+       UDEBUG(("node %p numregs %d\n", p, nxreg+1));
+       w = p->n_regw = tmpalloc(sizeof(REGW) * (nxreg+1));
+       memset(w, 0, sizeof(REGW) * (nxreg+1));
+
+       w->r_class = TCLASS(p->n_su);
+       if (w->r_class == 0)
+               w->r_class = gclass(p->n_type);
+       w->r_nclass[0] = o == LTYPE; /* XXX store leaf info here */
+       SETNUM(w);
+       if (w->r_class)
+               DLIST_INSERT_BEFORE(&initial, w, link);
+#ifdef PCC_DEBUG
+       UDEBUG(("Adding short %d class %d\n", w->nodnum, w->r_class));
+#endif
+       w++;
+       ADCL(nareg, CLASSA);
+       ADCL(nbreg, CLASSB);
+       ADCL(ncreg, CLASSC);
+       ADCL(ndreg, CLASSD);
+       ADCL(nereg, CLASSE);
+       ADCL(nfreg, CLASSF);
+       ADCL(ngreg, CLASSG);
+
+       if (q->rewrite & RESC1) {
+               w = p->n_regw + 1;
+               w->r_class = -1;
+               DLIST_REMOVE(w,link);
+       } else if (q->rewrite & RESC2) {
+               w = p->n_regw + 2;
+               w->r_class = -1;
+               DLIST_REMOVE(w,link);
+       } else if (q->rewrite & RESC3) {
+               w = p->n_regw + 3;
+               w->r_class = -1;
+               DLIST_REMOVE(w,link);
+       }
+
+       UDEBUG(("node %p return regs %d\n", p, need));
+
+       return need;
+}
+
+#define        CLASS(x)        (x)->r_class
+#define        NCLASS(x,c)     (x)->r_nclass[c]
+#define        ADJLIST(x)      (x)->r_adjList
+#define        ALIAS(x)        (x)->r_alias
+#define        ONLIST(x)       (x)->r_onlist
+#define        MOVELIST(x)     (x)->r_moveList
+#define        COLOR(x)        (x)->r_color
+
+static bittype *live;
+
+#define        PUSHWLIST(w, l) DLIST_INSERT_AFTER(&l, w, link); w->r_onlist = &l
+#define        POPWLIST(l)     popwlist(&l);
+#define        DELWLIST(w)     DLIST_REMOVE(w, link)
+#define WLISTEMPTY(h)  DLIST_ISEMPTY(&h,link)
+#define        PUSHMLIST(w, l, q)      DLIST_INSERT_AFTER(&l, w, link); w->queue = q
+#define        POPMLIST(l)     popmlist(&l);
+
+#define        trivially_colorable(x) \
+       trivially_colorable_p((x)->r_class, (x)->r_nclass)
+/*
+ * Determine if a node is trivially colorable ("degree < K").
+ * This implementation is a dumb one, without considering speed.
+ */
+static int
+trivially_colorable_p(int c, int *n)
+{
+       int r[NUMCLASS+1];
+       int i;
+
+       for (i = 1; i < NUMCLASS+1; i++)
+               r[i] = n[i] < regK[i] ? n[i] : regK[i];
+
+#if 0
+       /* add the exclusion nodes. */
+       /* XXX can we do someything smart here? */
+       /* worst-case for exclusion nodes are better than the `worst-case' */
+       for (; excl; excl >>= 1)
+               if (excl & 1)
+                       r[c]++;
+#endif
+
+       i = COLORMAP(c, r);
+       if (i < 0 || i > 1)
+               comperr("trivially_colorable_p");
+       RRDEBUG(("trivially_colorable_p: n[1] %d n[2] %d n[3] %d n[4] "
+           "%d for class %d, triv %d\n", n[1], n[2], n[3], n[4], c, i));
+       return i;
+}
+
+int
+ncnt(int needs)
+{
+       int i = 0;
+
+       while (needs & NACOUNT)
+               needs -= NAREG, i++;
+       while (needs & NBCOUNT)
+               needs -= NBREG, i++;
+       while (needs & NCCOUNT)
+               needs -= NCREG, i++;
+       while (needs & NDCOUNT)
+               needs -= NDREG, i++;
+       while (needs & NECOUNT)
+               needs -= NEREG, i++;
+       while (needs & NFCOUNT)
+               needs -= NFREG, i++;
+       while (needs & NGCOUNT)
+               needs -= NGREG, i++;
+       return i;
+}
+
+static REGW *
+popwlist(REGW *l)
+{
+       REGW *w = DLIST_NEXT(l, link);
+
+       DLIST_REMOVE(w, link);
+       w->r_onlist = NULL;
+       return w;
+}
+
+/*
+ * Move lists, a move node is always on only one list.
+ */
+static REGM coalescedMoves, constrainedMoves, frozenMoves, 
+       worklistMoves, activeMoves;
+enum { COAL, CONSTR, FROZEN, WLIST, ACTIVE };
+
+static REGM *
+popmlist(REGM *l)
+{
+       REGM *w = DLIST_NEXT(l, link);
+
+       DLIST_REMOVE(w, link);
+       return w;
+}
+
+/*
+ * About data structures used in liveness analysis:
+ *
+ * The temporaries generated in pass1 are numbered between tempmin and
+ * tempmax.  Temporaries generated in pass2 are numbered above tempmax,
+ * so they are sequentially numbered.
+ *
+ * Bitfields are used for liveness.  Bit arrays are allocated on the
+ * heap for the "live" variable and on the stack for the in, out, gen
+ * and killed variables. Therefore, for a temp number, the bit number must
+ * be biased with tempmin.
+ *
+ * There may be an idea to use a different data structure to store 
+ * pass2 allocated temporaries, because they are very sparse.
+ */
+
+#ifdef PCC_DEBUG
+static void
+LIVEADD(int x)
+{
+       RDEBUG(("Liveadd: %d\n", x));
+       if (x >= MAXREGS && (x < tempmin || x >= tempmax))
+               comperr("LIVEADD: out of range");
+       if (x < MAXREGS) {
+               BITSET(live, x);
+       } else
+               BITSET(live, (x-tempmin+MAXREGS));
+}
+
+static void
+LIVEDEL(int x)
+{
+       RDEBUG(("Livedel: %d\n", x));
+
+       if (x >= MAXREGS && (x < tempmin || x >= tempmax))
+               comperr("LIVEDEL: out of range");
+       if (x < MAXREGS) {
+               BITCLEAR(live, x);
+       } else
+               BITCLEAR(live, (x-tempmin+MAXREGS));
+}
+#else
+#define LIVEADD(x) \
+       (x >= MAXREGS ? BITSET(live, (x-tempmin+MAXREGS)) : BITSET(live, x))
+#define LIVEDEL(x) \
+       (x >= MAXREGS ? BITCLEAR(live, (x-tempmin+MAXREGS)) : BITCLEAR(live, x))
+#endif
+
+static struct lives {
+       DLIST_ENTRY(lives) link;
+       REGW *var;
+} lused, lunused;
+
+static void
+LIVEADDR(REGW *x)
+{
+       struct lives *l;
+
+#ifdef PCC_DEBUG
+       RDEBUG(("LIVEADDR: %d\n", x->nodnum));
+       DLIST_FOREACH(l, &lused, link)
+               if (l->var == x)
+                       return;
+#if 0
+                       comperr("LIVEADDR: multiple %d", ASGNUM(x));
+#endif
+#endif
+       if (!DLIST_ISEMPTY(&lunused, link)) {
+               l = DLIST_NEXT(&lunused, link);
+               DLIST_REMOVE(l, link);
+       } else
+               l = tmpalloc(sizeof(struct lives));
+
+       l->var = x;
+       DLIST_INSERT_AFTER(&lused, l, link);
+}
+
+static void
+LIVEDELR(REGW *x)
+{
+       struct lives *l;
+
+#ifdef PCC_DEBUG
+       RDEBUG(("LIVEDELR: %d\n", x->nodnum));
+#endif
+       DLIST_FOREACH(l, &lused, link) {
+               if (l->var != x)
+                       continue;
+               DLIST_REMOVE(l, link);
+               DLIST_INSERT_AFTER(&lunused, l, link);
+               return;
+       }
+#if 0
+       comperr("LIVEDELR: %p not found", x);
+#endif
+}
+
+#define        MOVELISTADD(t, p) movelistadd(t, p)
+#define WORKLISTMOVEADD(s,d) worklistmoveadd(s,d)
+
+static void
+movelistadd(REGW *t, REGM *p)
+{
+       MOVL *w = tmpalloc(sizeof(MOVL));
+
+       w->regm = p;
+       w->next = t->r_moveList;
+       t->r_moveList = w;
+}
+
+static REGM *
+worklistmoveadd(REGW *src, REGW *dst)
+{
+       REGM *w = tmpalloc(sizeof(REGM));
+
+       DLIST_INSERT_AFTER(&worklistMoves, w, link);
+       w->src = src;
+       w->dst = dst;
+       w->queue = WLIST;
+       return w;
+}
+
+#define        HASHSZ  16384
+struct AdjSet {
+       struct AdjSet *next;
+       REGW *u, *v;
+} *edgehash[HASHSZ];
+
+/* Check if a node pair is adjacent */
+static int
+adjSet(REGW *u, REGW *v)
+{
+       struct AdjSet *w;
+       REGW *t;
+
+       if (ONLIST(u) == &precolored) {
+               ADJL *a = ADJLIST(v);
+               /*
+                * Check if any of the registers that have edges against v
+                * alias to u.
+                */
+               for (; a; a = a->r_next) {
+                       if (ONLIST(a->a_temp) != &precolored)
+                               continue;
+                       t = a->a_temp;
+                       if (interferes(t - ablock, u - ablock))
+                               return 1;
+               }
+       }
+
+       w = edgehash[(u->nodnum+v->nodnum)& (HASHSZ-1)];
+
+       for (; w; w = w->next) {
+               if ((u == w->u && v == w->v) || (u == w->v && v == w->u))
+                       return 1;
+       }
+       return 0;
+}
+
+/* Add a pair to adjset.  No check for dups */
+static int
+adjSetadd(REGW *u, REGW *v)
+{
+       struct AdjSet *w;
+       int x;
+
+       x = (u->nodnum+v->nodnum)& (HASHSZ-1);
+       for (w = edgehash[x]; w; w = w->next)
+               if ((u == w->u && v == w->v) || (u == w->v && v == w->u))
+                       return 1;
+
+       w = tmpalloc(sizeof(struct AdjSet));
+       w->u = u, w->v = v;
+       w->next = edgehash[x];
+       edgehash[x] = w;
+       return 0;
+}
+
+/*
+ * Add an interference edge between two nodes.
+ */
+static void
+AddEdge(REGW *u, REGW *v)
+{
+       ADJL *x;
+
+#ifdef PCC_DEBUG
+       RRDEBUG(("AddEdge: u %d v %d\n", ASGNUM(u), ASGNUM(v)));
+
+#if 0
+       if (ASGNUM(u) == 0)
+               comperr("AddEdge 0");
+#endif
+       if (CLASS(u) == 0 || CLASS(v) == 0)
+               comperr("AddEdge class == 0 (%d=%d, %d=%d)",
+                   CLASS(u), ASGNUM(u), CLASS(v), ASGNUM(v));
+#endif
+
+       if (u == v)
+               return;
+       if (adjSetadd(u, v))
+               return;
+
+#if 0
+       if (ONLIST(u) == &precolored || ONLIST(v) == &precolored)
+               comperr("precolored node in AddEdge");
+#endif
+
+       if (ONLIST(u) != &precolored) {
+               x = tmpalloc(sizeof(ADJL));
+               x->a_temp = v;
+               x->r_next = u->r_adjList;
+               u->r_adjList = x;
+               NCLASS(u, CLASS(v))++;
+       }
+
+       if (ONLIST(v) != &precolored) {
+               x = tmpalloc(sizeof(ADJL));
+               x->a_temp = u;
+               x->r_next = v->r_adjList;
+               v->r_adjList = x;
+               NCLASS(v, CLASS(u))++;
+       }
+
+#if 0
+       RDEBUG(("AddEdge: u %d(d %d) v %d(d %d)\n", u, DEGREE(u), v, DEGREE(v)));
+#endif
+}
+
+static int
+MoveRelated(REGW *n)
+{
+       MOVL *l;
+       REGM *w;
+
+       for (l = MOVELIST(n); l; l = l->next) {
+               w = l->regm;
+               if (w->queue == ACTIVE || w->queue == WLIST)
+                       return 1;
+       }
+       return 0;
+}
+
+static void
+MkWorklist(void)
+{
+       REGW *w;
+
+       RDEBUGX(int s=0);
+       RDEBUGX(int f=0);
+       RDEBUGX(int d=0);
+
+       DLIST_INIT(&precolored, link);
+       DLIST_INIT(&simplifyWorklist, link);
+       DLIST_INIT(&freezeWorklist, link);
+       DLIST_INIT(&spillWorklist, link);
+       DLIST_INIT(&spilledNodes, link);
+       DLIST_INIT(&coalescedNodes, link);
+       DLIST_INIT(&coloredNodes, link);
+       DLIST_INIT(&selectStack, link);
+
+       /*
+        * Remove all nodes from the initial list and put them on 
+        * one of the worklists.
+        */
+       while (!DLIST_ISEMPTY(&initial, link)) {
+               w = DLIST_NEXT(&initial, link);
+               DLIST_REMOVE(w, link);
+               if (!trivially_colorable(w)) {
+                       PUSHWLIST(w, spillWorklist);
+                       RDEBUGX(s++);
+               } else if (MoveRelated(w)) {
+                       PUSHWLIST(w, freezeWorklist);
+                       RDEBUGX(f++);
+               } else {
+                       PUSHWLIST(w, simplifyWorklist);
+                       RDEBUGX(d++);
+               }
+       }
+       RDEBUG(("MkWorklist: spill %d freeze %d simplify %d\n", s,f,d));
+}
+
+static void
+addalledges(REGW *e)
+{
+       int i, j, k;
+       struct lives *l;
+
+#ifdef PCC_DEBUG
+       RDEBUG(("addalledges for %d\n", e->nodnum));
+#endif
+
+       if (e->r_class == -1)
+               return; /* unused */
+
+       if (ONLIST(e) != &precolored) {
+               for (i = 0; ndontregs[i] >= 0; i++)
+                       AddEdge(e, &ablock[ndontregs[i]]);
+       }
+
+       /* First add to long-lived temps and hard regs */
+       RDEBUG(("addalledges longlived "));
+       for (i = 0; i < xbits; i += NUMBITS) {
+               if ((k = live[i/NUMBITS])) {
+                       while (k) {
+                               j = ffs(k)-1;
+                               if (i+j < MAXREGS)
+                                       AddEdge(&ablock[i+j], e);
+                               else
+                                       AddEdge(&nblock[i+j+tempmin-MAXREGS],e);
+                               RRDEBUG(("%d ", i+j+tempmin));
+                               k &= ~(1 << j);
+                       }
+               }
+#if NUMBITS > 32 /* XXX hack for LP64 */
+               k = (live[i/NUMBITS] >> 32);
+               while (k) {
+                       j = ffs(k)-1;
+                       if (i+j+32 < MAXREGS)
+                               AddEdge(&ablock[i+j+32], e);
+                       else
+                               AddEdge(&nblock[i+j+tempmin-MAXREGS+32], e);
+                       RRDEBUG(("%d ", i+j+tempmin+32));
+                       k &= ~(1 << j);
+               }
+#endif
+       }
+       RDEBUG(("done\n"));
+       /* short-lived temps */
+       RDEBUG(("addalledges shortlived "));
+       DLIST_FOREACH(l, &lused, link) {
+#ifdef PCC_DEBUG
+               RRDEBUG(("%d ", ASGNUM(l->var)));
+#endif
+               AddEdge(l->var, e);
+       }
+       RDEBUG(("done\n"));
+}
+
+/*
+ * Add a move edge between def and use.
+ */
+static void
+moveadd(REGW *def, REGW *use)
+{
+       REGM *r;
+       MOVL *w;
+
+       if (def == use)
+               return; /* no move to itself XXX - ``shouldn't happen'' */
+#ifdef PCC_DEBUG
+       RDEBUG(("moveadd: def %d use %d\n", ASGNUM(def), ASGNUM(use)));
+#endif
+
+       /*
+        * Check if we are already on move list.
+        * XXX How can that happen ???
+        */
+       for (w = MOVELIST(def); w; w = w->next) {
+               if ((w->regm->src == def && w->regm->dst == use) ||
+                   (w->regm->src == use && w->regm->dst == def))
+                       return; /* already there XXX reverse? */
+       }
+
+       r = WORKLISTMOVEADD(use, def);
+       MOVELISTADD(def, r);
+       MOVELISTADD(use, r);
+}
+
+/*
+ * Traverse arguments backwards.
+ * XXX - can this be tricked in some other way?
+ */
+static void
+argswalk(NODE *p)
+{
+
+       if (p->n_op == CM) {
+               argswalk(p->n_left);
+               insnwalk(p->n_right);
+       } else
+               insnwalk(p);
+}
+
+/*
+ * Add to (or remove from) live set variables that must not
+ * be clobbered when traversing down on the other leg for 
+ * a BITYPE node.
+ */
+static void
+setlive(NODE *p, int set, REGW *rv)
+{
+       if (rv != NULL) {
+               if (rv->nodnum < MAXREGS &&
+                   TESTBIT(validregs, rv->nodnum) == 0)
+                       return;
+               set ? LIVEADDR(rv) : LIVEDELR(rv);
+               return;
+       }
+
+       if (p->n_regw != NULL) {
+               if (p->n_regw->nodnum < MAXREGS &&
+                   TESTBIT(validregs, p->n_regw->nodnum) == 0)
+                       return;
+               set ? LIVEADDR(p->n_regw) : LIVEDELR(p->n_regw);
+               return;
+       }
+
+       switch (optype(p->n_op)) {
+       case LTYPE:
+               if (p->n_op == TEMP || VALIDREG(p))
+                       set ? LIVEADD(regno(p)) : LIVEDEL(regno(p));
+               break;
+       case BITYPE:
+               setlive(p->n_right, set, rv);
+               /* FALLTHROUGH */
+       case UTYPE:
+               setlive(p->n_left, set, rv);
+               break;
+       }
+}
+
+/*
+ * Add edges for temporary w against all temporaries that may be
+ * used simultaneously (like index registers).
+ */
+static void
+addedge_r(NODE *p, REGW *w)
+{
+       RRDEBUG(("addedge_r: node %p regw %p\n", p, w));
+
+       if (p->n_regw != NULL) {
+               if (p->n_regw->nodnum < MAXREGS &&
+                   TESTBIT(validregs, p->n_regw->nodnum) == 0)
+                       return;
+               AddEdge(p->n_regw, w);
+               return;
+       }
+
+       if (optype(p->n_op) == BITYPE)
+               addedge_r(p->n_right, w);
+       if (optype(p->n_op) != LTYPE)
+               addedge_r(p->n_left, w);
+}
+
+/*
+ * delete early clobber liveness. Only interesting on regs.
+ */
+static void
+delcl(NODE *p)
+{
+       int cw;
+
+       if (p->n_op == ICON && p->n_type == STRTY)
+               return;
+       cw = xasmcode(p->n_name);
+       if ((cw & XASMCONSTR) == 0 || !XASMISOUT(cw))
+               return;
+       if (XASMVAL(cw) != 'r')
+               return;
+       LIVEDEL(regno(p->n_left));
+}
+
+/*
+ * add/del parameter from live set.
+ */
+static void
+setxarg(NODE *p)
+{
+       int i, ut = 0, in = 0;
+       REGW *rw;
+       int c, cw;
+
+       if (p->n_op == ICON && p->n_type == STRTY)
+               return;
+
+       RDEBUG(("setxarg %p %s\n", p, p->n_name));
+       cw = xasmcode(p->n_name);
+       if (XASMISINP(cw))
+               in = 1;
+       if (XASMISOUT(cw) && !(cw & XASMCONSTR))
+               ut = 1;
+
+       c = XASMVAL(cw);
+
+#ifdef MYSETXARG
+       MYSETXARG;
+#endif
+
+       switch (c) {
+       case 'm':
+       case 'g':
+               /* must find all TEMPs/REGs and set them live */
+               if (p->n_left->n_op != REG && p->n_left->n_op != TEMP) {
+                       insnwalk(p->n_left);
+                       break;
+               }
+               /* FALLTHROUGH */
+       case 'r':
+               i = regno(p->n_left);
+               rw = p->n_left->n_op == REG ? ablock : nblock;
+               if (ut) {
+                       LIVEDEL(i);
+               }
+               if (in) {
+                       LIVEADD(i);
+               }
+               addalledges(&rw[i]);
+               break;
+
+       case 'i':
+       case 'n':
+               break;
+       default:
+               comperr("bad ixarg %s", p->n_name);
+       }
+#ifdef MYSETXARG
+       MYSETXARG;
+#endif
+}
+
+/*
+ * Do the in-tree part of liveness analysis. (the difficult part)
+ *
+ * Walk down the tree in reversed-evaluation order (backwards).
+ * The moves and edges inserted and evaluation order for
+ * instructions when code is emitted is described here, hence
+ * this code runs the same but backwards.
+ *
+ * 2-op reclaim LEFT: eval L, move to DEST, eval R.
+ *     moveadd L,DEST; addedge DEST,R
+ * 2-op reclaim LEFT DORIGHT: eval R, eval L, move to DEST.
+ *     moveadd L,DEST; addedge DEST,R; addedge L,R
+ * 2-op reclaim RIGHT; eval L, eval R, move to DEST.
+ *     moveadd R,DEST; addedge DEST,L; addedge L,R
+ * 2-op reclaim RIGHT DORIGHT: eval R, move to DEST, eval L.
+ *     moveadd R,DEST; addedge DEST,L
+ * 3-op: eval L, eval R
+ *     addedge L,R
+ * 3-op DORIGHT: eval R, eval L
+ *     addedge L,R
+ *
+ * Instructions with special needs are handled just like these variants,
+ * with the exception of extra added moves and edges.
+ * Moves to special regs are scheduled after the evaluation of both legs.
+ */
+
+static void
+insnwalk(NODE *p)
+{
+       int o = p->n_op;
+       struct optab *q = &table[TBLIDX(p->n_su)];
+       REGW *lr, *rr, *rv, *r, *rrv, *lrv;
+       NODE *lp, *rp;
+       int i, n;
+
+       RDEBUG(("insnwalk %p\n", p));
+
+       rv = p->n_regw;
+
+       rrv = lrv = NULL;
+       if (p->n_op == ASSIGN &&
+           (p->n_left->n_op == TEMP || VALIDREG(p->n_left))) {
+               lr = p->n_left->n_op == TEMP ? nblock : ablock;
+               i = regno(p->n_left);
+               LIVEDEL(i);     /* remove assigned temp from live set */
+               addalledges(&lr[i]);
+       }
+
+       /* Add edges for the result of this node */
+       if (rv && (q->visit & INREGS || o == TEMP || VALIDREG(p)))      
+               addalledges(rv);
+
+       /* special handling of CALL operators */
+       if (callop(o)) {
+               if (rv)
+                       moveadd(rv, &ablock[RETREG(p->n_type)]);
+               for (i = 0; tempregs[i] >= 0; i++)
+                       addalledges(&ablock[tempregs[i]]);
+       }
+
+       /* for special return value registers add moves */
+       if ((q->needs & NSPECIAL) && (n = rspecial(q, NRES)) >= 0 &&
+           p->n_regw != NULL) {
+               rv = &ablock[n];
+               moveadd(p->n_regw, rv);
+       }
+
+       /* Check leaves for results in registers */
+       lr = optype(o) != LTYPE ? p->n_left->n_regw : NULL;
+       lp = optype(o) != LTYPE ? p->n_left : NULL;
+       rr = optype(o) == BITYPE ? p->n_right->n_regw : NULL;
+       rp = optype(o) == BITYPE ? p->n_right : NULL;
+
+       /* simple needs */
+       n = ncnt(q->needs);
+       for (i = 0; i < n; i++) {
+#if 1
+               static int ncl[] =
+                   { 0, NASL, NBSL, NCSL, NDSL, NESL, NFSL, NGSL };
+               static int ncr[] =
+                   { 0, NASR, NBSR, NCSR, NDSR, NESR, NFSR, NGSR };
+               int j;
+
+               /* edges are already added */
+               if ((r = &p->n_regw[1+i])->r_class == -1) {
+                       r = p->n_regw;
+               } else {
+                       AddEdge(r, p->n_regw);
+                       addalledges(r);
+                       if (q->needs & NSPECIAL) {
+                               struct rspecial *rc;
+                               for (rc = nspecial(q); rc->op; rc++) {
+                                       if (rc->op != NEVER)
+                                               continue;
+                                       AddEdge(r, &ablock[rc->num]);
+                               }
+                       }
+               }
+               if (optype(o) != LTYPE && (q->needs & ncl[CLASS(r)]) == 0)
+                       addedge_r(p->n_left, r);
+               if (optype(o) == BITYPE && (q->needs & ncr[CLASS(r)]) == 0)
+                       addedge_r(p->n_right, r);
+               for (j = i + 1; j < n; j++) {
+                       if (p->n_regw[j+1].r_class == -1)
+                               continue;
+                       AddEdge(r, &p->n_regw[j+1]);
+               }
+#else
+               if ((r = &p->n_regw[1+i])->r_class == -1)
+                       continue;
+               addalledges(r);
+               if (optype(o) != LTYPE && (q->needs & NASL) == 0)
+                       addedge_r(p->n_left, r);
+               if (optype(o) == BITYPE && (q->needs & NASR) == 0)
+                       addedge_r(p->n_right, r);
+#endif
+       }
+
+       /* special needs */
+       if (q->needs & NSPECIAL) {
+               struct rspecial *rc;
+               for (rc = nspecial(q); rc->op; rc++) {
+                       switch (rc->op) {
+#define        ONLY(c,s) if (c) s(c, &ablock[rc->num])
+                       case NLEFT:
+                               addalledges(&ablock[rc->num]);
+                               ONLY(lr, moveadd);
+                               if (optype(o) != BITYPE)
+                                       break;
+                               /* FALLTHROUGH */
+                       case NORIGHT:
+                               addedge_r(p->n_right, &ablock[rc->num]);
+                               break;
+                       case NRIGHT:
+                               addalledges(&ablock[rc->num]);
+                               ONLY(rr, moveadd);
+                               /* FALLTHROUGH */
+                       case NOLEFT:
+                               addedge_r(p->n_left, &ablock[rc->num]);
+                               break;
+                       case NEVER:
+                               addalledges(&ablock[rc->num]);
+                               break;
+#undef ONLY
+                       }
+               }
+       }
+
+       if (o == ASSIGN) {
+               /* avoid use of unhandled registers */
+               if (p->n_left->n_op == REG &&
+                   !TESTBIT(validregs, regno(p->n_left)))
+                       lr = NULL;
+               if (p->n_right->n_op == REG &&
+                   !TESTBIT(validregs, regno(p->n_right)))
+                       rr = NULL;
+               /* needs special treatment */
+               if (lr && rr)
+                       moveadd(lr, rr);
+               if (lr && rv)
+                       moveadd(lr, rv);
+               if (rr && rv)
+                       moveadd(rr, rv);
+       } else if (callop(o)) {
+               int *c;
+
+               for (c = livecall(p); *c != -1; c++) {
+                       addalledges(ablock + *c);
+                       LIVEADD(*c);
+               }
+       } else if (q->rewrite & (RESC1|RESC2|RESC3)) {
+               if (lr && rr)
+                       AddEdge(lr, rr);
+       } else if (q->rewrite & RLEFT) {
+               if (lr && rv)
+                       moveadd(rv, lr), lrv = rv;
+               if (rv && rp)
+                       addedge_r(rp, rv);
+       } else if (q->rewrite & RRIGHT) {
+               if (rr && rv)
+                       moveadd(rv, rr), rrv = rv;
+               if (rv && lp)
+                       addedge_r(lp, rv);
+       }
+
+       switch (optype(o)) {
+       case BITYPE:
+               if (p->n_op == ASSIGN &&
+                   (p->n_left->n_op == TEMP || p->n_left->n_op == REG)) {
+                       /* only go down right node */
+                       insnwalk(p->n_right);
+               } else if (callop(o)) {
+                       insnwalk(p->n_left);
+                       /* Do liveness analysis on arguments (backwards) */
+                       argswalk(p->n_right);
+               } else if ((p->n_su & DORIGHT) == 0) {
+                       setlive(p->n_left, 1, lrv);
+                       insnwalk(p->n_right);
+                       setlive(p->n_left, 0, lrv);
+                       insnwalk(p->n_left);
+               } else {
+                       setlive(p->n_right, 1, rrv);
+                       insnwalk(p->n_left);
+                       setlive(p->n_right, 0, rrv);
+                       insnwalk(p->n_right);
+               }
+               break;
+
+       case UTYPE:
+               insnwalk(p->n_left);
+               break;
+
+       case LTYPE:
+               switch (o) {
+               case REG:
+                       if (!TESTBIT(validregs, regno(p)))
+                               break; /* never add moves */
+                       /* FALLTHROUGH */
+               case TEMP:
+                       i = regno(p);
+                       rr = (o == TEMP ? &nblock[i] :  &ablock[i]);
+                       if (rv != rr) {
+                               addalledges(rr);
+                               moveadd(rv, rr);
+                       }
+                       LIVEADD(i);
+                       break;
+
+               case OREG: /* XXX - not yet */
+                       break; 
+
+               default:
+                       break;
+               }
+               break;
+       }
+}
+
+static bittype **gen, **killed, **in, **out;
+
+struct notspill {
+       SLIST_ENTRY(notspill) link;
+       int spnum;
+};
+SLIST_HEAD(, notspill) nothead;
+
+static int
+innotspill(int n)
+{
+       struct notspill *nsp;
+
+       SLIST_FOREACH(nsp, &nothead, link)
+               if (nsp->spnum == n)
+                       return 1;
+       return 0;
+}
+
+static void
+addnotspill(int n)
+{
+       struct notspill *nsp;
+
+       if (innotspill(n))
+               return;
+       nsp = tmpalloc(sizeof(struct notspill));
+       nsp->spnum = n;
+       SLIST_INSERT_LAST(&nothead, nsp, link);
+}
+
+/*
+ * Found an extended assembler node, so growel out gen/killed nodes.
+ */
+static void
+xasmionize(NODE *p, void *arg)
+{
+       int bb = *(int *)arg;
+       int cw, b;
+
+       if (p->n_op == ICON && p->n_type == STRTY)
+               return; /* dummy end marker */
+
+       cw = xasmcode(p->n_name);
+       if (XASMVAL(cw) == 'n' /* || XASMVAL(cw) == 'm' */)
+               return; /* no flow analysis */
+       p = p->n_left;
+
+       if (XASMVAL(cw) == 'g' && p->n_op != TEMP && p->n_op != REG)
+               return; /* no flow analysis */
+
+       b = regno(p);
+       if (XASMVAL(cw) == 'r' && p->n_op == TEMP)
+               addnotspill(b);
+       if (XASMVAL(cw) == 'm') {
+               if (p->n_op == UMUL && p->n_left->n_op == TEMP) {
+                       p = p->n_left;
+                       b = regno(p);
+                       addnotspill(b);
+                       cw &= ~(XASMASG|XASMINOUT);
+               } else
+                       return;
+       }
+#define        MKTOFF(r)       ((r) - tempmin + MAXREGS)
+       if (XASMISOUT(cw)) {
+               if (p->n_op == TEMP) {
+                       BITCLEAR(gen[bb], MKTOFF(b));
+                       BITSET(killed[bb], MKTOFF(b));
+               } else if (p->n_op == REG) {
+                       BITCLEAR(gen[bb], b);
+                       BITSET(killed[bb], b);
+               } else
+                       uerror("bad xasm node type %d", p->n_op);
+       }
+       if (XASMISINP(cw)) {
+               if (p->n_op == TEMP) {
+                       BITSET(gen[bb], MKTOFF(b));
+               } else if (p->n_op == REG) {
+                       BITSET(gen[bb], b);
+               } else if (optype(p->n_op) != LTYPE) {
+                       if (XASMVAL(cw) == 'r')
+                               uerror("couldn't find available register");
+                       else
+                               uerror("bad xasm node type2");
+               }
+       }
+}
+
+#ifndef XASMCONSTREGS
+#define        XASMCONSTREGS(x) (-1)
+#endif
+
+/*
+ * Check that given constraints are valid.
+ */
+static void
+xasmconstr(NODE *p, void *arg)
+{
+       int i;
+
+       if (p->n_op == ICON && p->n_type == STRTY)
+               return; /* no constraints */
+
+       if (strcmp(p->n_name, "cc") == 0 || strcmp(p->n_name, "memory") == 0)
+               return;
+
+       for (i = 0; i < MAXREGS; i++)
+               if (strcmp(rnames[i], p->n_name) == 0) {
+                       addalledges(&ablock[i]);
+                       return;
+               }
+       if ((i = XASMCONSTREGS(p->n_name)) < 0)
+               comperr("unsupported xasm constraint %s", p->n_name);
+       addalledges(&ablock[i]);
+}
+
+#define        RUP(x) (((x)+NUMBITS-1)/NUMBITS)
+#define        SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
+#define        SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
+#define        SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
+#define        SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
+       if (t[i] != f[i]) v = 1
+#define        SETEMPTY(t,sz)  memset(t, 0, BIT2BYTE(sz))
+
+static int
+deldead(NODE *p, bittype *lvar)
+{
+       NODE *q;
+       int ty, rv = 0;
+
+#define        BNO(p) (regno(p) - tempmin+MAXREGS)
+       if (p->n_op == TEMP)
+               BITSET(lvar, BNO(p));
+       if (asgop(p->n_op) && p->n_left->n_op == TEMP &&
+           TESTBIT(lvar, BNO(p->n_left)) == 0) {
+               /*
+                * Not live, must delete the right tree at least 
+                * down to next statement with side effects.
+                */
+               BDEBUG(("DCE deleting temp %d\n", regno(p->n_left)));
+               nfree(p->n_left);
+               q = p->n_right;
+               *p = *q;
+               nfree(q);
+               rv = 1;
+       }
+       ty = optype(p->n_op);
+       if (ty != LTYPE)
+               rv |= deldead(p->n_left, lvar);
+       if (ty == BITYPE)
+               rv |= deldead(p->n_right, lvar);
+       return rv;
+}
+
+/*
+ * Ensure that the su field is empty before generating instructions.
+ */
+static void
+clrsu(NODE *p)
+{
+       int o = optype(p->n_op);
+
+       p->n_su = 0;
+       if (o != LTYPE)
+               clrsu(p->n_left);
+       if (o == BITYPE)
+               clrsu(p->n_right);
+}
+
+/*
+ * Do dead code elimination.
+ */
+static int
+dce(struct p2env *p2e)
+{
+       extern struct interpass prepole;
+       struct basicblock *bb;
+       struct interpass *ip;
+       NODE *p;
+       bittype *lvar;
+       int i, bbnum, fix = 0;
+
+#ifdef mach_vax
+       return 0;       /* XXX may need to recalc tree structure */
+                       /* eliminating assignments may create more OREGs */
+                       /* Fix by or/either break out ASSIGN or do this earlier */
+#endif
+
+       BDEBUG(("Entering DCE\n"));
+       /*
+        * Traverse over the basic blocks.
+        * if an assignment is found that writes to a temporary
+        * that is not live out, remove that assignment and its legs.
+        */
+       DLIST_INIT(&prepole, qelem);
+       BITALLOC(lvar, tmpalloc, xbits);
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               bbnum = bb->bbnum;
+               BBDEBUG(("DCE bblock %d, start %p last %p\n",
+                   bbnum, bb->first, bb->last));
+               SETCOPY(lvar, out[bbnum], i, xbits);
+               for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+                       if (ip->type == IP_NODE && deldead(ip->ip_node, lvar)) {
+                               if ((p = deluseless(ip->ip_node)) == NULL) {
+                                       struct interpass *previp;
+                                       struct basicblock *prevbb;
+
+                                       if (ip == bb->first && ip == bb->last) {
+                                               /* Remove basic block */
+                                               previp = DLIST_PREV(ip, qelem);
+                                               DLIST_REMOVE(ip, qelem);
+                                               prevbb = DLIST_PREV(bb, bbelem);
+                                               DLIST_REMOVE(bb, bbelem);
+                                               bb = prevbb;
+                                       } else if (ip == bb->first) {
+                                               bb->first =
+                                                   DLIST_NEXT(ip, qelem);
+                                               DLIST_REMOVE(ip, qelem);
+                                       } else if (ip == bb->last) {
+                                               previp = DLIST_PREV(ip, qelem);
+                                               DLIST_REMOVE(ip, qelem);
+                                               bb->last = previp;
+                                               bb = DLIST_PREV(bb, bbelem);
+                                       } else {
+                                               previp = DLIST_NEXT(ip, qelem);
+                                               DLIST_REMOVE(ip, qelem);
+                                               ip = previp;
+                                               fix++;
+                                               continue;
+                                       }
+                                       fix++;
+                                       BDEBUG(("bb %d: DCE ip %p deleted\n",
+                                           bbnum, ip));
+                                       break;
+                               } else while (!DLIST_ISEMPTY(&prepole, qelem)) {
+                                       struct interpass *tipp;
+
+                                       BDEBUG(("bb %d: DCE doing ip prepend\n", bbnum));
+                                       tipp = DLIST_NEXT(&prepole, qelem);
+                                       DLIST_REMOVE(tipp, qelem);
+                                       DLIST_INSERT_BEFORE(ip, tipp, qelem);
+                                       if (ip == bb->first)
+                                               bb->first = tipp;
+                                       fix++;
+                                       BDEBUG(("DCE ip prepended\n"));
+                               }
+                               if (ip->type == IP_NODE) {
+                                       clrsu(p);
+                                       geninsn(p, FOREFF);
+                                       nsucomp(p);
+                                       ip->ip_node = p;
+                               }
+                       }
+                       if (ip == bb->first)
+                               break;
+               }
+       }
+       BDEBUG(("DCE fix %d\n", fix));
+       return fix;
+}
+
+/*
+ * Set/clear long term liveness for regs and temps.
+ */
+static void
+unionize(NODE *p, int bb)
+{
+       int i, o, ty;
+
+       if ((o = p->n_op) == TEMP) {
+#ifdef notyet
+               for (i = 0; i < szty(p->n_type); i++) {
+                       BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
+               }
+#else
+               i = 0;
+               BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
+#endif
+       } else if (VALIDREG(p)) {
+               BITSET(gen[bb], regno(p));
+       }
+       if (asgop(o)) {
+               if (p->n_left->n_op == TEMP) {
+                       int b = regno(p->n_left) - tempmin+MAXREGS;
+#ifdef notyet
+                       for (i = 0; i < szty(p->n_type); i++) {
+                               BITCLEAR(gen[bb], (b+i));
+                               BITSET(killed[bb], (b+i));
+                       }
+#else
+                       i = 0;
+                       BITCLEAR(gen[bb], (b+i));
+                       BITSET(killed[bb], (b+i));
+#endif
+                       unionize(p->n_right, bb);
+                       return;
+               } else if (VALIDREG(p->n_left)) {
+                       int b = regno(p->n_left);
+                       BITCLEAR(gen[bb], b);
+                       BITSET(killed[bb], b);
+                       unionize(p->n_right, bb);
+                       return;
+               }
+       }
+       ty = optype(o);
+       if (ty != LTYPE)
+               unionize(p->n_left, bb);
+       if (ty == BITYPE)
+               unionize(p->n_right, bb);
+}
+
+/*
+ * Do variable liveness analysis.  Only analyze the long-lived 
+ * variables, and save the live-on-exit temporaries in a bit-field
+ * at the end of each basic block. This bit-field is later used
+ * when doing short-range liveness analysis in Build().
+ */
+static void
+LivenessAnalysis(struct p2env *p2e)
+{
+       struct basicblock *bb;
+       struct interpass *ip;
+       int bbnum;
+
+       /*
+        * generate the gen-killed sets for all basic blocks.
+        */
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               bbnum = bb->bbnum;
+               for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+                       /* gen/killed is 'p', this node is 'n' */
+                       if (ip->type == IP_NODE) {
+                               if (ip->ip_node->n_op == XASM)
+                                       flist(ip->ip_node->n_left,
+                                           xasmionize, &bbnum);
+                               else
+                                       unionize(ip->ip_node, bbnum);
+                       }
+                       if (ip == bb->first)
+                               break;
+               }
+               memcpy(in[bbnum], gen[bbnum], BIT2BYTE(xbits));
+#ifdef PCC_DEBUG
+#define        PRTRG(x) printf("%d ", x < MAXREGS ? x : x + tempmin-MAXREGS)
+               if (r2debug) {
+                       int i;
+
+                       printf("basic block %d\ngen: ", bbnum);
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(gen[bbnum], i))
+                                       PRTRG(i);
+                       printf("\nkilled: ");
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(killed[bbnum], i))
+                                       PRTRG(i);
+                       printf("\n");
+               }
+#endif
+       }
+}
+
+
+/*
+ * Build the set of interference edges and adjacency list.
+ */
+static void
+Build(struct p2env *p2e)
+{
+       struct interpass *ipole = &p2e->ipole;
+       struct basicblock bbfake;
+       struct interpass *ip;
+       struct basicblock *bb;
+       bittype *saved;
+       int i, j, again;
+
+       if (xtemps == 0) {
+               /*
+                * No basic block splitup is done if not optimizing,
+                * so fake one basic block to keep the liveness analysis 
+                * happy.
+                */
+               p2e->nbblocks = 1;
+               bbfake.bbnum = 0;
+               bbfake.last = DLIST_PREV(ipole, qelem);
+               bbfake.first = DLIST_NEXT(ipole, qelem);
+               DLIST_INIT(&p2e->bblocks, bbelem);
+               DLIST_INSERT_AFTER(&p2e->bblocks, &bbfake, bbelem);
+               SLIST_INIT(&bbfake.child);
+       }
+
+       /* Just fetch space for the temporaries from stack */
+       gen = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+       killed = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+       in = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+       out = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+       for (i = 0; i < p2e->nbblocks; i++) {
+               BITALLOC(gen[i],tmpalloc,xbits);
+               BITALLOC(killed[i],tmpalloc,xbits);
+               BITALLOC(in[i],tmpalloc,xbits);
+               BITALLOC(out[i],tmpalloc,xbits);
+       }
+       BITALLOC(saved,tmpalloc,xbits);
+
+       SLIST_INIT(&nothead);
+livagain:
+       LivenessAnalysis(p2e);
+
+       /* register variable temporaries are live */
+       for (i = 0; i < NPERMREG-1; i++) {
+               if (nsavregs[i])
+                       continue;
+               BITSET(out[p2e->nbblocks-1], (i+MAXREGS));
+               for (j = i+1; j < NPERMREG-1; j++) {
+                       if (nsavregs[j])
+                               continue;
+                       AddEdge(&nblock[i+tempmin], &nblock[j+tempmin]);
+               }
+       }
+
+       /* do liveness analysis on basic block level */
+       do {
+               struct cfgnode *cn;
+               again = 0;
+               /* XXX - loop should be in reversed execution-order */
+               DLIST_FOREACH_REVERSE(bb, &p2e->bblocks, bbelem) {
+                       i = bb->bbnum;
+                       SETCOPY(saved, out[i], j, xbits);
+                       SLIST_FOREACH(cn, &bb->child, chld) {
+                               SETSET(out[i], in[cn->bblock->bbnum], j, xbits);
+                       }
+                       SETCMP(again, saved, out[i], j, xbits);
+                       SETCOPY(saved, in[i], j, xbits);
+                       SETCOPY(in[i], out[i], j, xbits);
+                       SETCLEAR(in[i], killed[i], j, xbits);
+                       SETSET(in[i], gen[i], j, xbits);
+                       SETCMP(again, saved, in[i], j, xbits);
+               }
+       } while (again);
+
+#ifdef PCC_DEBUG
+       if (r2debug) {
+               DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+                       printf("basic block %d\nin: ", bb->bbnum);
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(in[bb->bbnum], i))
+                                       PRTRG(i);
+                       printf("\nout: ");
+                       for (i = 0; i < xbits; i++)
+                               if (TESTBIT(out[bb->bbnum], i))
+                                       PRTRG(i);
+                       printf("\n");
+               }
+       }
+#endif
+       if (xtemps && xdce) {
+               /*
+                * Do dead code elimination by using live out.
+                * Ignores if any variable read from is marked volatile,
+                * but what it should do is unspecified anyway.
+                * Liveness Analysis should be done in optim2 instead.
+                *
+                * This should recalculate the basic block structure.
+                */
+               if (dce(p2e)) {
+                       /* Clear bitfields */
+                       for (i = 0; i < p2e->nbblocks; i++) {
+                               SETEMPTY(gen[i],xbits);
+                               SETEMPTY(killed[i],xbits);
+                               SETEMPTY(in[i],xbits);
+                               SETEMPTY(out[i],xbits);
+                       }
+                       SETEMPTY(saved,xbits);
+                       goto livagain;
+               }
+       }
+
+       DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+               RDEBUG(("liveadd bb %d\n", bb->bbnum));
+               i = bb->bbnum;
+               for (j = 0; j < xbits; j += NUMBITS)
+                       live[j/NUMBITS] = 0;
+               SETCOPY(live, out[i], j, xbits);
+               for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+                       if (ip->type == IP_NODE) {
+                               if (ip->ip_node->n_op == XASM) {
+                                       flist(ip->ip_node->n_right,
+                                           xasmconstr, 0);
+                                       listf(ip->ip_node->n_left, setxarg);
+                                       listf(ip->ip_node->n_left, delcl);
+                               } else
+                                       insnwalk(ip->ip_node);
+                       }
+                       if (ip == bb->first)
+                               break;
+               }
+       }
+
+#ifdef PCC_DEBUG
+       if (r2debug) {
+               struct AdjSet *w;
+               ADJL *x;
+               REGW *y;
+               MOVL *m;
+
+               printf("Interference edges\n");
+               for (i = 0; i < HASHSZ; i++) {
+                       if ((w = edgehash[i]) == NULL)
+                               continue;
+                       for (; w; w = w->next)
+                               printf("%d <-> %d\n", ASGNUM(w->u), ASGNUM(w->v));
+               }
+               printf("Degrees\n");
+               DLIST_FOREACH(y, &initial, link) {
+                       printf("%d (%c): trivial [%d] ", ASGNUM(y),
+                           CLASS(y)+'@', trivially_colorable(y));
+                       i = 0;
+                       for (x = ADJLIST(y); x; x = x->r_next) {
+                               if (ONLIST(x->a_temp) != &selectStack &&
+                                   ONLIST(x->a_temp) != &coalescedNodes)
+                                       printf("%d ", ASGNUM(x->a_temp));
+                               else
+                                       printf("(%d) ", ASGNUM(x->a_temp));
+                               i++;
+                       }
+                       printf(": n=%d\n", i);
+               }
+               printf("Move nodes\n");
+               DLIST_FOREACH(y, &initial, link) {
+                       if (MOVELIST(y) == NULL)
+                               continue;
+                       printf("%d: ", ASGNUM(y));
+                       for (m = MOVELIST(y); m; m = m->next) {
+                               REGW *yy = m->regm->src == y ?
+                                   m->regm->dst : m->regm->src;
+                               printf("%d ", ASGNUM(yy));
+                       }
+                       printf("\n");
+               }
+       }
+#endif
+
+}
+
+static void
+EnableMoves(REGW *n)
+{
+       MOVL *l;
+       REGM *m;
+
+       for (l = MOVELIST(n); l; l = l->next) {
+               m = l->regm;
+               if (m->queue != ACTIVE)
+                       continue;
+               DLIST_REMOVE(m, link);
+               PUSHMLIST(m, worklistMoves, WLIST);
+       }
+}
+
+static void
+EnableAdjMoves(REGW *nodes)
+{
+       ADJL *w;
+       REGW *n;
+
+       EnableMoves(nodes);
+       for (w = ADJLIST(nodes); w; w = w->r_next) {
+               n = w->a_temp;
+               if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
+                       continue;
+               EnableMoves(w->a_temp);
+       }
+}
+
+/*
+ * Decrement the degree of node w for class c.
+ */
+static void
+DecrementDegree(REGW *w, int c)
+{
+       int wast;
+
+#ifdef PCC_DEBUG
+       RRDEBUG(("DecrementDegree: w %d, c %d\n", ASGNUM(w), c));
+#endif
+
+       wast = trivially_colorable(w);
+       if (NCLASS(w, c) > 0)
+               NCLASS(w, c)--;
+       if (wast == trivially_colorable(w))
+               return;
+
+       EnableAdjMoves(w);
+       DELWLIST(w);
+       ONLIST(w) = 0;
+       if (MoveRelated(w)) {
+               PUSHWLIST(w, freezeWorklist);
+       } else {
+               PUSHWLIST(w, simplifyWorklist);
+       }
+}
+
+static void
+Simplify(void)
+{
+       REGW *w;
+       ADJL *l;
+
+       w = POPWLIST(simplifyWorklist);
+       PUSHWLIST(w, selectStack);
+#ifdef PCC_DEBUG
+       RDEBUG(("Simplify: node %d class %d\n", ASGNUM(w), w->r_class));
+#endif
+
+       l = w->r_adjList;
+       for (; l; l = l->r_next) {
+               if (ONLIST(l->a_temp) == &selectStack ||
+                   ONLIST(l->a_temp) == &coalescedNodes)
+                       continue;
+               DecrementDegree(l->a_temp, w->r_class);
+       }
+}
+
+static REGW *
+GetAlias(REGW *n)
+{
+       if (ONLIST(n) == &coalescedNodes)
+               return GetAlias(ALIAS(n));
+       return n;
+}
+
+static int
+OK(REGW *t, REGW *r)
+{
+#ifdef PCC_DEBUG
+       RDEBUG(("OK: t %d CLASS(t) %d adjSet(%d,%d)=%d\n",
+           ASGNUM(t), CLASS(t), ASGNUM(t), ASGNUM(r), adjSet(t, r)));
+
+       if (r2debug > 1) {
+               ADJL *w;
+               int ndeg = 0;
+               printf("OK degree: ");
+               for (w = ADJLIST(t); w; w = w->r_next) {
+                       if (ONLIST(w->a_temp) != &selectStack &&
+                           ONLIST(w->a_temp) != &coalescedNodes)
+                               printf("%c%d ", CLASS(w->a_temp)+'@',
+                                   ASGNUM(w->a_temp)), ndeg++;
+                       else
+                               printf("(%d) ", ASGNUM(w->a_temp));
+               }
+               printf("\n");
+#if 0
+               if (ndeg != DEGREE(t) && DEGREE(t) >= 0)
+                       printf("!!!ndeg %d != DEGREE(t) %d\n", ndeg, DEGREE(t));
+#endif
+       }
+#endif
+
+       if (trivially_colorable(t) || ONLIST(t) == &precolored || 
+           (adjSet(t, r) || !aliasmap(CLASS(t), COLOR(r))))/* XXX - check aliasmap */
+               return 1;
+       return 0;
+}
+
+static int
+adjok(REGW *v, REGW *u)
+{
+       ADJL *w;
+       REGW *t;
+
+       RDEBUG(("adjok\n"));
+       for (w = ADJLIST(v); w; w = w->r_next) {
+               t = w->a_temp;
+               if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes)
+                       continue;
+               if (OK(t, u) == 0)
+                       return 0;
+       }
+       RDEBUG(("adjok returns OK\n"));
+       return 1;
+}
+
+/*
+ * Do a conservative estimation of whether two temporaries can 
+ * be coalesced.  This is "Briggs-style" check.
+ * Neither u nor v is precolored when called.
+ */
+static int
+Conservative(REGW *u, REGW *v)
+{
+       ADJL *w, *ww;
+       REGW *n;
+       int xncl[NUMCLASS+1], mcl = 0, j;
+
+       for (j = 0; j < NUMCLASS+1; j++)
+               xncl[j] = 0;
+       /*
+        * Increment xncl[class] up to K for each class.
+        * If all classes has reached K then check colorability and return.
+        */
+       for (w = ADJLIST(u); w; w = w->r_next) {
+               n = w->a_temp;
+               if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
+                       continue;
+               if (xncl[CLASS(n)] == regK[CLASS(n)])
+                       continue;
+               if (!trivially_colorable(n) || ONLIST(n) == &precolored)
+                       xncl[CLASS(n)]++;
+               if (xncl[CLASS(n)] < regK[CLASS(n)])
+                       continue;
+               if (++mcl == NUMCLASS)
+                       goto out; /* cannot get more out of it */
+       }
+       for (w = ADJLIST(v); w; w = w->r_next) {
+               n = w->a_temp;
+               if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
+                       continue;
+               if (xncl[CLASS(n)] == regK[CLASS(n)])
+                       continue;
+               /* ugly: have we been here already? */
+               for (ww = ADJLIST(u); ww; ww = ww->r_next)
+                       if (ww->a_temp == n)
+                               break;
+               if (ww)
+                       continue;
+               if (!trivially_colorable(n) || ONLIST(n) == &precolored)
+                       xncl[CLASS(n)]++;
+               if (xncl[CLASS(n)] < regK[CLASS(n)])
+                       continue;
+               if (++mcl == NUMCLASS)
+                       break;
+       }
+out:   j = trivially_colorable_p(CLASS(u), xncl);
+       return j;
+}
+
+static void
+AddWorkList(REGW *w)
+{
+
+       if (ONLIST(w) != &precolored && !MoveRelated(w) &&
+           trivially_colorable(w)) {
+               DELWLIST(w);
+               PUSHWLIST(w, simplifyWorklist);
+       }
+}
+
+static void
+Combine(REGW *u, REGW *v)
+{
+       MOVL *m;
+       ADJL *l;
+       REGW *t;
+
+#ifdef PCC_DEBUG
+       RDEBUG(("Combine (%d,%d)\n", ASGNUM(u), ASGNUM(v)));
+#endif
+
+       if (ONLIST(v) == &freezeWorklist) {
+               DELWLIST(v);
+       } else {
+               DELWLIST(v);
+       }
+       PUSHWLIST(v, coalescedNodes);
+       ALIAS(v) = u;
+#ifdef PCC_DEBUG
+       if (r2debug) { 
+               printf("adjlist(%d): ", ASGNUM(v));
+               for (l = ADJLIST(v); l; l = l->r_next)
+                       printf("%d ", l->a_temp->nodnum);
+               printf("\n");
+       }
+#endif
+#if 1
+{
+       MOVL *m0 = MOVELIST(v);
+
+       for (m0 = MOVELIST(v); m0; m0 = m0->next) {
+               for (m = MOVELIST(u); m; m = m->next)
+                       if (m->regm == m0->regm)
+                               break; /* Already on list */
+               if (m)
+                       continue; /* already on list */
+               MOVELISTADD(u, m0->regm);
+       }
+}
+#else
+
+       if ((m = MOVELIST(u))) {
+               while (m->next)
+                       m = m->next;
+               m->next = MOVELIST(v);
+       } else
+               MOVELIST(u) = MOVELIST(v);
+#endif
+       EnableMoves(v);
+       for (l = ADJLIST(v); l; l = l->r_next) {
+               t = l->a_temp;
+               if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes)
+                       continue;
+               /* Do not add edge if u cannot affect the colorability of t */
+               /* XXX - check aliasmap */
+               if (ONLIST(u) != &precolored || aliasmap(CLASS(t), COLOR(u)))
+                       AddEdge(t, u);
+               DecrementDegree(t, CLASS(v));
+       }
+       if (!trivially_colorable(u) && ONLIST(u) == &freezeWorklist) {
+               DELWLIST(u);
+               PUSHWLIST(u, spillWorklist);
+       }
+#ifdef PCC_DEBUG
+       if (r2debug) {
+               ADJL *w;
+               printf("Combine %d class (%d): ", ASGNUM(u), CLASS(u));
+               for (w = ADJLIST(u); w; w = w->r_next) {
+                       if (ONLIST(w->a_temp) != &selectStack &&
+                           ONLIST(w->a_temp) != &coalescedNodes)
+                               printf("%d ", ASGNUM(w->a_temp));
+                       else
+                               printf("(%d) ", ASGNUM(w->a_temp));
+               }
+               printf("\n");
+       }
+#endif
+}
+
+static void
+Coalesce(void)
+{
+       REGM *m;
+       REGW *x, *y, *u, *v;
+
+       m = POPMLIST(worklistMoves);
+       x = GetAlias(m->src);
+       y = GetAlias(m->dst);
+
+       if (ONLIST(y) == &precolored)
+               u = y, v = x;
+       else
+               u = x, v = y;
+
+#ifdef PCC_DEBUG
+       RDEBUG(("Coalesce: src %d dst %d u %d v %d x %d y %d\n",
+           ASGNUM(m->src), ASGNUM(m->dst), ASGNUM(u), ASGNUM(v),
+           ASGNUM(x), ASGNUM(y)));
+#endif
+
+       if (CLASS(m->src) != CLASS(m->dst))
+               comperr("Coalesce: src class %d, dst class %d",
+                   CLASS(m->src), CLASS(m->dst));
+
+       if (u == v) {
+               RDEBUG(("Coalesce: u == v\n"));
+               PUSHMLIST(m, coalescedMoves, COAL);
+               AddWorkList(u);
+       } else if (ONLIST(v) == &precolored || adjSet(u, v)) {
+               RDEBUG(("Coalesce: constrainedMoves\n"));
+               PUSHMLIST(m, constrainedMoves, CONSTR);
+               AddWorkList(u);
+               AddWorkList(v);
+       } else if ((ONLIST(u) == &precolored && adjok(v, u)) ||
+           (ONLIST(u) != &precolored && Conservative(u, v))) {
+               RDEBUG(("Coalesce: Conservative\n"));
+               PUSHMLIST(m, coalescedMoves, COAL);
+               Combine(u, v);
+               AddWorkList(u);
+       } else {
+               RDEBUG(("Coalesce: activeMoves\n"));
+               PUSHMLIST(m, activeMoves, ACTIVE);
+       }
+}
+
+static void
+coalasg(NODE *p, void *arg)
+{
+       NODE *l;
+       REGW *u;
+
+       if (p->n_op != ASSIGN || p->n_regw == NULL)
+               return;
+       l = p->n_left;
+       if (l->n_op == TEMP)
+               u = &nblock[regno(l)];
+       else if (l->n_op == REG)
+               u = &ablock[regno(l)];
+       else
+               return;
+
+       Combine(u, p->n_regw);
+       AddWorkList(u);
+}
+
+/*
+ * Coalesce assign to a left reg with the assign temp node itself.
+ * This has to be done before anything else.
+ */
+static void
+Coalassign(struct p2env *p2e)
+{
+       struct interpass *ip;
+
+       DLIST_FOREACH(ip, &p2env.ipole, qelem) {
+               if (ip->type == IP_NODE)
+                       walkf(ip->ip_node, coalasg, 0);
+       }
+}
+
+static void
+FreezeMoves(REGW *u)
+{
+       MOVL *w, *o;
+       REGM *m;
+       REGW *z;
+       REGW *x, *y, *v;
+
+       for (w = MOVELIST(u); w; w = w->next) {
+               m = w->regm;
+               if (m->queue != WLIST && m->queue != ACTIVE)
+                       continue;
+               x = m->src;
+               y = m->dst;
+               if (GetAlias(y) == GetAlias(u))
+                       v = GetAlias(x);
+               else
+                       v = GetAlias(y);
+#ifdef PCC_DEBUG
+               RDEBUG(("FreezeMoves: u %d (%d,%d) v %d\n",
+                   ASGNUM(u),ASGNUM(x),ASGNUM(y),ASGNUM(v)));
+#endif
+               DLIST_REMOVE(m, link);
+               PUSHMLIST(m, frozenMoves, FROZEN);
+               if (ONLIST(v) != &freezeWorklist)
+                       continue;
+               for (o = MOVELIST(v); o; o = o->next)
+                       if (o->regm->queue == WLIST || o->regm->queue == ACTIVE)
+                               break;
+               if (o == NULL) {
+                       z = v;
+                       DELWLIST(z);
+                       PUSHWLIST(z, simplifyWorklist);
+               }
+       }
+}
+
+static void
+Freeze(void)
+{
+       REGW *u;
+
+       /*
+        * To find out:
+        * Check if the moves to freeze have exactly the same 
+        * interference edges.  If they do, coalesce them instead, it
+        * may free up other nodes that they interfere with.
+        */
+
+       /*
+        * Select nodes to freeze first by using following criteria:
+        * - Trivially colorable
+        * - Single or few moves to less trivial nodes.
+        */
+       DLIST_FOREACH(u, &freezeWorklist, link) {
+               if (u >= &nblock[tempmax] || u < &nblock[tempmin])
+                       continue; /* No short range temps */
+               if (!trivially_colorable(u))
+                       continue; /* Prefer colorable nodes */
+               /* Check for at most two move-related nodes */
+               if (u->r_moveList->next && u->r_moveList->next->next)
+                       continue;
+               /* Ok, remove node */
+               DLIST_REMOVE(u, link);
+               u->r_onlist = 0;
+               break;
+       }
+       if (u == &freezeWorklist) /* Nothing matched criteria, just take one */
+               u = POPWLIST(freezeWorklist);
+       PUSHWLIST(u, simplifyWorklist);
+#ifdef PCC_DEBUG
+       RDEBUG(("Freeze %d\n", ASGNUM(u)));
+#endif
+       FreezeMoves(u);
+}
+
+static void
+SelectSpill(void)
+{
+       REGW *w;
+
+       RDEBUG(("SelectSpill\n"));
+#ifdef PCC_DEBUG
+       if (r2debug)
+               DLIST_FOREACH(w, &spillWorklist, link)
+                       printf("SelectSpill: %d\n", ASGNUM(w));
+#endif
+
+       /* First check if we can spill register variables */
+       DLIST_FOREACH(w, &spillWorklist, link) {
+               if (w >= &nblock[tempmin] && w < &nblock[basetemp])
+                       break;
+       }
+
+       RRDEBUG(("SelectSpill: trying longrange\n"));
+       if (w == &spillWorklist) {
+               /* try to find another long-range variable */
+               DLIST_FOREACH(w, &spillWorklist, link) {
+                       if (innotspill(w - nblock))
+                               continue;
+                       if (w >= &nblock[tempmin] && w < &nblock[tempmax])
+                               break;
+               }
+       }
+
+       if (w == &spillWorklist) {
+               RRDEBUG(("SelectSpill: trying not leaf\n"));
+               /* no heuristics, just fetch first element */
+               /* but not if leaf */
+               DLIST_FOREACH(w, &spillWorklist, link) {
+                       if (w->r_nclass[0] == 0)
+                               break;
+               }
+       }
+
+       if (w == &spillWorklist) {
+               /* Eh, only leaves :-/ Try anyway */
+               /* May not be useable */
+               w = DLIST_NEXT(&spillWorklist, link);
+               RRDEBUG(("SelectSpill: need leaf\n"));
+       }
+        DLIST_REMOVE(w, link);
+
+       PUSHWLIST(w, simplifyWorklist);
+#ifdef PCC_DEBUG
+       RDEBUG(("Freezing node %d\n", ASGNUM(w)));
+#endif
+       FreezeMoves(w);
+}
+
+/*
+ * Set class on long-lived temporaries based on its type.
+ */
+static void
+traclass(NODE *p, void *arg)
+{
+       REGW *nb;
+
+       if (p->n_op != TEMP)
+               return;
+
+       nb = &nblock[regno(p)];
+       if (CLASS(nb) == 0)
+               CLASS(nb) = gclass(p->n_type);
+}
+
+static void
+paint(NODE *p, void *arg)
+{
+       struct optab *q;
+       REGW *w, *ww;
+       int i;
+
+#ifdef notyet
+       /* XXX - trashes rewrite of trees (short) */
+       if (!DLIST_ISEMPTY(&spilledNodes, link)) {
+               p->n_reg = 0;
+               return;
+       }
+#endif
+       if (p->n_regw != NULL) {
+               /* Must color all allocated regs also */
+               ww = w = p->n_regw;
+               q = &table[TBLIDX(p->n_su)];
+               p->n_reg = COLOR(w);
+               w++;
+               if (q->needs & ALLNEEDS)
+                       for (i = 0; i < ncnt(q->needs); i++) {
+                               if (w->r_class == -1)
+                                       p->n_reg |= ENCRA(COLOR(ww), i);
+                               else
+                                       p->n_reg |= ENCRA(COLOR(w), i);
+                               w++;
+                       }
+#ifdef notdef
+               if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
+                   DECRA(p->n_reg, 0) != regno(p->n_left))
+                       comperr("paint: %p clashing ASSIGN moves; %d != %d", p,
+                           DECRA(p->n_reg, 0), regno(p->n_left));
+#endif
+       } else
+               p->n_reg = -1;
+       if (p->n_op == TEMP) {
+               REGW *nb = &nblock[regno(p)];
+               regno(p) = COLOR(nb);
+               if (TCLASS(p->n_su) == 0)
+                       SCLASS(p->n_su, CLASS(nb));
+               p->n_op = REG;
+               setlval(p, 0);
+       }
+}
+
+/*
+ * See if this node have a move that has been removed in Freeze
+ * but as we can make use of anyway.
+ */
+static int
+colfind(int okColors, REGW *r)
+{
+       REGW *w;
+       MOVL *m;
+       int c;
+
+       for (m = MOVELIST(r); m; m = m->next) {
+               if ((w = m->regm->src) == r)
+                       w = m->regm->dst;
+               w = GetAlias(w);
+               if (ONLIST(w) != &coloredNodes && ONLIST(w) != &precolored)
+                       continue; /* Not yet colored */
+               if (CLASS(w) != CLASS(r))
+                       comperr("colfind: move between classes");
+
+               for (c = 0; c < regK[CLASS(w)]; c++)
+                       if (color2reg(c, CLASS(w)) == COLOR(w))
+                               break;
+               if (c == regK[CLASS(w)])
+                       comperr("colfind: out of reg number");
+
+               if (((1 << c) & okColors) == 0) {
+                       RDEBUG(("colfind: Failed coloring as %d\n", ASGNUM(w)));
+                       continue;
+               }
+               RDEBUG(("colfind: Recommend color from %d\n", ASGNUM(w)));
+               return COLOR(w);
+       }
+       return color2reg(ffs(okColors)-1, CLASS(r));
+}
+
+static void
+AssignColors(struct interpass *ip)
+{
+       struct interpass *ip2;
+       int okColors, c;
+       REGW *o, *w;
+       ADJL *x;
+
+       RDEBUG(("AssignColors\n"));
+       while (!WLISTEMPTY(selectStack)) {
+               w = POPWLIST(selectStack);
+               okColors = classmask(CLASS(w));
+#ifdef PCC_DEBUG
+               RDEBUG(("classmask av %d, class %d: %x\n",
+                   w->nodnum, CLASS(w), okColors));
+#endif
+
+               for (x = ADJLIST(w); x; x = x->r_next) {
+                       o = GetAlias(x->a_temp);
+#ifdef PCC_DEBUG
+                       RRDEBUG(("Adj(%d): %d (%d)\n",
+                           ASGNUM(w), ASGNUM(o), ASGNUM(x->a_temp)));
+#endif
+
+                       if (ONLIST(o) == &coloredNodes ||
+                           ONLIST(o) == &precolored) {
+                               c = aliasmap(CLASS(w), COLOR(o));
+                               RRDEBUG(("aliasmap in class %d by color %d: "
+                                   "%x, okColors %x\n",
+                                   CLASS(w), COLOR(o), c, okColors));
+
+                               okColors &= ~c;
+                       }
+               }
+               if (okColors == 0) {
+                       PUSHWLIST(w, spilledNodes);
+#ifdef PCC_DEBUG
+                       RDEBUG(("Spilling node %d\n", ASGNUM(w)));
+#endif
+               } else {
+                       COLOR(w) = colfind(okColors, w);
+                       PUSHWLIST(w, coloredNodes);
+#ifdef PCC_DEBUG
+                       RDEBUG(("Coloring %d with %s, free %x\n",
+                           ASGNUM(w), rnames[COLOR(w)], okColors));
+#endif
+               }
+       }
+       DLIST_FOREACH(w, &coalescedNodes, link) {
+               REGW *ww = GetAlias(w);
+               COLOR(w) = COLOR(ww);
+               if (ONLIST(ww) == &spilledNodes) {
+#ifdef PCC_DEBUG
+                       RDEBUG(("coalesced node %d spilled\n", w->nodnum));
+#endif
+                       ww = DLIST_PREV(w, link);
+                       DLIST_REMOVE(w, link);
+                       PUSHWLIST(w, spilledNodes);
+                       w = ww;
+               } else {
+#ifdef PCC_DEBUG
+                       RDEBUG(("Giving coalesced node %d color %s\n",
+                           w->nodnum, rnames[COLOR(w)]));
+#endif
+               }
+       }
+
+#ifdef PCC_DEBUG
+       if (r2debug)
+               DLIST_FOREACH(w, &coloredNodes, link)
+                       printf("%d: color %s\n", ASGNUM(w), rnames[COLOR(w)]);
+#endif
+       if (DLIST_ISEMPTY(&spilledNodes, link)) {
+               DLIST_FOREACH(ip2, ip, qelem)
+                       if (ip2->type == IP_NODE)
+                               walkf(ip2->ip_node, paint, 0);
+       }
+}
+
+static REGW *spole, *longsp;
+/*
+ * Store all spilled nodes in memory by fetching a temporary on the stack.
+ * Will never end up here if not optimizing.
+ */
+static void
+longtemp(NODE *p, void *arg)
+{
+       REGW *w;
+
+       if (p->n_op != TEMP)
+               return;
+       /* XXX - should have a bitmask to find temps to convert */
+       DLIST_FOREACH(w, spole, link) {
+               if (w != &nblock[regno(p)])
+                       continue;
+#ifdef MYLONGTEMP
+               MYLONGTEMP(p, w);
+#endif
+               if (w->r_class == 0) {
+                       w->r_color = freetemp(szty(p->n_type));
+                       w->r_class = FPREG; /* XXX - assumption? */
+               }
+               storemod(p, w->r_color, w->r_class);
+               break;
+       }
+}
+
+/*
+ * Check if this node is just something directly addressable.
+ * XXX - should use target canaddr() when we knows that it is OK
+ * for all targets. Can currently be a little too optimistic.
+ */
+static int
+regcanaddr(NODE *p)
+{
+       int o = p->n_op;
+
+       if (o==NAME || o==ICON || o==OREG )
+               return 1;
+       if (o == UMUL) {
+               if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
+                       return 1;
+               if ((p->n_left->n_op == PLUS || p->n_left->n_op == MINUS) &&
+                   (p->n_left->n_left->n_op == REG ||
+                    p->n_left->n_left->n_op == TEMP) &&
+                   p->n_left->n_right->n_op == ICON)
+                       return 1;
+       }
+       return 0;
+}
+
+static struct interpass *cip;
+
+static NODE *
+shstore(NODE *p, struct interpass *ipp, REGW *w)
+{
+       struct interpass *ip;
+       int off;
+       NODE *l;
+
+       off = freetemp(szty(p->n_type));
+       l = storenode(p->n_type, off);
+
+       ip = ipnode(mkbinode(ASSIGN, storenode(p->n_type, off), p, p->n_type));
+       DLIST_INSERT_BEFORE(ipp, ip, qelem);
+       DLIST_REMOVE(w, link);
+       return l;
+}
+
+/*
+ * Rewrite a tree by storing a variable in memory.
+ * This code would work better if the SU computations were smarter.
+ * XXX - must check if basic block structure is destroyed!
+ *
+ * 1) Ensure that both left & right are directly addressable.
+ * 2) Save interfering long-term temporaries.
+ * 3) If node itself not addressable, store the node itself.
+ * 4) Store the parent.
+ * 5) ...HELP!!??!!
+ *
+ * It might be a better idea to start with 3) or 4) first, but that will
+ * make the code more complicated and I'm not sure it's worth it.
+ */
+static int
+shorttemp(NODE *p, NODE *parent, REGW *w)
+{
+       struct interpass *nip;
+       ADJL *ll;
+       NODE *l, *r;
+       int off, i, nc;
+
+       if (p->n_regw == NULL)
+               goto down;
+
+       /* Check if this the correct node. */
+       nc = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
+       for (i = 0; i < nc + 1; i++)
+               if ((p->n_regw + i) == w)
+                       break;
+
+       if (i == nc + 1) {
+down:          switch (optype(p->n_op)) {
+               case BITYPE:
+                       if (shorttemp(p->n_left, p, w) == 0)
+                               return shorttemp(p->n_right, p, w);
+                       return 1;
+               case UTYPE:
+                       return shorttemp(p->n_left, p, w);
+               case LTYPE:
+                       return 0;
+               }
+       }
+
+       RDEBUG(("Node %d (%p) to store\n", ASGNUM(w), p));
+       /* ensure that both left and right are addressable */
+       if (!regcanaddr(p) && !callop(p->n_op)) {
+               /* this is neither leaf nor addressable */
+               if (p->n_op != ASSIGN && !regcanaddr(p->n_left)) {
+                       /* store left */
+                       p->n_left = shstore(p->n_left, cip, w);
+                       RDEBUG(("Node %d stored left\n", ASGNUM(w)));
+                       return 1;
+               } else if (optype(p->n_op) == BITYPE &&
+                   !regcanaddr(p->n_right)) {
+                       /* store right */
+                       p->n_right = shstore(p->n_right, cip, w);
+                       RDEBUG(("Node %d stored right\n", ASGNUM(w)));
+                       return 1;
+               }
+       }
+       /* Store long-term temps that interferes */
+       ll = w->r_adjList;
+       for (; ll; ll = ll->r_next) {
+               if (ll->a_temp < &nblock[tempmax] &&
+                   ll->a_temp >= &nblock[tempmin]) {
+                       longsp = ll->a_temp;
+                       RDEBUG(("Stored long %d\n", ASGNUM(longsp)));
+                       return 1; /* try again */
+               }
+       }
+
+       if (regcanaddr(p)) {
+               /* The node to spill is addressable, spill parent */
+               if (parent == NULL)
+                       comperr("cannot spill TOP node!");
+               p = parent;
+       }
+       off = freetemp(szty(p->n_type));
+       l = storenode(p->n_type, off);
+       r = talloc();
+       *r = *p;
+       nip = ipnode(mkbinode(ASSIGN, l, r, p->n_type));
+       storemod(p, off, FPREG); /* XXX */
+       DLIST_INSERT_BEFORE(cip, nip, qelem);
+       DLIST_REMOVE(w, link);
+       RDEBUG(("Stored parent node %d (%p)\n", ASGNUM(w), p));
+       return 1;
+}
+
+static void
+dlr(REGW *w)
+{
+       if (w == 0)
+               return;
+       DLIST_REMOVE(w, link);
+       RDEBUG(("Removing %d\n", ASGNUM(w)));
+}
+
+/*
+ * Return the number of the topmost temporary that should be spilled.
+ * If temps below found, remove them from the spill list.
+ * If two temps at the same level are found, remove one.
+ * If both left & right have temps, store right and leave left.
+ */
+static REGW *
+toptemp(NODE *p, REGW *rw)
+{
+       REGW *r, *l, *rv, *w;
+       int nc, i;
+
+       l = r = rv = NULL;
+       if (optype(p->n_op) != LTYPE)
+               l = toptemp(p->n_left, rw);
+       if (optype(p->n_op) == BITYPE)
+               r = toptemp(p->n_right, rw);
+       DLIST_FOREACH(w, rw, link) {
+               nc = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
+               for (i = 0; i < nc + 1; i++) {
+                       if ((p->n_regw + i) != w)
+                               continue;
+                       RDEBUG(("Found %d \n", ASGNUM(w)));
+                       dlr(rv);
+                       rv = w;
+               }
+       }
+       if (rv != NULL) {
+               dlr(l);
+               dlr(r);
+       } else if (r != NULL) {
+               /* pick right, not left */
+               rv = r;
+               dlr(l);
+       } else {
+               rv = l;
+       }
+       return rv;
+}
+
+static void leafrewrite(struct interpass *ipole, REGW *rpole);
+/*
+ * Change the TEMPs in the ipole list to stack variables.
+ */
+static void
+treerewrite(struct interpass *ipole, REGW *rpole)
+{
+       struct interpass *ip;
+       REGW *w, longregs;
+
+       spole = rpole;
+
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               if ((w = toptemp(ip->ip_node, rpole)) == 0)
+                       continue;
+               cip = ip;
+               shorttemp(ip->ip_node, NULL, w); /* convert temps to oregs */
+       }
+        if (longsp) {
+#ifdef PCC_DEBUG
+               RDEBUG(("Storing node %d to save short\n", ASGNUM(longsp)));
+#endif
+               if (longsp >= &nblock[tempmin] && longsp < &nblock[basetemp]) {
+                       int num = longsp - nblock - tempmin;
+                       nsavregs[num] = 1;
+               } else {
+                       DLIST_INIT(&longregs, link);
+                       DLIST_INSERT_AFTER(&longregs, longsp, link);
+                       leafrewrite(ipole, &longregs);
+               }
+       } else if (!DLIST_ISEMPTY(spole, link))
+               comperr("treerewrite not empty");
+}
+
+/*
+ * Change the TEMPs in the ipole list to stack variables.
+ */
+static void
+leafrewrite(struct interpass *ipole, REGW *rpole)
+{
+       extern NODE *nodepole;
+       extern int thisline;
+       struct interpass *ip;
+
+       spole = rpole;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               if (ip->type != IP_NODE)
+                       continue;
+               nodepole = ip->ip_node;
+               thisline = ip->lineno;
+               walkf(ip->ip_node, longtemp, 0); /* convert temps to oregs */
+       }
+       nodepole = NIL;
+}
+
+/*
+ * Avoid copying spilled argument to new position on stack.
+ */
+static int
+temparg(struct interpass *ipole, REGW *w)
+{
+       struct interpass *ip;
+       NODE *p;
+       int reg;
+
+       ip = DLIST_NEXT(ipole, qelem); /* PROLOG */
+       while (ip->type != IP_DEFLAB)
+               ip = DLIST_NEXT(ip, qelem);
+       ip = DLIST_NEXT(ip, qelem); /* first NODE */
+       for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
+               if (ip->type == IP_ASM)
+                       continue;
+               p = ip->ip_node;
+#ifdef notdef
+               /* register args may already have been put on stack */
+               if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+                       comperr("temparg");
+#endif
+               if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+                       continue; /* unknown tree */
+
+               if (p->n_right->n_op != OREG)
+                       continue; /* arg in register */
+               if (w != &nblock[regno(p->n_left)])
+                       continue;
+               w->r_color = (int)getlval(p->n_right);
+               reg = regno(p->n_right);
+               tfree(p);
+               /* Cannot DLIST_REMOVE here, would break basic blocks */
+               /* Make it a nothing instead */
+               ip->type = IP_ASM;
+               ip->ip_asm = "";
+               return reg;
+       }
+       return 0;
+}
+
+#define        ONLYPERM 1
+#define        LEAVES   2
+#define        SMALL    3
+
+/*
+ * Scan the whole function and search for temporaries to be stored
+ * on-stack.
+ *
+ * Be careful to not destroy the basic block structure in the first scan.
+ */
+static int
+RewriteProgram(struct interpass *ip)
+{
+       REGW shortregs, longregs, saveregs, *q;
+       REGW *w;
+       int rwtyp;
+
+       RDEBUG(("RewriteProgram\n"));
+       DLIST_INIT(&shortregs, link);
+       DLIST_INIT(&longregs, link);
+       DLIST_INIT(&saveregs, link);
+
+       /* sort the temporaries in three queues, short, long and perm */
+       while (!DLIST_ISEMPTY(&spilledNodes, link)) {
+               w = DLIST_NEXT(&spilledNodes, link);
+               DLIST_REMOVE(w, link);
+
+               if (w >= &nblock[tempmin] && w < &nblock[basetemp]) {
+                       q = &saveregs;
+               } else if (w >= &nblock[basetemp] && w < &nblock[tempmax]) {
+                       q = &longregs;
+               } else
+                       q = &shortregs;
+               DLIST_INSERT_AFTER(q, w, link);
+       }
+#ifdef PCC_DEBUG
+       if (r2debug) {
+               printf("permanent: ");
+               DLIST_FOREACH(w, &saveregs, link)
+                       printf("%d ", ASGNUM(w));
+               printf("\nlong-lived: ");
+               DLIST_FOREACH(w, &longregs, link)
+                       printf("%d ", ASGNUM(w));
+               printf("\nshort-lived: ");
+               DLIST_FOREACH(w, &shortregs, link)
+                       printf("%d ", ASGNUM(w));
+               printf("\n");
+       }
+#endif
+       rwtyp = 0;
+
+       if (!DLIST_ISEMPTY(&saveregs, link)) {
+               rwtyp = ONLYPERM;
+               DLIST_FOREACH(w, &saveregs, link) {
+                       int num = w - nblock - tempmin;
+                       nsavregs[num] = 1;
+               }
+       }
+       if (!DLIST_ISEMPTY(&longregs, link)) {
+               rwtyp = LEAVES;
+               DLIST_FOREACH(w, &longregs, link) {
+                       w->r_class = xtemps ? temparg(ip, w) : 0;
+               }
+       }
+
+       if (rwtyp == LEAVES) {
+               leafrewrite(ip, &longregs);
+               rwtyp = ONLYPERM;
+       }
+
+       if (rwtyp == 0 && !DLIST_ISEMPTY(&shortregs, link)) {
+               /* Must rewrite the trees */
+               treerewrite(ip, &shortregs);
+#if 0
+               if (xtemps)
+                       comperr("treerewrite");
+#endif
+               rwtyp = SMALL;
+       }
+
+       RDEBUG(("savregs %x rwtyp %d\n", 0, rwtyp));
+
+       return rwtyp;
+}
+
+#ifdef PCC_DEBUG
+/*
+ * Print TEMP/REG contents in a node.
+ */
+void
+prtreg(NODE *p)
+{
+       int i, n = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
+if (p->n_reg == -1) goto foo;
+       if (use_regw || p->n_reg > 0x40000000 || p->n_reg < 0) {
+               printf("TEMP ");
+               if (p->n_regw != NULL) {
+                       for (i = 0; i < n+1; i++)
+                               printf("%d ", p->n_regw[i].nodnum);
+               } else
+                       printf("<undef>");
+       } else {
+foo:           printf("REG ");
+               if (p->n_reg != -1) {
+                       for (i = 0; i < n+1; i++) {
+                               int r = DECRA(p->n_reg, i);
+                               if (r >= MAXREGS)
+                                       printf("<badreg> ");
+                               else
+                                       printf("%s ", rnames[r]);
+                       }
+               } else
+                       printf("<undef>");
+       }
+}
+#endif
+
+#ifdef notyet
+/*
+ * Assign instructions, calculate evaluation order and
+ * set temporary register numbers.
+ */
+static void
+insgen()
+{
+       clrsu(p);
+       geninsn(); /* instruction assignment */
+       sucomp();  /* set evaluation order */
+       slong();   /* set long temp types */
+       sshort();  /* set short temp numbers */
+}
+#endif
+
+/*
+ * Do register allocation for trees by graph-coloring.
+ */
+void
+ngenregs(struct p2env *p2e)
+{
+       struct interpass *ipole = &p2e->ipole;
+       extern NODE *nodepole;
+       struct interpass *ip;
+       int i, j, tbits;
+       int uu[NPERMREG] = { -1 };
+       int xnsavregs[NPERMREG];
+       int beenhere = 0;
+       TWORD type;
+
+       DLIST_INIT(&lunused, link);
+       DLIST_INIT(&lused, link);
+
+       /*
+        * Do some setup before doing the real thing.
+        */
+       tempmin = p2e->ipp->ip_tmpnum;
+
+       /*
+        * Allocate space for the permanent registers in the
+        * same block as the long-lived temporaries.
+        * These temporaries will be handled the same way as 
+        * all other variables.
+        */
+       basetemp = tempmin;
+       nsavregs = xnsavregs;
+       for (i = 0; i < NPERMREG; i++)
+               xnsavregs[i] = 0;
+       ndontregs = uu; /* currently never avoid any regs */
+
+       tempmin -= (NPERMREG-1);
+#ifdef notyet
+       if (xavoidfp)
+               dontregs |= REGBIT(FPREG);
+#endif
+
+       /* Block for precolored nodes */
+       ablock = tmpalloc(sizeof(REGW)*MAXREGS);
+       memset(ablock, 0, sizeof(REGW)*MAXREGS);
+       for (i = 0; i < MAXREGS; i++) {
+               ablock[i].r_onlist = &precolored;
+               ablock[i].r_class = GCLASS(i); /* XXX */
+               ablock[i].r_color = i;
+#ifdef PCC_DEBUG
+               ablock[i].nodnum = i;
+#endif
+       }
+
+ssagain:
+       tempmax = p2e->epp->ip_tmpnum;
+#ifdef PCC_DEBUG
+       nodnum = tempmax;
+#endif
+       tbits = tempmax - tempmin;      /* # of temporaries */
+       xbits = tbits + MAXREGS;        /* total size of live array */
+       if (tbits) {
+               nblock = tmpalloc(tbits * sizeof(REGW));
+
+               nblock -= tempmin;
+#ifdef HAVE_C99_FORMAT
+               RDEBUG(("nblock %p num %d size %zu\n",
+                   nblock, tbits, (size_t)(tbits * sizeof(REGW))));
+#endif
+       }
+       live = tmpalloc(BIT2BYTE(xbits));
+
+#ifdef notyet
+       TMPMARK();
+#endif
+
+
+recalc:
+onlyperm: /* XXX - should not have to redo all */
+       memset(edgehash, 0, sizeof(edgehash));
+
+       /* clear adjacent node list */
+       for (i = 0; i < MAXREGS; i++)
+               for (j = 0; j < NUMCLASS+1; j++)
+                       NCLASS(&ablock[i], j) = 0;
+
+       if (tbits) {
+               memset(nblock+tempmin, 0, tbits * sizeof(REGW));
+#ifdef PCC_DEBUG
+               for (i = tempmin; i < tempmax; i++)
+                       nblock[i].nodnum = i;
+#endif
+       }
+       memset(live, 0, BIT2BYTE(xbits));
+       RPRINTIP(ipole);
+       DLIST_INIT(&initial, link);
+       ntsz = 0;
+       DLIST_FOREACH(ip, ipole, qelem) {
+               extern int thisline;
+               if (ip->type != IP_NODE)
+                       continue;
+               nodepole = ip->ip_node;
+               thisline = ip->lineno;
+               if (ip->ip_node->n_op != XASM) {
+                       clrsu(ip->ip_node);
+                       geninsn(ip->ip_node, FOREFF);
+               }
+               nsucomp(ip->ip_node);
+               walkf(ip->ip_node, traclass, 0);
+       }
+       nodepole = NIL;
+       RDEBUG(("nsucomp allocated %d temps (%d,%d)\n", 
+           tempmax-tempmin, tempmin, tempmax));
+
+#ifdef PCC_DEBUG
+       use_regw = 1;
+       RPRINTIP(ipole);
+       use_regw = 0;
+#endif
+       RDEBUG(("ngenregs: numtemps %d (%d, %d)\n", tempmax-tempmin,
+                   tempmin, tempmax));
+
+       DLIST_INIT(&coalescedMoves, link);
+       DLIST_INIT(&constrainedMoves, link);
+       DLIST_INIT(&frozenMoves, link);
+       DLIST_INIT(&worklistMoves, link);
+       DLIST_INIT(&activeMoves, link);
+
+       /* Set class and move-related for perm regs */
+       for (i = 0; i < (NPERMREG-1); i++) {
+               if (nsavregs[i])
+                       continue;
+               nblock[i+tempmin].r_class = GCLASS(permregs[i]);
+               DLIST_INSERT_AFTER(&initial, &nblock[i+tempmin], link);
+               moveadd(&nblock[i+tempmin], &ablock[permregs[i]]);
+               addalledges(&nblock[i+tempmin]);
+       }
+
+       Build(p2e);
+       RDEBUG(("Build done\n"));
+       MkWorklist();
+       RDEBUG(("MkWorklist done\n"));
+       Coalassign(p2e);
+       do {
+               if (!WLISTEMPTY(simplifyWorklist))
+                       Simplify();
+               else if (!WLISTEMPTY(worklistMoves))
+                       Coalesce();
+               else if (!WLISTEMPTY(freezeWorklist))
+                       Freeze();
+               else if (!WLISTEMPTY(spillWorklist))
+                       SelectSpill();
+       } while (!WLISTEMPTY(simplifyWorklist) || !WLISTEMPTY(worklistMoves) ||
+           !WLISTEMPTY(freezeWorklist) || !WLISTEMPTY(spillWorklist));
+       AssignColors(ipole);
+
+       RDEBUG(("After AssignColors\n"));
+       RPRINTIP(ipole);
+
+       if (!WLISTEMPTY(spilledNodes)) {
+               switch (RewriteProgram(ipole)) {
+               case ONLYPERM:
+                       goto onlyperm;
+               case SMALL:
+                       optimize(p2e);
+                       if (beenhere++ == MAXLOOP)
+                               comperr("cannot color graph - COLORMAP() bug?");
+                       if (xssa)
+                               goto ssagain;
+                       goto recalc;
+               }
+       }
+
+       /* fill in regs to save */
+       memset(p2e->ipp->ipp_regs, 0, sizeof(p2e->ipp->ipp_regs));
+       for (i = 0; i < NPERMREG-1; i++) {
+               NODE *p;
+
+               if (nsavregs[i]) {
+                       BITSET(p2e->ipp->ipp_regs, permregs[i]);
+                       continue; /* Spilled */
+               }
+               if (nblock[i+tempmin].r_color == permregs[i])
+                       continue; /* Coalesced */
+               /*
+                * If the original color of this permreg is used for
+                * coloring another register, swap them to avoid
+                * unnecessary moves.
+                */
+               for (j = i+1; j < NPERMREG-1; j++) {
+                       if (nblock[j+tempmin].r_color != permregs[i])
+                               continue;
+                       nblock[j+tempmin].r_color = nblock[i+tempmin].r_color;
+                       break;
+               }
+               if (j != NPERMREG-1)
+                       continue;
+
+               /* Generate reg-reg move nodes for save */
+               type = PERMTYPE(permregs[i]);
+#ifdef PCC_DEBUG
+               if (PERMTYPE(nblock[i+tempmin].r_color) != type)
+                       comperr("permreg botch");
+#endif
+               p = mkbinode(ASSIGN,
+                   mklnode(REG, 0, nblock[i+tempmin].r_color, type),
+                   mklnode(REG, 0, permregs[i], type), type);
+               p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1;
+               clrsu(p);
+               geninsn(p, FOREFF);
+               ip = ipnode(p);
+               DLIST_INSERT_AFTER(ipole->qelem.q_forw, ip, qelem);
+               p = mkbinode(ASSIGN, mklnode(REG, 0, permregs[i], type),
+                   mklnode(REG, 0, nblock[i+tempmin].r_color, type), type);
+               p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1;
+               clrsu(p);
+               geninsn(p, FOREFF);
+               ip = ipnode(p);
+               DLIST_INSERT_BEFORE(ipole->qelem.q_back, ip, qelem);
+       }
+       stktemp = freetemp(ntsz);
+       memcpy(p2e->epp->ipp_regs, p2e->ipp->ipp_regs, sizeof(p2e->epp->ipp_regs));
+       /* Done! */
+}
diff --git a/lang/pcc/pcc/os/android/ccconfig.h b/lang/pcc/pcc/os/android/ccconfig.h
new file mode 100644 (file)
index 0000000..d36e4ba
--- /dev/null
@@ -0,0 +1,61 @@
+/*     $Id: ccconfig.h,v 1.2 2015/01/08 06:31:11 plunky Exp $  */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define CPPADD { "-D__ANDROID__", "-D__linux__", "-D__ELF__", NULL, }
+
+#define CRT0           "crt1.o"
+#define GCRT0          "gcrt1.o"
+#define DYNLINKLIB     "/system/bin/linker"
+
+#define STARTLABEL "_start"
+
+#if defined(mach_i386)
+#define CPPMDADD       { "-D__i386__", NULL, }
+#elif defined(mach_amd64)
+#define CPPMDADD       { "-D__x86_64__", "-D__x86_64", "-D__amd64__", \
+       "-D__amd64", "-D__LP64__", "-D_LP64", NULL, }
+#define        DEFLIBDIRS      { "/usr/lib64/", 0 }
+#elif defined(mach_mips)
+#define CPPMDADD { "-D__mips__", NULL, }
+#elif defined(mach_arm)
+#define CPPMDADD { "-D__arm__", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+
+#define PCC_EARLY_ARG_CHECK    {                       \
+       if (match(argp, "-no-canonical-prefixes")) {    \
+               continue;                               \
+       }                                               \
+}
+
diff --git a/lang/pcc/pcc/os/bsd/ccconfig.h b/lang/pcc/pcc/os/bsd/ccconfig.h
new file mode 100644 (file)
index 0000000..f1a065b
--- /dev/null
@@ -0,0 +1,51 @@
+/*     $Id: ccconfig.h,v 1.3 2014/03/09 09:32:58 ragge Exp $   */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD  { "-D__BSD2_11__", "-DBSD2_11", NULL }
+
+/* host-dependent */
+#define CRTBEGIN       0
+#define CRTEND         0
+#define CRTI           0
+#define CRTN           0
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#if defined(mach_pdp11)
+#define        CPPMDADD { "-D__pdp11__", "-Dpdp11", NULL, }
+#elif defined(mach_nova)
+#define        CPPMDADD { "-D__nova__", "-Dnova", NULL, }
+#else
+#error defines for arch missing
+#endif
diff --git a/lang/pcc/pcc/os/darwin/ccconfig.h b/lang/pcc/pcc/os/darwin/ccconfig.h
new file mode 100644 (file)
index 0000000..1e73b21
--- /dev/null
@@ -0,0 +1,111 @@
+/*     $Id: ccconfig.h,v 1.20 2014/06/04 06:43:50 gmcgarry Exp $       */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD          { "-D__Darwin__", "-D__APPLE__", "-D__MACH__", "-D__APPLE_CPP__", NULL }
+#define        CRT0            "crt1.o"
+#define GCRT0          "gcrt1.o"
+#define CRTBEGIN_T     0
+#define CRTEND_T       0
+#define CRTBEGIN       0
+#define CRTEND         0
+#define CRTBEGIN_S     "dylib1.o"
+#define CRTEND_S       0
+#define CRTI           0
+#define CRTN           0
+#define DEFLIBS                { "-lSystem", "-lpcc", NULL }
+#define DEFPROFLIBS    { "-lSystem_profile", "-lpcc", NULL }
+#define STARTLABEL "start"
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L" PCCLIBDIR, "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+/*
+ld -arch ppc -weak_reference_mismatches non-weak -o a.out -lcrt1.o -lcrt2.o -L/usr/lib/gcc/powerpc-apple-darwin8/4.0.1 hello_ppc.o -lgcc -lSystemStubs -lSystem
+*/
+
+#if defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", "-D__LITTLE_ENDIAN__", NULL }
+#elif defined(mach_powerpc)
+#define        CPPMDADD { "-D__ppc__", "-D__BIG_ENDIAN__", NULL }
+#elif defined(mach_amd64)
+#define        CPPMDADD { "-D__x86_64__", "-D__LITTLE_ENDIAN__", NULL }
+#elif define(mach_m68k)
+#define        CPPMDADD { "-D__m68k__", "-D__BIG_ENDIAN__", NULL }
+#else
+#error defines for arch missing
+#endif
+
+
+/*
+ * Deal with some darwin-specific args.
+ */
+#define        PCC_EARLY_ARG_CHECK     {                                               \
+       if (match(argp, "-install_name")) {                             \
+               strlist_append(&middle_linker_flags, argp);             \
+               strlist_append(&middle_linker_flags, nxtopt(0));        \
+               continue;                                               \
+       } else if (match(argp, "-compatibility_version") ||             \
+           match(argp, "-current_version")) {                          \
+               strlist_append(&middle_linker_flags, argp);             \
+               strlist_append(&middle_linker_flags, nxtopt(0));        \
+               continue;                                               \
+       } else if (strcmp(argp, "-dynamiclib") == 0) {                  \
+               shared = 1;                                             \
+               continue;                                               \
+       } else if (strcmp(argp, "-shared") == 0) {                      \
+               oerror(argp);                                           \
+               continue;                                               \
+       } else if (strncmp(argp, "-mmacosx-version-min", 20) == 0) {    \
+               char tmp[10];                                           \
+               char *p = &argp[21];                                    \
+               int idx = 0;                                            \
+               while (*p != 0) {                                       \
+                       if (*p != '.')                                  \
+                               tmp[idx++] = *p;                        \
+                       p++;                                            \
+               }                                                       \
+               while (idx < 4)                                         \
+                       tmp[idx++] = '0';                               \
+               tmp[idx] = 0;                                           \
+               strlist_append(&preprocessor_flags, cat("-D__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=", tmp)); \
+               strlist_append(&middle_linker_flags, "-macosx_version_min");            \
+               strlist_append(&middle_linker_flags, &argp[21]);        \
+               continue;                                               \
+       } else if (strcmp(argp, "-framework") == 0) {                   \
+               strlist_append(&middle_linker_flags, argp);             \
+               strlist_append(&middle_linker_flags, nxtopt(0));        \
+               continue;                                               \
+       }                                                               \
+}
+
+
diff --git a/lang/pcc/pcc/os/dragonfly/ccconfig.h b/lang/pcc/pcc/os/dragonfly/ccconfig.h
new file mode 100644 (file)
index 0000000..09a5313
--- /dev/null
@@ -0,0 +1,64 @@
+/*     $Id: ccconfig.h,v 1.9 2014/12/24 08:43:28 plunky Exp $  */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#include <sys/param.h>
+
+/* common cpp predefines */
+#define        CPPADD  { "-D__DragonFly__", "-D__ELF__", NULL, }
+
+#if __DragonFly_version < 200202
+#define CRT0FILE "/usr/lib/gcc34/crt1.o"
+#define CRT0FILE_PROFILE "/usr/lib/gcc34/gcrt1.o"
+#define STARTFILES { "/usr/lib/gcc34/crti.o", "/usr/lib/gcc34/crtbegin.o", NULL }
+#define LIBCLIBS { "-lc", "-L/usr/lib/gcc34", "-lgcc", NULL }
+#define        ENDFILES { "/usr/lib/gcc34/crtend.o", "/usr/lib/gcc34/crtn.o", NULL }
+#else
+#define        CRT0FILE "/usr/lib/crt1.o"
+#define        CRT0FILE_PROFILE "/usr/lib/gcrt1.o"
+#define        STARTFILES { "/usr/lib/crti.o", "/usr/lib/gcc41/crtbegin.o", NULL }
+#define        LIBCLIBS { "-lc", "-L/usr/lib/gcc41", "-lgcc", NULL }
+#define        ENDFILES { "/usr/lib/gcc41/crtend.o", "/usr/lib/crtn.o", NULL }
+#endif
+
+#define        DYNLINKLIB "/usr/libexec/ld-elf.so.2"
+#define STARTLABEL "_start"
+
+#if defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", NULL, }
+#elif defined(mach_amd64)
+#define CPPMDADD \
+       { "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", \
+         "-D__LP64__=1", "-D_LP64=1", NULL, }
+#else
+#error defines for arch missing
+#endif
diff --git a/lang/pcc/pcc/os/freebsd/ccconfig.h b/lang/pcc/pcc/os/freebsd/ccconfig.h
new file mode 100644 (file)
index 0000000..c66d1fa
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $Id: ccconfig.h,v 1.18 2014/12/24 08:43:28 plunky Exp $ */
+
+/*-
+ * Copyright (c) 2007 David O'Brien <obrien@FreeBSD.org>
+ * Copyright (c) 2007 Ed Schouten <ed@fxq.nl>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define CPPADD { "-D__FreeBSD__=" MKS(TARGOSVER), "-D__ELF__", \
+       "-D__unix__=1", "-D__unix=1", NULL, }
+
+/* host-dependent */
+#define CRT0           "crt1.o"
+#define GCRT0          "gcrt1.o"
+#define        DYNLINKLIB      "/libexec/ld-elf.so.1"
+#define STARTLABEL "_start"
+
+#if defined(mach_i386)
+#define CPPMDADD { "-D__i386__", "-D__i386", NULL, }
+#elif defined(mach_amd64)
+#define        AMD64_32_EMUL   "elf_i386_fbsd"
+#define        AMD64_64_EMUL   "elf_x86_64_fbsd"
+#include "../inc/amd64.h"
+#elif defined(mach_sparc64)
+#define CPPMDADD \
+       { "-D__sparc64__", "-D__sparc_v9__", "-D__sparc__", "-D__sparc",\
+         "-D__LP64__=1", "-D_LP64=1", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
diff --git a/lang/pcc/pcc/os/inc/amd64.h b/lang/pcc/pcc/os/inc/amd64.h
new file mode 100644 (file)
index 0000000..9eb9955
--- /dev/null
@@ -0,0 +1,44 @@
+/*     $Id: amd64.h,v 1.1 2012/12/28 12:38:15 ragge Exp $      */
+
+/*
+ * Copyright (c) 2012 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define CPPMDADD       { "-D__x86_64__", "-D__x86_64", "-D__amd64__", \
+       "-D__amd64", "-D__LP64__", "-D_LP64", NULL, }
+
+/* fixup small m options */
+#ifndef AMD64_64_EMUL
+#define        AMD64_64_EMUL   "elf_x86_64"
+#endif
+#ifndef AMD64_32_EMUL
+#define        AMD64_32_EMUL   "elf_i386"
+#endif
+#define PCC_EARLY_ARG_CHECK    {                                       \
+       if (match(argp, "-m32")) {                                      \
+               argp = "-m" AMD64_32_EMUL;                              \
+       } else if (match(argp, "-m64")) {                               \
+               argp = "-m" AMD64_64_EMUL;                              \
+       }                                                               \
+}
diff --git a/lang/pcc/pcc/os/linux/ccconfig.h b/lang/pcc/pcc/os/linux/ccconfig.h
new file mode 100644 (file)
index 0000000..c2cd0e4
--- /dev/null
@@ -0,0 +1,98 @@
+/*     $Id: ccconfig.h,v 1.28 2014/12/24 08:43:28 plunky Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define CPPADD { "-D__linux__", "-D__ELF__", NULL, }
+
+#define CRT0           "crt1.o"
+#define GCRT0          "gcrt1.o"
+
+#define STARTLABEL "_start"
+
+#if defined(mach_i386)
+#define CPPMDADD       { "-D__i386__", NULL, }
+#define        DYNLINKLIB      "/lib/ld-linux.so.2"
+#define MUSL_DYLIB     "/lib/ld-musl-i386.so.1"
+#elif defined(mach_powerpc)
+#define CPPMDADD       { "-D__ppc__", NULL, }
+#define        DYNLINKLIB      "/lib/ld-linux.so.2"
+#define MUSL_DYLIB     "/lib/ld-musl-powerpc.so.1"
+#elif defined(mach_amd64)
+#include "../inc/amd64.h"
+#define        DYNLINKLIB      "/lib64/ld-linux-x86-64.so.2"
+#define MUSL_DYLIB     "/lib/ld-musl-x86_64.so.1"
+#ifndef MULTIARCH_PATH
+#define        DEFLIBDIRS      { "/usr/lib64/", 0 }
+#else
+#define        DEFLIBDIRS      { "/usr/lib64/", "/usr/lib/" MULTIARCH_PATH "/", 0 }
+#endif
+#elif defined(mach_mips)
+#define CPPMDADD       { "-D__mips__", NULL, }
+#define        DYNLINKLIB      "/lib/ld.so.1"
+#define MUSL_ROOT      "/lib/ld-musl-mips"
+#define MUSL_EL                "el"
+#define MUSL_SF                "-sf"
+#else
+#error defines for arch missing
+#endif
+
+/*
+ * When USE_MUSL is defined, we either provide MUSL_DYLIB, or
+ * code to construct the dynamic linker name at runtime
+ */
+#ifdef USE_MUSL
+#ifdef MUSL_DYLIB
+#define DYNLINKLIB MUSL_DYLIB
+#else
+#ifndef MUSL_EB
+#define MUSL_EB        NULL
+#endif
+#ifndef MUSL_EL
+#define MUSL_EL        NULL
+#endif
+#ifndef MUSL_SF
+#define MUSL_SF        NULL
+#endif
+#ifndef MUSL_HF
+#define MUSL_HF        NULL
+#endif
+#ifndef MUSL_EXT
+#define MUSL_EXT ".so.1"
+#endif
+
+#define PCC_SETUP_LD_ARGS      {                               \
+               char *t = MUSL_ROOT;                            \
+               t = cat(t, bigendian ? MUSL_EB : MUSL_EL);      \
+               t = cat(t, softfloat ? MUSL_SF : MUSL_HF);      \
+               dynlinklib = cat(t, MUSL_EXT);                  \
+       }
+#endif
+#endif
diff --git a/lang/pcc/pcc/os/litebsd/ccconfig.h b/lang/pcc/pcc/os/litebsd/ccconfig.h
new file mode 100644 (file)
index 0000000..83007df
--- /dev/null
@@ -0,0 +1,50 @@
+/*     $Id: ccconfig.h,v 1.3 2016/01/06 16:14:54 ragge Exp $   */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define CPPADD  { "-D__LiteBSD__", "-D__ELF__", "-D__unix__", \
+       NULL, }
+#define        DYNLINKER { NULL }
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#define        CPPMDADD { "-D__mips__", "-Dmips", "-D__mips=32", "-D__MIPSEL", \
+       "-D__MIPSEL__", "-DMIPSEL", "-D_MIPSEL", NULL, }
+
+#define DEFLIBS { "-lc", "-lgcc", NULL }
+
+/* We only have crt0.o */
+#define CRTBEGIN       0
+#define CRTEND         0
+#define CRTI           0
+#define CRTN           0
diff --git a/lang/pcc/pcc/os/midnightbsd/ccconfig.h b/lang/pcc/pcc/os/midnightbsd/ccconfig.h
new file mode 100644 (file)
index 0000000..c450e82
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id: ccconfig.h,v 1.7 2014/12/24 08:43:28 plunky Exp $ */
+/*-
+ * Copyright (c) 2007, 2008
+ *     Thorsten Glaser <tg@mirbsd.de>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+/**
+ * Configuration for pcc on a MidnightBSD (amd64, i386 or sparc64) target
+ */
+
+/* === mi part === */
+
+/* cpp MI defines */
+#define CPPADD                 {               \
+       "-D__MidnightBSD__",                    \
+       "-D__FreeBSD__",                        \
+       "-D__unix__",                           \
+       "-D__unix",                             \
+       "-Dunix",                               \
+       "-D__ELF__",                            \
+       "-D_LONGLONG",                          \
+       NULL                                    \
+}
+
+/* for dynamically linked binaries */
+#define        DYNLINKLIB      "/libexec/ld-elf.so.1"
+
+/* C run-time startup */
+#define CRT0           "crt1.o"
+#define GCRT0          "gcrt1.o"
+
+#define CRTEND_T       "crtend.o"
+
+/* === md part === */
+
+#if defined(mach_i386)
+#define CPPMDADD               {               \
+       "-D__i386__",                           \
+       "-D__i386",                             \
+       "-Di386",                               \
+       NULL,                                   \
+}
+#elif defined(mach_sparc64)
+#define CPPMDADD               {               \
+       "-D__sparc64__",                        \
+       "-D__sparc_v9__",                       \
+       "-D__sparcv9",                          \
+       "-D__sparc__",                          \
+       "-D__sparc",                            \
+       "-Dsparc",                              \
+       "-D__arch64__",                         \
+       "-D__LP64__",                           \
+       "-D_LP64",                              \
+       NULL,                                   \
+}
+#elif defined(mach_amd64)
+#error pcc does not support amd64 yet
+#else
+#error this architecture is not supported by MidnightBSD
+#endif
diff --git a/lang/pcc/pcc/os/minix/ccconfig.h b/lang/pcc/pcc/os/minix/ccconfig.h
new file mode 100644 (file)
index 0000000..9f8fa77
--- /dev/null
@@ -0,0 +1,107 @@
+/*      $Id: ccconfig.h,v 1.6 2014/12/24 08:43:28 plunky Exp $ */
+/*
+ * Escrit per Antoine Leca pel projecte PCC, 2011-03.
+ * Copyright (C) 2011 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ *
+ * MINIX (http://www.minix3.org), both Classic a.out=PC/IX and ELF
+ */
+
+#ifdef ELFABI
+/* MINIX versions 3.2 (2011) and up, using NetBSD userland. */
+
+/* common cpp predefines */
+#define CPPADD { "-D__minix", "-D__ELF__", NULL }
+
+#define        DYNLINKLIB      "/libexec/ld.elf_so"
+
+#define CRTEND_T       "crtend.o"
+
+#define DEFLIBS                { "-lc", NULL }
+#define DEFPROFLIBS    { "-lc_p", NULL }
+#define DEFCXXLIBS     { "-lp++", "-lc", NULL }
+
+#if defined(mach_amd64)
+#include "../inc/amd64.h"
+#define        PCC_SIZE_TYPE           "unsigned long"
+#define        PCC_PTRDIFF_TYPE        "long"
+#elif defined(mach_arm)
+#define        CPPMDADD        { "-D__arm__", NULL, }
+#elif defined(mach_i386)
+#define        CPPMDADD        { "-D__i386", "-D__i386__", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#ifndef        PCC_WINT_TYPE
+#define        PCC_WINT_TYPE           "int"
+#endif
+#ifndef        PCC_SIZE_TYPE
+#define        PCC_SIZE_TYPE           "unsigned int"
+#endif
+#ifndef        PCC_PTRDIFF_TYPE
+#define        PCC_PTRDIFF_TYPE        "int"
+#endif
+
+#elif defined(AOUTABI)
+/* MINIX 2 or 3.1.x, a.out-like format derived from PC/IX. */
+
+/* common cpp predefines */
+#define CPPADD { "-D__minix", NULL }
+
+/* linker stuff */
+#define STARTLABEL     "crtso"
+#define CRT0           "crtso.o"
+#ifdef notyet
+#define GCRT0  "/usr/lib/pcc/gcrtso.o"
+#endif
+
+#define CRTBEGIN       0
+#define CRTEND         0
+#define CRTBEGIN_S     0
+#define CRTEND_S       0
+#define CRTBEGIN_T     0
+#define CRTEND_T       0
+
+#define CRTI           0
+#define CRTN           "-lend"
+
+#if defined(mach_i386)
+#define CPPMDADD { "-D__i386", "-D__i386__", \
+       "-D_EM_WSIZE=4", "-D_EM_PSIZE=4", "-D_EM_LSIZE=4", \
+       "-D_EM_SSIZE=2", "-D_EM_FSIZE=4", "-D_EM_DSIZE=8", \
+       NULL, }
+#else
+#define CPPMDADD { "-D__i86", \
+       "-D_EM_WSIZE=2", "-D_EM_PSIZE=2", "-D_EM_LSIZE=4", \
+       "-D_EM_SSIZE=2", "-D_EM_FSIZE=4", "-D_EM_DSIZE=8", \
+       NULL, }
+#endif
+
+#else
+#error defines for ABI missing
+#endif
diff --git a/lang/pcc/pcc/os/mirbsd/ccconfig.h b/lang/pcc/pcc/os/mirbsd/ccconfig.h
new file mode 100644 (file)
index 0000000..8852de3
--- /dev/null
@@ -0,0 +1,56 @@
+/* $Id: ccconfig.h,v 1.10 2014/12/24 08:43:28 plunky Exp $ */
+/*-
+ * Copyright (c) 2007, 2008
+ *     Thorsten Glaser <tg@mirbsd.de>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+/**
+ * Configuration for pcc on a MirOS BSD (i386 or sparc) target
+ */
+
+/* === mi part === */
+
+/* cpp MI defines */
+#define CPPADD                 {               \
+       "-D__MirBSD__",                         \
+       "-D__OpenBSD__",                        \
+       "-D__unix__",                           \
+       "-D__ELF__",                            \
+       NULL                                    \
+}
+
+/* for dynamically linked binaries */
+#define        DYNLINKLIB      "/usr/libexec/ld.so"
+
+#define CRTEND_T       "crtend.o"
+#define DEFLIBS                { "-lc", NULL }
+
+/* === md part === */
+
+#if defined(mach_i386)
+#define CPPMDADD               {               \
+       "-D__i386__",                           \
+       "-D__i386",                             \
+       "-Di386",                               \
+       NULL,                                   \
+}
+#elif defined(mach_sparc)
+#error pcc does not support sparc yet
+#else
+#error this architecture is not supported by MirOS BSD
+#endif
diff --git a/lang/pcc/pcc/os/netbsd/ccconfig.h b/lang/pcc/pcc/os/netbsd/ccconfig.h
new file mode 100644 (file)
index 0000000..f8f0e90
--- /dev/null
@@ -0,0 +1,88 @@
+/*     $Id: ccconfig.h,v 1.31 2014/12/24 08:43:29 plunky Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD  { "-D__NetBSD__", "-D__ELF__", NULL, }
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#define        DYNLINKLIB      "/usr/libexec/ld.elf_so"
+
+#define CRTEND_T       "crtend.o"
+
+#define DEFLIBS                { "-lc", NULL }
+#define DEFPROFLIBS    { "-lc_p", NULL }
+#define DEFCXXLIBS     { "-lp++", "-lc", NULL }
+
+#if defined(mach_amd64)
+#define CPPMDADD \
+       { "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", \
+         "-D__LP64__", "-D_LP64", NULL, }
+#elif defined(mach_arm)
+#define        CPPMDADD { "-D__arm__", NULL, }
+#elif defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", NULL, }
+#define        PCC_SIZE_TYPE           "unsigned int"
+#define        PCC_PTRDIFF_TYPE        "int"
+#elif defined(mach_m68k)
+#define        CPPMDADD { "-D__mc68000__", "-D__mc68020__", "-D__m68k__", NULL, }
+#undef DEFLIBS
+#define DEFLIBS        { "-lc", "-lgcc", NULL }
+#define STARTLABEL "_start"
+#elif defined(mach_mips)
+#define        CPPMDADD { "-D__mips__", NULL, }
+#elif defined(mach_pdp10)
+#define CPPMDADD { "-D__pdp10__", NULL, }
+#elif defined(mach_powerpc)
+#define        CPPMDADD { "-D__ppc__", NULL, }
+#define STARTLABEL "_start"
+#elif defined(mach_vax)
+#define CPPMDADD { "-D__vax__", NULL, }
+#define        PCC_EARLY_SETUP { kflag = 1; }
+#elif defined(mach_sparc64)
+#define CPPMDADD { "-D__sparc64__", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#ifndef        PCC_WINT_TYPE
+#define        PCC_WINT_TYPE           "int"
+#endif
+#ifndef        PCC_SIZE_TYPE
+#define        PCC_SIZE_TYPE           "unsigned long"
+#endif
+#ifndef        PCC_PTRDIFF_TYPE
+#define        PCC_PTRDIFF_TYPE        "long"
+#endif
diff --git a/lang/pcc/pcc/os/nextstep/ccconfig.h b/lang/pcc/pcc/os/nextstep/ccconfig.h
new file mode 100644 (file)
index 0000000..b2e8e01
--- /dev/null
@@ -0,0 +1,69 @@
+/*     $Id: ccconfig.h,v 1.5 2014/12/24 08:43:29 plunky Exp $  */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD  {               \
+       "-D__NeXT__",           \
+       "-I" LIBDIR "ansi",     \
+       "-I" LIBDIR "bsd",      \
+       NULL                    \
+}
+
+#define CRTBEGIN       0
+#define CRTBEGIN_S     0
+#define CRTBEGIN_T     0
+#define CRTEND         0
+#define CRTEND_S       0
+#define CRTEND_T       0
+#define CRTI           0
+#define CRTN           0
+
+#define CRT0           "crt1.o"
+#define GCRT0          "gcrt1.o"
+
+#define LIBCLIBS { "-lc", "-lpcc", NULL }
+#define LIBCLIBS_PROFILE { "-lc", "-lpcc", NULL }
+
+#define STARTLABEL     "start"
+
+/*
+ld -arch ppc -weak_reference_mismatches non-weak -o a.out -lcrt1.o -lcrt2.o -L/usr/lib/gcc/powerpc-apple-darwin8/4.0.1 hello_ppc.o -lgcc -lSystemStubs -lSystem
+*/
+
+#if defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", "-D__LITTLE_ENDIAN__", NULL }
+#elif defined(mach_powerpc)
+#define        CPPMDADD { "-D__ppc__", "-D__BIG_ENDIAN__", NULL }
+#else
+#error defines for arch missing
+#endif
diff --git a/lang/pcc/pcc/os/none/ccconfig.h b/lang/pcc/pcc/os/none/ccconfig.h
new file mode 100644 (file)
index 0000000..e6a6283
--- /dev/null
@@ -0,0 +1,53 @@
+/*     $Id: ccconfig.h,v 1.4 2014/12/26 11:05:27 ragge Exp $   */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/*
+ * This file is for targets where there is no OS
+ */
+
+/* common cpp predefines */
+#define        CPPADD  { NULL, }
+#define CRT0FILE ""
+#define STARTFILES { NULL }
+#define        ENDFILES { NULL }
+
+#if defined(mach_m16c)
+#define        CPPMDADD { "-D__m16c__", NULL, }
+#elif defined(mach_nova)
+#define        CPPMDADD { "-D__nova__", NULL, }
+#elif defined(mach_i86)
+#define        CPPMDADD { "-D__i86__", NULL, }
+#else
+#error defines for arch missing
+#endif
+
diff --git a/lang/pcc/pcc/os/openbsd/ccconfig.h b/lang/pcc/pcc/os/openbsd/ccconfig.h
new file mode 100644 (file)
index 0000000..73095bd
--- /dev/null
@@ -0,0 +1,57 @@
+/*     $Id: ccconfig.h,v 1.15 2014/12/24 08:43:29 plunky Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD  { "-D__OpenBSD__", "-D__ELF__", NULL, }
+#define        DYNLINKLIB      "/usr/libexec/ld.so"
+#define        CRTI 0          /* OpenBSD does not use this */
+#define        CRTN 0          /* OpenBSD does not use this */
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#if defined(mach_amd64)
+#define        CPPMDADD { "-D__amd64__", NULL, }
+#elif defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", NULL, }
+#elif defined(mach_vax)
+#define CPPMDADD { "-D__vax__", NULL, } 
+#elif defined(mach_powerpc)
+#define CPPMDADD { "-D__powerpc__", NULL }
+#elif defined(mach_sparc64)
+#define CPPMDADD { "-D__sparc64__", NULL }
+#elif defined(mach_m68k)
+#define CPPMDADD { "-D__mc68000__", "-D__mc68020__", "-D__m68k__", NULL }
+#define STARTLABEL "_start"
+#else
+#error defines for arch missing
+#endif
diff --git a/lang/pcc/pcc/os/openbsd/f77config.h b/lang/pcc/pcc/os/openbsd/f77config.h
new file mode 100644 (file)
index 0000000..ee9d4fb
--- /dev/null
@@ -0,0 +1,46 @@
+/*     $Id: f77config.h,v 1.1 2007/09/15 07:37:49 ragge Exp $  */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the f77 compiler works.
+ */
+
+#define PASS1NAME      "/usr/lib/f77pass1"
+#define PASS2NAME      "/lib/f1"
+#define PASS2OPT       "/lib/c2"
+#define NOFLPASS2      "/lib/fc1"
+
+#define ASMNAME                "/usr/bin/as"
+#define LDNAME         "/usr/bin/ld"
+#define FOOTNAME       "/usr/lib/crt0.o"
+#define PROFFOOT       "/usr/lib/mcrt0.o"
+#define NOFLFOOT       "/usr/lib/fcrt0.o"
+#define NOFLPROFFOOT   "/usr/lib/fmcrt0.o"
+#define LIBLIST                { "-lF77", "-lI77", "-lm", "-lc", "-l", NULL };
+
diff --git a/lang/pcc/pcc/os/sunos/ccconfig.h b/lang/pcc/pcc/os/sunos/ccconfig.h
new file mode 100644 (file)
index 0000000..f80d358
--- /dev/null
@@ -0,0 +1,62 @@
+/*     $Id: ccconfig.h,v 1.7 2014/12/24 08:43:29 plunky Exp $  */
+
+/*
+ * Copyright (c) 2008 Adam Hoka.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD  { "-Dunix", "-Dsun", "-D__SVR4", "-D__unix", "-D__sun", "-D__SunOS", "-D__ELF__", NULL }
+
+/* TODO: _ _SunOS_5_6, _ _SunOS_5_7, _ _SunOS_5_8, _ _SunOS_5_9, _ _SunOS_5_10 */
+
+/* host-dependent */
+#define CRT0           "crt1.o"
+#define GCRT0          "gcrt1.o"
+#define CRTBEGIN       0
+#define CRTEND         0
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+/* host-independent */
+#define        DYNLINKARG      "-Bdynamic"
+#define        DYNLINKLIB      "/usr/lib/ld.so"
+
+#if defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", "-D__i386", NULL, }
+/* Let's keep it here in case of Polaris. ;) */
+#elif defined(mach_powerpc)
+#define        CPPMDADD { "-D__ppc__", NULL, }
+#elif defined(mach_sparc64)
+#define CPPMDADD { "-D__sparc64__", "-D__sparc", NULL, }
+#else
+#error defines for arch missing
+#endif
diff --git a/lang/pcc/pcc/os/sysv4/ccconfig.h b/lang/pcc/pcc/os/sysv4/ccconfig.h
new file mode 100644 (file)
index 0000000..ee4fb8a
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $Id: ccconfig.h,v 1.2 2014/12/24 08:43:29 plunky Exp $  */
+
+/*
+ * Copyright (c) 2008 Adam Hoka.
+ * Modified from sunos files slightly by Gregor Richards.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define        CPPADD  { "-Dunix", "-D__SVR4", "-D__unix", "-D__svr4__", "-D__ELF__", NULL }
+
+/* host-dependent */
+#define CRT0 "crt1.o"
+#define GCRT0 "gcrt1.o"
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#define        DYNLINKARG      "--dynamic-linker"
+#define        DYNLINKLIB      "/usr/lib/ld.so.1"
+
+#if defined(mach_i386)
+#define        CPPMDADD { "-D__i386__", "-D__i386", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#define        STABS
diff --git a/lang/pcc/pcc/os/win32/build.bat b/lang/pcc/pcc/os/win32/build.bat
new file mode 100644 (file)
index 0000000..3f1c134
--- /dev/null
@@ -0,0 +1,205 @@
+rem @echo off
+
+set PCCDIR=
+set PREFIX=
+set usecl=
+set doinstall=false
+
+:parsecommandline
+if '%1' == '/h' goto dispinfo
+if '%1' == '/pcc' goto usepcc
+if '%1' == '/cl' goto usecl
+if '%1' == '/prefix' goto prefix
+if '%1' == '/pccdir' goto pccdir
+if '%1' == '/pccsrcdir' goto pccsrcdir
+if '%1' == '/pcclibssrcdir' goto pcclibssrcdir
+if '%1' == '/install' set doinstall=true
+goto build
+
+:dispinfo
+echo build.bat [/h] { /pcc or /cl } [/prefix -dir-] [/pccdir -dir-] [/pccsrcdir -dir-] [/pcclibssrcdir -dir-] [/install]
+goto end
+
+:prefix
+shift
+set PREFIX=%1
+shift
+goto parsecommandline
+
+:pccdir
+shift
+set PCCDIR=%1
+shift
+goto parsecommandline
+
+:pccsrcdir
+shift
+set PCCSRCDIR=%1
+shift
+goto parsecommandline
+
+:pcclibssrcdir
+shift
+set PCCLIBSSRCDIR=%1
+shift
+goto parsecommandline
+
+:usecl
+set CC=cl.exe -D__MSC__
+set CFLAGS=/nologo /Zi /MT /W2
+set CFLAGS2=/nologo /Zi /MD /Za /Wall /GS-
+set OBJ=obj
+set AR=lib.exe /nologo
+set AR_OUT=/OUT:libpcc.a
+set usecl=true
+shift
+goto parsecommandline
+
+:usepcc
+set CC=pcc.exe
+set CFLAGS=-g
+set CFLAGS2=-fno-stack-protector-all
+set OBJ=o
+set AR=ar.exe
+set AR_OUT=r libpcc.a
+set usecl=false
+shift
+goto parsecommandline
+
+:build
+
+if '%usecl%' == '' goto dispinfo
+
+set PREFIX=###%PREFIX%###
+set PREFIX=%PREFIX:"###=%
+set PREFIX=%PREFIX:###"=%
+set PREFIX=%PREFIX:###=%
+
+set PCCDIR=###%PCCDIR%###
+set PCCDIR=%PCCDIR:"###=%
+set PCCDIR=%PCCDIR:###"=%
+set PCCDIR=%PCCDIR:###=%
+
+set PCCSRCDIR=###%PCCSRCDIR%###
+set PCCSRCDIR=%PCCSRCDIR:"###=%
+set PCCSRCDIR=%PCCSRCDIR:###"=%
+set PCCSRCDIR=%PCCSRCDIR:###=%
+
+set PCCLIBSSRCDIR=###%PCCLIBSSRCDIR%###
+set PCCLIBSSRCDIR=%PCCLIBSSRCDIR:"###=%
+set PCCLIBSSRCDIR=%PCCLIBSSRCDIR:###"=%
+set PCCLIBSSRCDIR=%PCCLIBSSRCDIR:###=%
+
+if not '%PCCDIR%' == '' goto pccdirset
+set PCCDIR=C:\Program Files\pcc
+:pccdirset
+
+if not '%PCCSRCDIR%' == '' goto pccsrcdirset
+set PCCSRCDIR=..\..
+:pccsrcdirset
+
+if not '%PCCLIBSSRCDIR%' == '' goto pcclibssrcdirset
+set PCCLIBSSRCDIR=..\..\..\pcc-libs
+:pcclibssrcdirset
+
+if '%usecl%' == 'true' goto ccprefixed
+set CC="%PCCDIR%\bin\%CC%"
+set AR="%PCCDIR%\bin\%AR%"
+:ccprefixed
+
+set TARGOS=win32
+set MACH=i386
+set LIBEXECDIR=""
+
+set MIPDIR=%PCCSRCDIR%\mip
+set CPPDIR=%PCCSRCDIR%\cc\cpp
+set CCOMDIR=%PCCSRCDIR%\cc\ccom
+set CCDIR=%PCCSRCDIR%\cc\cc
+set OSDIR=%PCCSRCDIR%\os\%TARGOS%
+set MACHDIR=%PCCSRCDIR%\arch\%MACH%
+set BISON_SIMPLE=%OSDIR%\bison.simple
+set CPPFLAGS=-DWIN32 -DGCC_COMPAT -DPCC_DEBUG -DTARGOS="%TARGOS%" -Dos_%TARGOS% -DTARGMACH="%MACH%" -Dmach_%MACH% -DLIBEXECDIR=%LIBEXECDIR% -D_CRT_SECURE_NO_WARNINGS
+
+del *.obj *.o *.exe
+
+%CC% -o pcc.exe %CPPFLAGS% %CFLAGS% -I%CCDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% %CCDIR%\cc.c %MIPDIR%\compat.c
+
+bison -y -t -d --no-lines %CPPDIR%\cpy.y
+rem flex %CPPDIR%\scanner.l
+rem %CC% -o cpp.exe %CPPFLAGS% %CFLAGS% -I%CPPDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% -I. %CPPDIR%\cpp.c %MIPDIR%\compat.c y.tab.c lex.yy.c "C:\Program Files\UnxUtils\usr\local\lib\libfl.lib"
+%CC% -o cpp.exe %CPPFLAGS% %CFLAGS% -I%CPPDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% -I. %CPPDIR%\cpp.c %CPPDIR%\token.c %MIPDIR%\compat.c y.tab.c "C:\Program Files\UnxUtils\usr\local\lib\libfl.lib"
+
+%CC% -o mkext.exe -DMKEXT %CPPFLAGS% %CFLAGS% -I%CCOMDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% %MIPDIR%\mkext.c %MACHDIR%\table.c %MIPDIR%\common.c
+mkext
+bison -y -t -d --no-lines %CCOMDIR%\cgram.y
+move y.tab.c cgram.c
+move y.tab.h cgram.h
+flex %CCOMDIR%\scan.l
+move lex.yy.c scan.c
+
+%CC% -o ccom.exe %CPPFLAGS% %CFLAGS% -I%CCOMDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% -I. %CCOMDIR%\main.c %MIPDIR%\compat.c scan.c cgram.c external.c %CCOMDIR%\optim.c %CCOMDIR%\builtins.c %CCOMDIR%\pftn.c %CCOMDIR%\trees.c %CCOMDIR%\inline.c %CCOMDIR%\symtabs.c %CCOMDIR%\init.c %MACHDIR%\local.c %MACHDIR%\code.c %CCOMDIR%\stabs.c %CCOMDIR%\gcc_compat.c %MIPDIR%\match.c %MIPDIR%\reader.c %MIPDIR%\optim2.c %MIPDIR%\regs.c %MACHDIR%\local2.c %MACHDIR%\order.c %MACHDIR%\table.c %MIPDIR%\common.c "C:\Program Files\UnxUtils\usr\local\lib\libfl.lib"
+
+if not '%PREFIX%' == '' goto prefixset
+set PREFIX=C:\Program Files\pcc
+:prefixset
+
+set PCCDESTDIR=%PREFIX%
+set LIBPCCDESTDIR=%PREFIX%\lib\i386-win32\1.1.0
+
+set LIBPCCDIR=%PCCLIBSSRCDIR%\libpcc
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\_alloca.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\adddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\anddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ashldi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ashrdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\cmpdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\divdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixdfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixsfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixunsdfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixunssfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\floatdidf.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\floatdisf.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\floatunsdidf.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\iordi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\lshldi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\lshrdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\moddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\muldi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\negdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\notdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\qdivrem.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ssp.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\subdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ucmpdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\udivdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\umoddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\xordi3.c
+
+if '%usecl%' == 'false' %CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\_ftol.c
+if '%usecl%' == 'true' ml /nologo -c %LIBPCCDIR%\_ftol.asm
+
+%AR% %AR_OUT% _ftol.%OBJ% adddi3.%OBJ% anddi3.%OBJ% ashldi3.%OBJ% ashrdi3.%OBJ% cmpdi2.%OBJ% divdi3.%OBJ% fixdfdi.%OBJ% fixsfdi.%OBJ% fixunsdfdi.%OBJ% fixunssfdi.%OBJ% floatdidf.%OBJ% floatdisf.%OBJ% floatunsdidf.%OBJ% iordi3.%OBJ% lshldi3.%OBJ% lshrdi3.%OBJ% moddi3.%OBJ% muldi3.%OBJ% negdi2.%OBJ% notdi2.%OBJ% qdivrem.%OBJ% ssp.%OBJ% subdi3.%OBJ% ucmpdi2.%OBJ% udivdi3.%OBJ% umoddi3.%OBJ% xordi3.%OBJ%
+
+if not '%doinstall%' == 'true' goto end
+
+md "%PCCDESTDIR%"
+md "%PCCDESTDIR%\bin"
+md "%PCCDESTDIR%\libexec"
+md "%PCCDESTDIR%\man"
+md "%PCCDESTDIR%\man\man1"
+md "%LIBPCCDESTDIR%\lib"
+md "%LIBPCCDESTDIR%\include"
+
+copy pcc.exe "%PCCDESTDIR%\bin"
+copy cpp.exe "%PCCDESTDIR%\libexec"
+copy ccom.exe "%PCCDESTDIR%\libexec"
+
+copy libpcc.a "%LIBPCCDESTDIR%\lib"
+copy "%LIBPCCDIR%\include\*.h" "%LIBPCCDESTDIR%\include"
+
+copy "%CCDIR%\cc.1" "%PCCDESTDIR%\man\man1"
+copy "%CPPDIR%\cpp.1" "%PCCDESTDIR%\man\man1"
+copy "%CCOMDIR%\ccom.1" "%PCCDESTDIR%\man\man1"
+
+:end
diff --git a/lang/pcc/pcc/os/win32/build_installer.bat b/lang/pcc/pcc/os/win32/build_installer.bat
new file mode 100755 (executable)
index 0000000..3239028
--- /dev/null
@@ -0,0 +1 @@
+"C:\Program Files\Inno Setup 5\ISCC.exe" /DAppName="PCC" /DAppVersion="1.1.x" /DAppNameLower="pcc" pcc.iss
diff --git a/lang/pcc/pcc/os/win32/ccconfig.h b/lang/pcc/pcc/os/win32/ccconfig.h
new file mode 100644 (file)
index 0000000..cb7c634
--- /dev/null
@@ -0,0 +1,41 @@
+/*     $Id: ccconfig.h,v 1.19 2014/12/24 12:35:38 plunky Exp $ */
+
+/*
+ * Currently only supports console applications.
+ */
+
+#if defined(MSLINKER)
+/* requires microsoft toolkit headers and linker, and pcc-libs */
+#define CPPADD         { "-DWIN32", "-D_WIN32", NULL }
+#define DEFLIBS                { "/subsystem:console", "msvcrt.lib", "libpcc.a", NULL }
+#else
+/* common cpp predefines */
+#define CPPADD         { "-DWIN32", "-D_WIN32", "-D__MSVCRT__", "-D__MINGW32__", NULL }
+
+/* host-dependent */
+/* requires w32api-3.2.tar.gz and mingw-runtime-3.14.tar.gz */
+#define CRT0           "crt2.o"
+#define STARTLABEL     "_mainCRTStartup"
+#define CRT0_S         "dllcrt2.o"
+#define STARTLABEL_S   "_DllMainCRTStartup@12"
+#define GCRT0          "gcrt2.o"       /* in _addition_ to either crt2.o or dllcrt2.o */
+
+#define CRTBEGIN       0       /* No constructor/destructor support for now */
+#define CRTEND         0
+#define CRTBEGIN_S     0
+#define CRTEND_S       0
+#define CRTBEGIN_T     0       /* Note: MingW cannot do -static linking */
+#define CRTEND_T       0
+#define CRTI           0
+#define CRTN           0
+
+#define WIN32_LIBC     "-lmsvcrt"
+#define MINGW_RTLIBS   "-lmoldname", "-lmingwex", "-lmingw32"
+#define MINGW_SYSLIBS  "-luser32", "-lkernel32" /* ,"-ladvapi32", "-lshell32" */
+#define DEFLIBS                { MINGW_RTLIBS, "-lpcc", WIN32_LIBC, MINGW_SYSLIBS, MINGW_RTLIBS, WIN32_LIBC, 0 }
+#define DEFPROFLIBS    { MINGW_RTLIBS, "-lpcc", WIN32_LIBC, "-lgmon", MINGW_SYSLIBS, MINGW_RTLIBS, WIN32_LIBC, 0 }
+#define DEFCXXLIBS     { "-lp++", MINGW_RTLIBS, "-lpcc", WIN32_LIBC, MINGW_SYSLIBS, MINGW_RTLIBS, WIN32_LIBC, 0 }
+
+#endif
+
+#define CPPMDADD { "-D__i386__", NULL }
diff --git a/lang/pcc/pcc/os/win32/config.h b/lang/pcc/pcc/os/win32/config.h
new file mode 100644 (file)
index 0000000..f4532b7
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Config file for visual studio build
+ */
+#define PREPROCESSOR "%PCCDIR%\\libexec\\cpp.exe"
+#define COMPILER "%PCCDIR%\\libexec\\ccom.exe"
+
+#define USE_YASM
+
+#ifdef USE_YASM
+#define ASSEMBLER "yasm.exe"
+#else
+#define ASSEMBLER "gas.exe"
+#endif
+
+#ifdef USE_MSLINKER
+#define LINKER "link.exe /nologo"
+#define MSLINKER
+#else
+#define LINKER "ld.exe"
+#endif
+
+
+#define PECOFFABI
+
+#define STDINC "%PCCDIR%\\include\\"
+#define LIBDIR "%PCCDIR%\\lib\\"
+#define INCLUDEDIR STDINC
+#define PCCLIBDIR "%PCCDIR%\\lib\\i386-win32\\1.1.0\\lib\\"
+#define PCCINCDIR "%PCCDIR%\\lib\\i386-win32\\1.1.0\\include\\"
+
+#if !defined(vsnprintf)
+#define vsnprintf _vsnprintf
+#endif
+/* windows defines (u)uintptr_t in stddef.h, not inttypes.h */
+#include <stddef.h>
+#if !defined(snprintf)
+#define snprintf _snprintf
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#define inline __inline
+
+/* #define HAVE_INTTYPES_H 1 */
+#define HAVE_MEMORY_H 1
+/* #define HAVE_MKSTEMP 1 */
+
+#ifndef __MSC__
+#define HAVE_STDINT_H 1
+#endif
+
+#define HAVE_STDLIB_H 1
+/* #define HAVE_STRINGS_H 1 */
+#define HAVE_STRING_H 1
+/* #define HAVE_STRLCAT 1 */
+/* #define HAVE_STRLCPY 1 */
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SNPRINTF 1
+#define HAVE_VSNPRINTF 1
+/* #define HAVE_UNISTD_H 1 */
+/* #define HOST_BIG_ENDIAN  */
+#define HOST_LITTLE_ENDIAN
+
+#define PACKAGE_NAME "pcc"
+#define PACKAGE_STRING "pcc 1.1.0"
+#define PACKAGE_TARNAME "pcc"
+#define PACKAGE_VERSION "1.1.0"
+#define PCC_MAJOR 1
+#define PCC_MINOR 1
+#define PCC_MINORMINOR 0
+#define STDC_HEADERS 1
+#define TARGET_LITTLE_ENDIAN 1
+#define VERSSTR "pcc 1.1.0 for win32, gmcgarry@pcc.ludd.ltu.se"
+#define WCHAR_SIZE 2
+#define WCHAR_TYPE USHORT
+#define YYTEXT_POINTER 1
diff --git a/lang/pcc/pcc/os/win32/pcc.iss b/lang/pcc/pcc/os/win32/pcc.iss
new file mode 100644 (file)
index 0000000..88640ab
--- /dev/null
@@ -0,0 +1,93 @@
+[Setup]\r
+AppName={#AppName}\r
+AppID={#AppNameLower}\r
+AppVerName={#AppName} {#AppVersion}\r
+AppPublisher=PCC Project\r
+AppPublisherURL=http://pcc.ludd.ltu.se/\r
+DefaultDirName={pf}\{#AppNameLower}\r
+DefaultGroupName={#AppName}\r
+Compression=lzma/ultra\r
+InternalCompressLevel=ultra\r
+SolidCompression=yes\r
+OutputDir=.\r
+OutputBaseFilename={#AppNameLower}-{#AppVersion}-win32\r
+ChangesEnvironment=yes\r
+\r
+[Files]\r
+Source: "c:\Program Files\{#AppNameLower}\*.*"; DestDir: {app}; Flags: recursesubdirs\r
+\r
+[Icons]\r
+Name: {group}\{cm:UninstallProgram, {#AppName}}; FileName: {uninstallexe}\r
+\r
+[Registry]\r
+Root: HKLM; Subkey: System\CurrentControlSet\Control\Session Manager\Environment; ValueName: {#AppName}DIR; ValueType: string; ValueData: {app}; Flags: deletevalue\r
+\r
+[Tasks]\r
+Name: modifypath; Description: Add application directory to your system path; Flags: unchecked\r
+\r
+[Code]\r
+\r
+// Jared Breland <jbreland@legroom.net>\r
+// http://www.legroom.net/software/modpath\r
+\r
+procedure ModPath(BinDir : String);\r
+var\r
+       oldpath : String;\r
+       newpath : String;\r
+       pathArr : TArrayOfString;\r
+       i : Integer;\r
+begin\r
+       RegQueryStringValue(HKEY_LOCAL_MACHINE, 'System\CurrentControlSet\Control\Session Manager\Environment', 'Path', oldpath);\r
+       oldpath := oldpath + ';';\r
+       i := 0;\r
+       while (Pos(';', oldpath) > 0) do begin\r
+               SetArrayLength(pathArr, i+1);\r
+               pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath) - 1);\r
+               oldpath := Copy(oldpath, Pos(';', oldpath) + 1, Length(oldpath));\r
+               i := i + 1;\r
+\r
+               if BinDir = pathArr[i-1] then\r
+                       if IsUninstaller() = true then begin\r
+                               continue;\r
+                       end else begin\r
+                               abort;\r
+                       end;\r
+\r
+               if i = 1 then begin\r
+                       newpath := pathArr[i-1];\r
+               end else begin\r
+                       newpath := newpath + ';' + pathArr[i-1];\r
+               end;\r
+       end;\r
+\r
+       if IsUninstaller() = false then\r
+               newpath := newpath + ';' + BinDir;\r
+\r
+       RegWriteStringValue(HKEY_LOCAL_MACHINE, 'System\CurrentControlSet\Control\Session Manager\Environment', 'Path', newpath);\r
+end;\r
+               \r
+procedure CurStepChanged(CurStep : TSetupStep);\r
+var\r
+       appdir : String;\r
+begin\r
+       if CurStep = ssPostInstall then\r
+               if IsTaskSelected('modifypath') then begin\r
+                       appdir := ExpandConstant('{app}');\r
+                       ModPath(appdir + '\bin');\r
+                       SaveStringToFile(appdir + '\uninsTasks.txt', WizardSelectedTasks(False), False);\r
+               end;\r
+end;\r
+\r
+procedure CurUninstallStepChanged(CurUninstallStep : TUninstallStep);\r
+var\r
+       appdir : String;\r
+       selectedTasks : String;\r
+begin\r
+       if CurUninstallStep = usUninstall then begin\r
+               appdir := ExpandConstant('{app}');\r
+               if LoadStringFromFile(appdir + '\uninsTasks.txt', selectedTasks) then\r
+                       if (Pos('modifypath', selectedTasks) > 0) then\r
+                               ModPath(appdir + '\bin');\r
+                       DeleteFile(appdir + '\uninsTasks.txt')\r
+       end;\r
+end;\r