ref: 1900acf7ad612d4f40701ad9b32434579c269304
author: kws <kws@cirno>
date: Wed Nov 29 22:10:52 EST 2023
basic efi
--- /dev/null
+++ b/NOTICE
@@ -1,0 +1,35 @@
+Thanks Tim Weiss for the original 4[acl] compilers based on earlier work from the Labs.
+
+Thanks Cherry (Zhang) Mui for her Loongson work based off of Tim Weiss' compilers.
+
+Thanks Richard Miller for his RISC-V work which served as a useful reference.
+
+The LoongArch linker (zl) contains some definitions derived from the Go LoongArch sources:
+
+Copyright (c) 2009 The Go Authors. 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 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.
+ * Neither the name of Google Inc. 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 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
+OWNER 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.
--- /dev/null
+++ b/bind.rc
@@ -1,0 +1,10 @@
+#!/bin/rc
+
+bind -a . /
+bind -b sys/include /sys/include
+bind -bc sys/src/libmach /sys/src/libmach
+bind -bc sys/src/boot/efi /sys/src/boot/efi
+bind -ac sys/src/cmd /sys/src/cmd
+bind -c sys/src/cmd/aux/aout2efi.c /sys/src/cmd/aux/aout2efi.c
+bind -c sys/lib/rootstub /sys/lib/rootstub
+bind -c sys/src/mkfile.proto /sys/src/mkfile.proto
--- /dev/null
+++ b/loong/include/u.h
@@ -1,0 +1,79 @@
+// TODO: LoongArch
+
+#define nil ((void*)0)
+
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef signed char schar;
+typedef long long vlong;
+typedef unsigned long long uvlong;
+typedef vlong intptr;
+typedef uvlong uintptr;
+typedef unsigned long long usize;
+typedef uint Rune;
+typedef union FPdbleword FPdbleword;
+typedef uintptr jmp_buf[2];
+#define JMPBUFSP 0
+#define JMPBUFPC 1
+#define JMPBUFDPC 0
+typedef unsigned int mpdigit; /* for /sys/include/mp.h */
+typedef unsigned char u8int;
+typedef unsigned short u16int;
+typedef unsigned int u32int;
+typedef unsigned long long u64int;
+typedef signed char s8int;
+typedef signed short s16int;
+typedef signed int s32int;
+typedef signed long long s64int;
+
+/* FPCR (control) */
+#define FPINEX (1<<12)
+#define FPUNFL (1<<11)
+#define FPOVFL (1<<10)
+#define FPZDIV (1<<9)
+#define FPINVAL (1<<8)
+
+#define FPRNR (0<<22)
+#define FPRPINF (1<<22)
+#define FPRNINF (2<<22)
+#define FPRZ (3<<22)
+
+#define FPRMASK (3<<22)
+
+/* FPSR (status) */
+#define FPPEXT 0
+#define FPPSGL 0
+#define FPPDBL 0
+#define FPPMASK 0
+#define FPAINEX (1<<4)
+#define FPAUNFL (1<<3)
+#define FPAOVFL (1<<2)
+#define FPAZDIV (1<<1)
+#define FPAINVAL (1<<0)
+
+union FPdbleword
+{
+ double x;
+ struct { /* little endian */
+ ulong lo;
+ ulong hi;
+ };
+};
+
+typedef char* va_list;
+#define va_start(list, start) list =\
+ (sizeof(start) < 8?\
+ (char*)((vlong*)&(start)+1):\
+ (char*)(&(start)+1))
+#define va_end(list)\
+ USED(list)
+#define va_arg(list, mode)\
+ ((sizeof(mode) == 1)?\
+ ((list += 8), (mode*)list)[-8]:\
+ (sizeof(mode) == 2)?\
+ ((list += 8), (mode*)list)[-4]:\
+ (sizeof(mode) == 4)?\
+ ((list += 8), (mode*)list)[-2]:\
+ ((list += sizeof(mode)), (mode*)list)[-1])
--- /dev/null
+++ b/loong/include/ureg.h
@@ -1,0 +1,42 @@
+// TODO: LoongArch
+
+typedef struct Ureg {
+ u64int r0;
+ u64int r1;
+ u64int r2;
+ u64int r3;
+ u64int r4;
+ u64int r5;
+ u64int r6;
+ u64int r7;
+ u64int r8;
+ u64int r9;
+ u64int r10;
+ u64int r11;
+ u64int r12;
+ u64int r13;
+ u64int r14;
+ u64int r15;
+ u64int r16;
+ u64int r17;
+ u64int r18;
+ u64int r19;
+ u64int r20;
+ u64int r21;
+ u64int r22;
+ u64int r23;
+ u64int r24;
+ u64int r25;
+ u64int r26;
+ u64int r27;
+ u64int r28; /* sb */
+ u64int r29;
+ union {
+ u64int r30;
+ u64int link;
+ };
+ u64int sp;
+ u64int pc; /* interrupted addr */
+ u64int psr;
+ u64int type; /* of exception */
+} Ureg;
--- /dev/null
+++ b/loong/mkfile
@@ -1,0 +1,6 @@
+</sys/src/mkfile.proto
+
+CC=zc
+LD=zl
+AS=za
+O=z
--- /dev/null
+++ b/sys/include/a.out.h
@@ -1,0 +1,48 @@
+typedef struct Exec Exec;
+struct Exec
+{
+ long magic; /* magic number */
+ long text; /* size of text segment */
+ long data; /* size of initialized data */
+ long bss; /* size of uninitialized data */
+ long syms; /* size of symbol table */
+ long entry; /* entry point */
+ long spsz; /* size of pc/sp offset table */
+ long pcsz; /* size of pc/line number table */
+};
+
+#define HDR_MAGIC 0x00008000 /* header expansion */
+
+#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
+#define A_MAGIC _MAGIC(0, 8) /* 68020 */
+#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
+#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
+#define K_MAGIC _MAGIC(0, 13) /* sparc */
+#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
+#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
+#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
+#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
+#define E_MAGIC _MAGIC(0, 20) /* arm */
+#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
+#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
+#define L_MAGIC _MAGIC(0, 23) /* dec alpha (retired) */
+#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
+#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
+#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
+#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
+#define R_MAGIC _MAGIC(HDR_MAGIC, 28) /* arm64 */
+#define Z_MAGIC _MAGIC(HDR_MAGIC, 29) /* loong */
+
+#define MIN_MAGIC 8
+#define MAX_MAGIC 28 /* <= 90 */
+
+#define DYN_MAGIC 0x80000000 /* dlm */
+
+typedef struct Sym Sym;
+struct Sym
+{
+ vlong value;
+ uint sig;
+ char type;
+ char *name;
+};
--- /dev/null
+++ b/sys/include/mach.h
@@ -1,0 +1,331 @@
+/*
+ * Architecture-dependent application data
+ */
+#include "a.out.h"
+#pragma src "/sys/src/libmach"
+#pragma lib "libmach.a"
+/*
+ * Supported architectures:
+ * mips,
+ * 68020,
+ * i386,
+ * amd64,
+ * sparc,
+ * sparc64,
+ * mips2 (R4000)
+ * arm
+ * powerpc,
+ * powerpc64
+ * alpha
+ * arm64
+ * loong
+ */
+enum
+{
+ MMIPS, /* machine types */
+ MSPARC,
+ M68020,
+ MI386,
+ MI960, /* retired */
+ M3210, /* retired */
+ MMIPS2,
+ NMIPS2,
+ M29000, /* retired */
+ MARM,
+ MPOWER,
+ MALPHA,
+ NMIPS,
+ MSPARC64,
+ MAMD64,
+ MPOWER64,
+ MARM64,
+ MLOONG,
+ /* types of executables */
+ FNONE = 0, /* unidentified */
+ FMIPS, /* v.out */
+ FMIPSB, /* mips bootable */
+ FSPARC, /* k.out */
+ FSPARCB, /* Sparc bootable */
+ F68020, /* 2.out */
+ F68020B, /* 68020 bootable */
+ FNEXTB, /* Next bootable */
+ FI386, /* 8.out */
+ FI386B, /* I386 bootable */
+ FI960, /* retired */
+ FI960B, /* retired */
+ F3210, /* retired */
+ FMIPS2BE, /* 4.out */
+ F29000, /* retired */
+ FARM, /* 5.out */
+ FARMB, /* ARM bootable */
+ FPOWER, /* q.out */
+ FPOWERB, /* power pc bootable */
+ FMIPS2LE, /* 0.out */
+ FALPHA, /* 7.out */
+ FALPHAB, /* DEC Alpha bootable */
+ FMIPSLE, /* 3k little endian */
+ FSPARC64, /* u.out */
+ FAMD64, /* 6.out */
+ FAMD64B, /* 6.out bootable */
+ FPOWER64, /* 9.out */
+ FPOWER64B, /* 9.out bootable */
+ FARM64, /* arm64 */
+ FARM64B, /* arm64 bootable */
+ FLOONG, /* loong */
+ FLOONGB, /* loong bootable */
+
+ ANONE = 0, /* dissembler types */
+ AMIPS,
+ AMIPSCO, /* native mips */
+ ASPARC,
+ ASUNSPARC, /* native sun */
+ A68020,
+ AI386,
+ AI8086, /* oh god */
+ AI960, /* retired */
+ A29000, /* retired */
+ AARM,
+ APOWER,
+ AALPHA,
+ ASPARC64,
+ AAMD64,
+ APOWER64,
+ AARM64,
+ ALOONG,
+ /* object file types */
+ Obj68020 = 0, /* .2 */
+ ObjSparc, /* .k */
+ ObjMips, /* .v */
+ Obj386, /* .8 */
+ Obj960, /* retired */
+ Obj3210, /* retired */
+ ObjMips2, /* .4 */
+ Obj29000, /* retired */
+ ObjArm, /* .5 */
+ ObjPower, /* .q */
+ ObjMips2le, /* .0 */
+ ObjAlpha, /* .7 */
+ ObjSparc64, /* .u */
+ ObjAmd64, /* .6 */
+ ObjSpim, /* .0 */
+ ObjPower64, /* .9 */
+ ObjArm64, /* .4? */
+ ObjLoong, /* .z */
+ Maxobjtype,
+
+ CNONE = 0, /* symbol table classes */
+ CAUTO,
+ CPARAM,
+ CSTAB,
+ CTEXT,
+ CDATA,
+ CANY, /* to look for any class */
+};
+
+typedef struct Map Map;
+typedef struct Symbol Symbol;
+typedef struct Reglist Reglist;
+typedef struct Mach Mach;
+typedef struct Machdata Machdata;
+
+/*
+ * Structure to map a segment to a position in a file
+ */
+struct Map {
+ int nsegs; /* number of segments */
+ struct segment { /* per-segment map */
+ char *name; /* the segment name */
+ int fd; /* file descriptor */
+ long (*read)(int, void *, long, vlong);
+ int inuse; /* in use - not in use */
+ int cache; /* should cache reads? */
+ uvlong b; /* base */
+ uvlong e; /* end */
+ vlong f; /* offset within file */
+ } seg[1]; /* actually n of these */
+};
+
+/*
+ * Internal structure describing a symbol table entry
+ */
+struct Symbol {
+ void *handle; /* used internally - owning func */
+ struct {
+ char *name;
+ vlong value; /* address or stack offset */
+ char type; /* as in a.out.h */
+ char class; /* as above */
+ int index; /* in findlocal, globalsym, textsym */
+ };
+};
+
+/*
+ * machine register description
+ */
+struct Reglist {
+ char *rname; /* register name */
+ short roffs; /* offset in u-block */
+ char rflags; /* INTEGER/FLOAT, WRITABLE */
+ char rformat; /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */
+};
+
+enum { /* bits in rflags field */
+ RINT = (0<<0),
+ RFLT = (1<<0),
+ RRDONLY = (1<<1),
+};
+
+/*
+ * Machine-dependent data is stored in two structures:
+ * Mach - miscellaneous general parameters
+ * Machdata - jump vector of service functions used by debuggers
+ *
+ * Mach is defined in ?.c and set in executable.c
+ *
+ * Machdata is defined in ?db.c
+ * and set in the debugger startup.
+ */
+struct Mach{
+ char *name;
+ int mtype; /* machine type code */
+ Reglist *reglist; /* register set */
+ long regsize; /* sizeof registers in bytes */
+ long fpregsize; /* sizeof fp registers in bytes */
+ char *pc; /* pc name */
+ char *sp; /* sp name */
+ char *link; /* link register name */
+ char *sbreg; /* static base register name */
+ uvlong sb; /* static base register value */
+ int pgsize; /* page size */
+ uvlong kbase; /* kernel base address */
+ uvlong ktmask; /* ktzero = kbase & ~ktmask */
+ uvlong utop; /* user stack top */
+ int pcquant; /* quantization of pc */
+ int szaddr; /* sizeof(void*) */
+ int szreg; /* sizeof(register) */
+ int szfloat; /* sizeof(float) */
+ int szdouble; /* sizeof(double) */
+};
+
+extern Mach *mach; /* Current machine */
+
+typedef uvlong (*Rgetter)(Map*, char*);
+typedef void (*Tracer)(Map*, uvlong, uvlong, Symbol*);
+
+struct Machdata { /* Machine-dependent debugger support */
+ uchar bpinst[4]; /* break point instr. */
+ short bpsize; /* size of break point instr. */
+
+ ushort (*swab)(ushort); /* ushort to local byte order */
+ ulong (*swal)(ulong); /* ulong to local byte order */
+ uvlong (*swav)(uvlong); /* uvlong to local byte order */
+ int (*ctrace)(Map*, uvlong, uvlong, uvlong, Tracer); /* C traceback */
+ uvlong (*findframe)(Map*, uvlong, uvlong, uvlong, uvlong);/* frame finder */
+ char* (*excep)(Map*, Rgetter); /* last exception */
+ ulong (*bpfix)(uvlong); /* breakpoint fixup */
+ int (*sftos)(char*, int, void*); /* single precision float */
+ int (*dftos)(char*, int, void*); /* double precision float */
+ int (*foll)(Map*, uvlong, Rgetter, uvlong*);/* follow set */
+ int (*das)(Map*, uvlong, char, char*, int); /* symbolic disassembly */
+ int (*hexinst)(Map*, uvlong, char*, int); /* hex disassembly */
+ int (*instsize)(Map*, uvlong); /* instruction size */
+};
+
+/*
+ * Common a.out header describing all architectures
+ */
+typedef struct Fhdr
+{
+ char *name; /* identifier of executable */
+ uchar type; /* file type - see codes above */
+ uchar hdrsz; /* header size */
+ uchar _magic; /* _MAGIC() magic */
+ uchar spare;
+ long magic; /* magic number */
+ uvlong txtaddr; /* text address */
+ vlong txtoff; /* start of text in file */
+ uvlong dataddr; /* start of data segment */
+ vlong datoff; /* offset to data seg in file */
+ vlong symoff; /* offset of symbol table in file */
+ uvlong entry; /* entry point */
+ vlong sppcoff; /* offset of sp-pc table in file */
+ vlong lnpcoff; /* offset of line number-pc table in file */
+ long txtsz; /* text size */
+ long datsz; /* size of data seg */
+ long bsssz; /* size of bss */
+ long symsz; /* size of symbol table */
+ long sppcsz; /* size of sp-pc table */
+ long lnpcsz; /* size of line number-pc table */
+} Fhdr;
+
+extern int asstype; /* dissembler type - machdata.c */
+extern Machdata *machdata; /* jump vector - machdata.c */
+
+Map* attachproc(int, int, int, Fhdr*);
+int beieee80ftos(char*, int, void*);
+int beieeesftos(char*, int, void*);
+int beieeedftos(char*, int, void*);
+ushort beswab(ushort);
+ulong beswal(ulong);
+uvlong beswav(uvlong);
+uvlong ciscframe(Map*, uvlong, uvlong, uvlong, uvlong);
+int cisctrace(Map*, uvlong, uvlong, uvlong, Tracer);
+int crackhdr(int fd, Fhdr*);
+uvlong file2pc(char*, long);
+int fileelem(Sym**, uchar *, char*, int);
+long fileline(char*, int, uvlong);
+int filesym(int, char*, int);
+int findlocal(Symbol*, char*, Symbol*);
+int findseg(Map*, char*);
+int findsym(uvlong, int, Symbol *);
+int fnbound(uvlong, uvlong*);
+int fpformat(Map*, Reglist*, char*, int, int);
+int get1(Map*, uvlong, uchar*, int);
+int get2(Map*, uvlong, ushort*);
+int get4(Map*, uvlong, ulong*);
+int get8(Map*, uvlong, uvlong*);
+int geta(Map*, uvlong, uvlong*);
+int getauto(Symbol*, int, int, Symbol*);
+Sym* getsym(int);
+int globalsym(Symbol *, int);
+char* _hexify(char*, ulong, int);
+int ieeesftos(char*, int, ulong);
+int ieeedftos(char*, int, ulong, ulong);
+int isar(Biobuf*);
+int leieee80ftos(char*, int, void*);
+int leieeesftos(char*, int, void*);
+int leieeedftos(char*, int, void*);
+ushort leswab(ushort);
+ulong leswal(ulong);
+uvlong leswav(uvlong);
+uvlong line2addr(long, uvlong, uvlong);
+Map* loadmap(Map*, int, Fhdr*);
+int localaddr(Map*, char*, char*, uvlong*, Rgetter);
+int localsym(Symbol*, int);
+int lookup(char*, char*, Symbol*);
+void machbytype(int);
+int machbyname(char*);
+int nextar(Biobuf*, int, char*);
+Map* newmap(Map*, int);
+void objtraverse(void(*)(Sym*, void*), void*);
+int objtype(Biobuf*, char**);
+uvlong pc2sp(uvlong);
+long pc2line(uvlong);
+int put1(Map*, uvlong, uchar*, int);
+int put2(Map*, uvlong, ushort);
+int put4(Map*, uvlong, ulong);
+int put8(Map*, uvlong, uvlong);
+int puta(Map*, uvlong, uvlong);
+int readar(Biobuf*, int, vlong, int);
+int readobj(Biobuf*, int);
+uvlong riscframe(Map*, uvlong, uvlong, uvlong, uvlong);
+int risctrace(Map*, uvlong, uvlong, uvlong, Tracer);
+int setmap(Map*, int, uvlong, uvlong, vlong, char*);
+Sym* symbase(long*);
+int syminit(int, Fhdr*);
+int symoff(char*, int, uvlong, int);
+void textseg(uvlong, Fhdr*);
+int textsym(Symbol*, int);
+void thumbpctab(int, Fhdr*);
+int thumbpclookup(uvlong);
+void unusemap(Map*, int);
--- /dev/null
+++ b/sys/lib/rootstub
@@ -1,0 +1,254 @@
+mkdir -p 386/bin/ape
+mkdir -p 386/bin/audio
+mkdir -p 386/bin/auth
+mkdir -p 386/bin/aux
+mkdir -p 386/bin/bitsy
+mkdir -p 386/bin/dial
+mkdir -p 386/bin/disk
+mkdir -p 386/bin/fs
+mkdir -p 386/bin/games
+mkdir -p 386/bin/ip/httpd
+mkdir -p 386/bin/ndb
+mkdir -p 386/bin/nusb
+mkdir -p 386/bin/replica
+mkdir -p 386/bin/upas
+mkdir -p 386/bin/venti
+mkdir -p 386/lib/ape
+mkdir -p 68000/bin/ape
+mkdir -p 68000/bin/audio
+mkdir -p 68000/bin/auth
+mkdir -p 68000/bin/aux
+mkdir -p 68000/bin/bitsy
+mkdir -p 68000/bin/dial
+mkdir -p 68000/bin/disk
+mkdir -p 68000/bin/fs
+mkdir -p 68000/bin/games
+mkdir -p 68000/bin/ip/httpd
+mkdir -p 68000/bin/ndb
+mkdir -p 68000/bin/nusb
+mkdir -p 68000/bin/replica
+mkdir -p 68000/bin/upas
+mkdir -p 68000/bin/venti
+mkdir -p 68000/lib/ape
+mkdir -p 68020/bin/ape
+mkdir -p 68020/bin/audio
+mkdir -p 68020/bin/auth
+mkdir -p 68020/bin/aux
+mkdir -p 68020/bin/bitsy
+mkdir -p 68020/bin/dial
+mkdir -p 68020/bin/disk
+mkdir -p 68020/bin/fs
+mkdir -p 68020/bin/games
+mkdir -p 68020/bin/ip/httpd
+mkdir -p 68020/bin/ndb
+mkdir -p 68020/bin/nusb
+mkdir -p 68020/bin/replica
+mkdir -p 68020/bin/upas
+mkdir -p 68020/bin/venti
+mkdir -p 68020/lib/ape
+mkdir -p acme/bin/amd64
+mkdir -p acme/bin/386
+mkdir -p acme/bin/arm
+mkdir -p acme/bin/arm64
+mkdir -p acme/bin/loong
+mkdir -p acme/bin/dial
+mkdir -p acme/bin/mips
+mkdir -p acme/bin/spim
+mkdir -p acme/bin/power
+mkdir -p acme/bin/power64
+mkdir -p acme/bin/sparc
+mkdir -p acme/bin/sparc64
+mkdir -p amd64/bin/ape
+mkdir -p amd64/bin/audio
+mkdir -p amd64/bin/auth
+mkdir -p amd64/bin/aux
+mkdir -p amd64/bin/bitsy
+mkdir -p amd64/bin/dial
+mkdir -p amd64/bin/disk
+mkdir -p amd64/bin/fs
+mkdir -p amd64/bin/games
+mkdir -p amd64/bin/ip/httpd
+mkdir -p amd64/bin/ndb
+mkdir -p amd64/bin/nusb
+mkdir -p amd64/bin/replica
+mkdir -p amd64/bin/upas
+mkdir -p amd64/bin/venti
+mkdir -p amd64/lib/ape
+mkdir -p arm/bin/ape
+mkdir -p arm/bin/audio
+mkdir -p arm/bin/auth
+mkdir -p arm/bin/aux
+mkdir -p arm/bin/bitsy
+mkdir -p arm/bin/dial
+mkdir -p arm/bin/disk
+mkdir -p arm/bin/fs
+mkdir -p arm/bin/games
+mkdir -p arm/bin/ip/httpd
+mkdir -p arm/bin/ndb
+mkdir -p arm/bin/nusb
+mkdir -p arm/bin/replica
+mkdir -p arm/bin/upas
+mkdir -p arm/bin/venti
+mkdir -p arm/lib/ape
+mkdir -p arm64/bin/ape
+mkdir -p arm64/bin/audio
+mkdir -p arm64/bin/auth
+mkdir -p arm64/bin/aux
+mkdir -p arm64/bin/bitsy
+mkdir -p arm64/bin/dial
+mkdir -p arm64/bin/disk
+mkdir -p arm64/bin/fs
+mkdir -p arm64/bin/games
+mkdir -p arm64/bin/ip/httpd
+mkdir -p arm64/bin/ndb
+mkdir -p arm64/bin/nusb
+mkdir -p arm64/bin/replica
+mkdir -p arm64/bin/upas
+mkdir -p arm64/bin/venti
+mkdir -p arm64/lib/ape
+mkdir -p loong/bin/ape
+mkdir -p loong/bin/audio
+mkdir -p loong/bin/auth
+mkdir -p loong/bin/aux
+mkdir -p loong/bin/bitsy
+mkdir -p loong/bin/dial
+mkdir -p loong/bin/disk
+mkdir -p loong/bin/fs
+mkdir -p loong/bin/games
+mkdir -p loong/bin/ip/httpd
+mkdir -p loong/bin/ndb
+mkdir -p loong/bin/nusb
+mkdir -p loong/bin/replica
+mkdir -p loong/bin/upas
+mkdir -p loong/bin/venti
+mkdir -p loong/lib/ape
+mkdir -p cfg/pxe
+mkdir -p cron
+mkdir -p dist/plan9front
+mkdir -p lib/audio/icon
+mkdir -p lib/firmware
+mkdir -p lib/ndb/dhcp
+mkdir -p lib/news
+mkdir -p mail/box/glenda/mbox
+mkdir -p mail/faxoutqueue
+mkdir -p mail/faxqueue
+mkdir -p mail/fs
+mkdir -p mail/grey
+mkdir -p mail/lib
+mkdir -p mail/queue
+mkdir -p mail/tmp
+mkdir -p mips/bin/ape
+mkdir -p mips/bin/audio
+mkdir -p mips/bin/auth
+mkdir -p mips/bin/aux
+mkdir -p mips/bin/bitsy
+mkdir -p mips/bin/dial
+mkdir -p mips/bin/disk
+mkdir -p mips/bin/fs
+mkdir -p mips/bin/games
+mkdir -p mips/bin/ip/httpd
+mkdir -p mips/bin/ndb
+mkdir -p mips/bin/nusb
+mkdir -p mips/bin/replica
+mkdir -p mips/bin/upas
+mkdir -p mips/bin/venti
+mkdir -p mips/lib/ape
+mkdir -p spim/bin/ape
+mkdir -p spim/bin/audio
+mkdir -p spim/bin/auth
+mkdir -p spim/bin/aux
+mkdir -p spim/bin/bitsy
+mkdir -p spim/bin/dial
+mkdir -p spim/bin/disk
+mkdir -p spim/bin/fs
+mkdir -p spim/bin/games
+mkdir -p spim/bin/ip/httpd
+mkdir -p spim/bin/ndb
+mkdir -p spim/bin/nusb
+mkdir -p spim/bin/replica
+mkdir -p spim/bin/upas
+mkdir -p spim/bin/venti
+mkdir -p spim/lib/ape
+mkdir -p power/bin/ape
+mkdir -p power/bin/audio
+mkdir -p power/bin/auth
+mkdir -p power/bin/aux
+mkdir -p power/bin/bitsy
+mkdir -p power/bin/dial
+mkdir -p power/bin/disk
+mkdir -p power/bin/fs
+mkdir -p power/bin/games
+mkdir -p power/bin/ip/httpd
+mkdir -p power/bin/ndb
+mkdir -p power/bin/nusb
+mkdir -p power/bin/replica
+mkdir -p power/bin/upas
+mkdir -p power/bin/venti
+mkdir -p power/lib/ape
+mkdir -p power64/bin/ape
+mkdir -p power64/bin/audio
+mkdir -p power64/bin/auth
+mkdir -p power64/bin/aux
+mkdir -p power64/bin/bitsy
+mkdir -p power64/bin/dial
+mkdir -p power64/bin/disk
+mkdir -p power64/bin/fs
+mkdir -p power64/bin/games
+mkdir -p power64/bin/ip/httpd
+mkdir -p power64/bin/ndb
+mkdir -p power64/bin/nusb
+mkdir -p power64/bin/replica
+mkdir -p power64/bin/upas
+mkdir -p power64/bin/venti
+mkdir -p power64/lib/ape
+mkdir -p rc/bin/aux
+mkdir -p rc/bin/postscript
+mkdir -p rc/lib/ape
+mkdir -p sparc/bin/ape
+mkdir -p sparc/bin/audio
+mkdir -p sparc/bin/auth
+mkdir -p sparc/bin/aux
+mkdir -p sparc/bin/bitsy
+mkdir -p sparc/bin/dial
+mkdir -p sparc/bin/disk
+mkdir -p sparc/bin/fs
+mkdir -p sparc/bin/games
+mkdir -p sparc/bin/ip/httpd
+mkdir -p sparc/bin/ndb
+mkdir -p sparc/bin/nusb
+mkdir -p sparc/bin/replica
+mkdir -p sparc/bin/upas
+mkdir -p sparc/bin/venti
+mkdir -p sparc/lib/ape
+mkdir -p sparc64/bin/ape
+mkdir -p sparc64/bin/audio
+mkdir -p sparc64/bin/auth
+mkdir -p sparc64/bin/aux
+mkdir -p sparc64/bin/bitsy
+mkdir -p sparc64/bin/dial
+mkdir -p sparc64/bin/disk
+mkdir -p sparc64/bin/fs
+mkdir -p sparc64/bin/games
+mkdir -p sparc64/bin/ip/httpd
+mkdir -p sparc64/bin/ndb
+mkdir -p sparc64/bin/nusb
+mkdir -p sparc64/bin/replica
+mkdir -p sparc64/bin/upas
+mkdir -p sparc64/bin/venti
+mkdir -p sparc64/lib/ape
+mkdir -p sys/lib/dist/usr/glenda/bin/386
+mkdir -p sys/lib/dist/usr/glenda/bin/amd64
+mkdir -p sys/lib/dist/usr/glenda/bin/arm
+mkdir -p sys/lib/dist/usr/glenda/bin/arm64
+mkdir -p sys/lib/dist/usr/glenda/bin/loong
+mkdir -p sys/lib/dist/usr/glenda/bin/mips
+mkdir -p sys/lib/dist/usr/glenda/tmp
+mkdir -p sys/lib/dist/ndb/dhcp
+mkdir -p sys/lib/dist/cfg/pxe
+mkdir -p sys/lib/tls/acmed
+mkdir -p sys/lib/lp/log
+mkdir -p sys/lib/lp/tmp
+mkdir -p sys/lib/ssl
+mkdir -p sys/log/httpd
+mkdir -p tmp
+mkdir -p usr
--- /dev/null
+++ b/sys/src/boot/efi/loong.s
@@ -1,0 +1,25 @@
+TEXT start(SB), $-8
+ // TODO: Rebase
+ JMP efimain(SB)
+
+TEXT rebase(SB), $-8
+
+TEXT eficall(SB), $-8
+ MOVV R4, R12
+ MOVV 0x08(FP), R4
+ MOVV 0x10(FP), R5
+ MOVV 0x18(FP), R6
+ MOVV 0x20(FP), R7
+ MOVV 0x28(FP), R8
+ MOVV 0x30(FP), R9
+ MOVV 0x38(FP), R10
+ MOVV 0x40(FP), R11
+ JMP (R12)
+
+TEXT jump(SB), $-8
+ MOVV R4, R7
+ MOVV 0x08(FP), R4
+ JMP (R7)
+
+GLOBL confaddr(SB), $8
+GLOBL argsbuf<>(SB), $0x1000
--- /dev/null
+++ b/sys/src/boot/efi/mkfile
@@ -1,0 +1,101 @@
+TARG=bootia32.efi bootx64.efi bootaa64.efi bootloongarch64.efi efiboot.fat
+HFILES=fns.h mem.h
+IMAGEBASE=0x8000
+CFLAGS=-FTVw
+PEFLAGS=$CFLAGS '-DIMAGEBASE='$IMAGEBASE
+
+all:V: $TARG
+
+install:V: $TARG
+ cp $prereq /386
+
+%.8: %.s
+ 8a $PEFLAGS $stem.s
+%.8: %.c
+ 8c $CFLAGS $stem.c
+bootia32.efi: ia32.8 efi.8 fs.8 pxe.8 iso.8 sub.8
+ 8l -l -s -R1 -T0x8200 -o bootia32.out $prereq
+ aux/aout2efi -Z$IMAGEBASE -o $target bootia32.out
+%.8: $HFILES
+
+
+%.6: %.s
+ 6a $PEFLAGS $stem.s
+%.6: %.c
+ 6c $CFLAGS $stem.c
+bootx64.efi: x64.6 efi.6 fs.6 pxe.6 iso.6 sub.6
+ 6l -l -s -R1 -T0x8200 -o bootx64.out $prereq
+ aux/aout2efi -Z$IMAGEBASE -o $target bootx64.out
+%.6: $HFILES
+
+
+%.7: %.s
+ 7a $PEFLAGS $stem.s
+%.7: %.c
+ 7c $CFLAGS $stem.c
+bootaa64.efi: aa64.7 efi.7 fs.7 pxe.7 iso.7 sub.7
+ 7l -l -s -R1 -T0x8200 -o bootaa64.out $prereq
+ aux/aout2efi -Z$IMAGEBASE -o $target bootaa64.out
+%.7: $HFILES
+
+
+%.z: %.s
+ za $PEFLAGS $stem.s
+%.z: %.c
+ zc $CFLAGS $stem.c
+bootloongarch64.efi: loong.z efi.z fs.z pxe.z iso.z sub.z
+ zl -l -s -R1 -T0x8200 -o bootloongarch64.out $prereq
+ aux/aout2efi -Z$IMAGEBASE -o $target bootloongarch64.out
+%.z: $HFILES
+
+
+efiboot.fat:D: bootia32.efi bootx64.efi bootaa64.efi bootloongarch64.efi
+ s = $target.$pid
+ rm -f $target
+ dd -if /dev/zero -of $target -bs 1024 -count 1024
+ disk/format -xd -t hard $target
+ dossrv -f $target $s
+ mount -c /srv/$s /n/esp
+ mkdir /n/esp/efi
+ mkdir /n/esp/efi/boot
+ cp bootia32.efi /n/esp/efi/boot
+ cp bootx64.efi /n/esp/efi/boot
+ cp bootaa64.efi /n/esp/efi/boot
+ cp bootloongarch64.efi /n/esp/efi/boot
+ unmount /n/esp
+ rm /srv/$s
+
+
+test.iso:D: efiboot.fat
+ rm -fr tmp
+ mkdir tmp
+ mkdir tmp/cfg
+ mkdir tmp/386
+ cp efiboot.fat tmp/386
+ cp /386/9bootiso tmp/386
+ cp /386/9pc tmp/386
+ echo 'bootfile=/386/9pc' >tmp/cfg/plan9.ini
+ disk/mk9660 -B 386/9bootiso -E 386/efiboot.fat -p <{echo +} -s tmp $target
+ rm -r tmp
+
+test.fat:D: bootia32.efi bootx64.efi bootaa64.efi bootloongarch64.efi
+ s = $target.$pid
+ rm -f $target
+ dd -if /dev/zero -of $target -bs 65536 -count 128
+ disk/format -xd -t hard $target
+ dossrv -f $target $s
+ mount -c /srv/$s /n/esp
+ mkdir /n/esp/efi
+ mkdir /n/esp/efi/boot
+ cp bootia32.efi /n/esp/efi/boot
+ cp bootx64.efi /n/esp/efi/boot
+ cp bootaa64.efi /n/esp/efi/boot
+ cp bootloongarch64.efi /n/esp/efi/boot
+ cp /386/9pc /n/esp
+ echo 'bootfile=9pc' >/n/esp/plan9.ini
+ unmount /n/esp
+ rm /srv/$s
+
+
+clean:V:
+ rm -f *.[678] *.out $TARG test.*
--- /dev/null
+++ b/sys/src/cmd/aux/aout2efi.c
@@ -1,0 +1,244 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+#define HDRSZ 0x200 /* EFI header size */
+
+enum {
+ EFI_IMAGE_MACHINE_IA32 = 0x014c,
+ EFI_IMAGE_MACHINE_x64 = 0x8664,
+ EFI_IMAGE_MACHINE_AARCH64 = 0xAA64,
+ EFI_IMAGE_MACHINE_LOONGARCH64 = 0x6264,
+};
+
+static int is32;
+static int infd, outfd;
+static uchar buf[IOUNIT];
+
+static void
+pack(uchar **pp, char *fmt, ...)
+{
+ va_list args;
+ int c;
+ uchar *p;
+ u32int u;
+ u64int l;
+
+ va_start(args, fmt);
+ for(; *fmt; fmt++){
+ c = *fmt;
+ if(c == 'q' && is32)
+ c = 'l';
+ p = *pp;
+ switch(c){
+ case 'b':
+ p[0] = va_arg(args, int);
+ *pp += 1;
+ break;
+ case 'w':
+ u = va_arg(args, u32int);
+ p[0] = u;
+ p[1] = u>>8;
+ *pp += 2;
+ break;
+ case 'l':
+ u = va_arg(args, u32int);
+ p[0] = u;
+ p[1] = u>>8;
+ p[2] = u>>16;
+ p[3] = u>>24;
+ *pp += 4;
+ break;
+ case 'q':
+ l = va_arg(args, u64int);
+ p[0] = l;
+ p[1] = l>>8;
+ p[2] = l>>16;
+ p[3] = l>>24;
+ p[4] = l>>32;
+ p[5] = l>>40;
+ p[6] = l>>48;
+ p[7] = l>>56;
+ *pp += 8;
+ break;
+ case '0':
+ *pp += va_arg(args, int);
+ break;
+ default:
+ sysfatal("pack: %c", c);
+ }
+ }
+ va_end(args);
+}
+
+static void
+usage(void)
+{
+ fprint(2, "usage: %s a.out\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ Fhdr fhdr;
+ u64int kzero;
+ uchar *header;
+ char *ofile, *iname;
+ int arch, chars, relocs;
+ long n, szofdat, szofimage;
+
+ kzero = 0x8000;
+ ofile = nil;
+ relocs = 0;
+ ARGBEGIN{
+ case 'Z':
+ kzero = strtoull(EARGF(usage()), 0, 0);
+ break;
+ case 'o':
+ ofile = strdup(EARGF(usage()));
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc != 1)
+ usage();
+
+ infd = open(argv[0], OREAD);
+ if(infd < 0)
+ sysfatal("infd: %r");
+
+ if(crackhdr(infd, &fhdr) == 0)
+ sysfatal("crackhdr: %r");
+ switch(mach->mtype){
+ case MI386:
+ arch = EFI_IMAGE_MACHINE_IA32;
+ is32 = 1;
+ chars = 2103;
+ break;
+ case MAMD64:
+ arch = EFI_IMAGE_MACHINE_x64;
+ chars = 2223;
+ break;
+ case MARM64:
+ arch = EFI_IMAGE_MACHINE_AARCH64;
+ chars = 518;
+ relocs = 1;
+ break;
+ case MLOONG:
+ arch = EFI_IMAGE_MACHINE_LOONGARCH64;
+ chars = 518;
+ relocs = 1;
+ break;
+ default:
+ SET(arch, chars);
+ sysfatal("archloch");
+ }
+ szofdat = fhdr.txtsz + fhdr.datsz;
+ szofimage = szofdat + fhdr.bsssz + HDRSZ;
+
+ iname = strrchr(argv[0], '/');
+ if(iname != nil)
+ iname++;
+ else
+ iname = argv[0];
+ if(ofile == nil)
+ ofile = smprint("%s.efi", iname);
+ outfd = create(ofile, OWRITE|OTRUNC, 0666);
+ if(outfd < 0)
+ sysfatal("create: %r");
+
+ header = buf;
+
+ /* mzhdr */
+ pack(&header, "bb0l",
+ 'M', 'Z', /* e_magic */
+ 0x3a, /* UNUSED */
+ 0x40); /* e_lfanew */
+
+ /* pehdr */
+ pack(&header, "bbbbwwlllww",
+ 'P', 'E', 0, 0,
+ arch, /* Machine */
+ 1+relocs, /* NumberOfSections */
+ 0, /* TimeDateStamp UNUSED */
+ 0, /* PointerToSymbolTable UNUSED */
+ 0, /* NumberOfSymbols UNUSED */
+ is32 ? 0xE0 : 0xF0, /* SizeOfOptionalHeader */
+ chars); /* Characteristics */
+ pack(&header, "wbblllll",
+ is32 ? 0x10B : 0x20B, /* Magic */
+ 9, /* MajorLinkerVersion UNUSED */
+ 0, /* MinorLinkerVersion UNUSED */
+ 0, /* SizeOfCode UNUSED */
+ 0, /* SizeOfInitializedData UNUSED */
+ 0, /* SizeOfUninitializedData UNUSED */
+ fhdr.entry-kzero, /* AddressOfEntryPoint */
+ 0); /* BaseOfCode UNUSED */
+ if(is32)
+ pack(&header, "l", 0); /* BaseOfData UNUSED */
+ pack(&header, "qllwwwwwwllllwwqqqqll0",
+ kzero, /* ImageBase */
+ HDRSZ, /* SectionAlignment */
+ HDRSZ, /* FileAlignment */
+ 4, /* MajorOperatingSystemVersion UNUSED */
+ 0, /* MinorOperatingSystemVersion UNUSED */
+ 0, /* MajorImageVersion UNUSED */
+ 0, /* MinorImageVersion UNUSED */
+ 4, /* MajorSubsystemVersion */
+ 0, /* MinorSubsystemVersion UNUSED */
+ 0, /* Win32VersionValue UNUSED */
+ szofimage, /* SizeOfImage */
+ HDRSZ, /* SizeOfHeaders */
+ 0, /* CheckSum UNUSED */
+ 10, /* Subsystem (10 = efi application) */
+ 0, /* DllCharacteristics UNUSED */
+ 0, /* SizeOfStackReserve UNUSED */
+ 0, /* SizeOfStackCommit UNUSED */
+ 0, /* SizeOfHeapReserve UNUSED */
+ 0, /* SizeOfHeapCommit UNUSED */
+ 0, /* LoaderFlags UNUSED */
+ 16, /* NumberOfRvaAndSizes UNUSED */
+ 32*4); /* RVA UNUSED */
+ if(relocs)
+ pack(&header, "bbbbbbbbllllllwwl",
+ '.', 'r', 'e', 'l', 'o', 'c', 0, 0,
+ 0, /* VirtualSize */
+ 0, /* VirtualAddress */
+ 0, /* SizeOfData */
+ 0, /* PointerToRawData */
+ 0, /* PointerToRelocations UNUSED */
+ 0, /* PointerToLinenumbers UNUSED */
+ 0, /* NumberOfRelocations UNUSED */
+ 0, /* NumberOfLinenumbers UNUSED */
+ 0x42100040); /* Characteristics (read, discardable) */
+ pack(&header, "bbbbbbbbllllllwwl",
+ '.', 't', 'e', 'x', 't', 0, 0, 0,
+ szofdat, /* VirtualSize */
+ HDRSZ, /* VirtualAddress */
+ szofdat, /* SizeOfData */
+ HDRSZ, /* PointerToRawData */
+ 0, /* PointerToRelocations UNUSED */
+ 0, /* PointerToLinenumbers UNUSED */
+ 0, /* NumberOfRelocations UNUSED */
+ 0, /* NumberOfLinenumbers UNUSED */
+ 0x86000020); /* Characteristics (code, RWX) */
+
+ if(write(outfd, buf, HDRSZ) != HDRSZ)
+ sysfatal("write: %r");
+ if(seek(infd, fhdr.hdrsz, 0) != fhdr.hdrsz)
+ sysfatal("seek: %r");
+ for(;;){
+ n = read(infd, buf, sizeof(buf));
+ if(n < 0)
+ sysfatal("read: %r");
+ if(n == 0)
+ break;
+ if(write(outfd, buf, n) != n)
+ sysfatal("write: %r");
+ }
+
+ exits(nil);
+}
--- /dev/null
+++ b/sys/src/cmd/za/a.h
@@ -1,0 +1,177 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "../zc/z.out.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+typedef struct Sym Sym;
+typedef struct Gen Gen;
+typedef struct Io Io;
+typedef struct Hist Hist;
+
+#define MAXALIGN 7
+#define FPCHIP 1
+#define NSYMB 8192
+#define BUFSIZ 8192
+#define HISTSZ 20
+#define NINCLUDE 10
+#define NHUNK 10000
+#define EOF (-1)
+#define IGN (-2)
+#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define NHASH 503
+#define STRINGSZ 200
+#define NMACRO 10
+
+struct Sym
+{
+ Sym* link;
+ char* macro;
+ vlong value;
+ ushort type;
+ char *name;
+ char sym;
+};
+#define S ((Sym*)0)
+
+EXTERN struct
+{
+ char* p;
+ int c;
+} fi;
+
+struct Io
+{
+ Io* link;
+ char b[BUFSIZ];
+ char* p;
+ short c;
+ short f;
+};
+#define I ((Io*)0)
+
+EXTERN struct
+{
+ Sym* sym;
+ short type;
+} h[NSYM];
+
+struct Gen
+{
+ Sym* sym;
+ vlong offset;
+ short type;
+ short reg;
+ short name;
+ double dval;
+ char sval[8];
+};
+
+struct Hist
+{
+ Hist* link;
+ char* name;
+ long line;
+ vlong offset;
+};
+#define H ((Hist*)0)
+
+enum
+{
+ CLAST,
+ CMACARG,
+ CMACRO,
+ CPREPROC
+};
+
+EXTERN char debug[256];
+EXTERN Sym* hash[NHASH];
+EXTERN char* Dlist[30];
+EXTERN int nDlist;
+EXTERN Hist* ehist;
+EXTERN int newflag;
+EXTERN Hist* hist;
+EXTERN char* include[NINCLUDE];
+EXTERN Io* iofree;
+EXTERN Io* ionext;
+EXTERN Io* iostack;
+EXTERN long lineno;
+EXTERN int nerrors;
+EXTERN int ninclude;
+EXTERN Gen nullgen;
+EXTERN char* outfile;
+EXTERN int pass;
+EXTERN char* pathname;
+EXTERN vlong pc;
+EXTERN int peekc;
+EXTERN int sym;
+EXTERN char symb[NSYMB];
+EXTERN int thechar;
+EXTERN char* thestring;
+EXTERN Biobuf obuf;
+
+void* alloc(long);
+void* allocn(void*, long, long);
+void errorexit(void);
+void pushio(void);
+void newio(void);
+void newfile(char*, int);
+Sym* slookup(char*);
+Sym* lookup(void);
+void syminit(Sym*);
+long yylex(void);
+int getc(void);
+int getnsc(void);
+void unget(int);
+int escchar(int);
+void cinit(void);
+void pinit(char*);
+void cclean(void);
+int isreg(Gen*);
+void outcode(int, Gen*, int, Gen*);
+void zname(char*, int, int);
+void zaddr(Gen*, int);
+void ieeedtod(Ieee*, double);
+int filbuf(void);
+Sym* getsym(void);
+void domacro(void);
+void macund(void);
+void macdef(void);
+int macexpand(Sym*, char*, int);
+void macinc(void);
+void maclin(void);
+void macprag(void);
+void macif(int);
+void macend(void);
+void outhist(void);
+void dodefine(char*);
+void prfile(long);
+void linehist(char*, int);
+void yyerror(char*, ...);
+int yyparse(void);
+void setinclude(char*);
+int assemble(char*);
+
+/*
+ * system-dependent stuff from ../cc/compat.c
+ */
+
+enum /* keep in synch with ../cc/cc.h */
+{
+ Plan9 = 1<<0,
+ Unix = 1<<1,
+ Windows = 1<<2
+};
+int mywait(int*);
+int mycreat(char*, int);
+int systemtype(int);
+int pathchar(void);
+char* mygetwd(char*, int);
+int myexec(char*, char*[]);
+int mydup(int, int);
+int myfork(void);
+int mypipe(int*);
+void* mysbrk(ulong);
--- /dev/null
+++ b/sys/src/cmd/za/a.y
@@ -1,0 +1,580 @@
+%{
+#include "a.h"
+%}
+%union
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+}
+%left '|'
+%left '^'
+%left '&'
+%left '<' '>'
+%left '+' '-'
+%left '*' '/' '%'
+%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token <lval> LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
+%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token <lval> LCONST LSP LSB LFP LPC LTYPEX
+%token <lval> LREG LFREG LFCCREG LFCSREG LR LF LFCC LFCSR
+%token <dval> LFCONST
+%token <sval> LSCONST
+%token <lval> LVCONST
+%token <sym> LNAME LLAB LVAR
+%type <lval> con expr pointer offset sreg
+%type <gen> gen vgen lgen vlgen rel reg freg fccreg fcsreg
+%type <gen> imm ximm ireg name oreg imr nireg fgen
+%%
+prog:
+| prog line
+
+line:
+ LLAB ':'
+ {
+ if($1->value != pc)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = pc;
+ }
+ line
+| LNAME ':'
+ {
+ $1->type = LLAB;
+ $1->value = pc;
+ }
+ line
+| LNAME '=' expr ';'
+ {
+ $1->type = LVAR;
+ $1->value = $3;
+ }
+| LVAR '=' expr ';'
+ {
+ if($1->value != $3)
+ yyerror("redeclaration of %s", $1->name);
+ $1->value = $3;
+ }
+| ';'
+| inst ';'
+| error ';'
+
+inst:
+/*
+ * Immed-type
+ */
+ LTYPE1 imr ',' sreg ',' reg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPE1 imr ',' reg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * NOR
+ */
+| LTYPE2 imr ',' sreg ',' imr
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPE2 imr ',' imr
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * LOAD/STORE, but not MOVW
+ */
+| LTYPE3 lgen ',' gen
+ {
+ if(!isreg(&$2) && !isreg(&$4))
+ print("one side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * SPECIAL
+ */
+| LTYPE4 comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+/*
+ * MOVW
+ */
+| LTYPE5 vlgen ',' vgen
+ {
+ if(!isreg(&$2) && !isreg(&$4))
+ print("one side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * MUL/DIV
+ */
+| LTYPE6 reg ',' sreg comma
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+| LTYPE6 reg ',' sreg ',' reg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * JMP/JAL
+ */
+| LTYPE7 comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE7 comma nireg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 comma nireg
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPE8 sreg ',' nireg
+ {
+ outcode($1, &nullgen, $2, &$4);
+ }
+/*
+ * BEQ/BNE
+ */
+| LTYPE9 gen ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPE9 gen ',' sreg ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * B-other
+ */
+| LTYPEA gen ',' rel
+ {
+ if(!isreg(&$2))
+ print("left side must be register\n");
+ outcode($1, &$2, NREG, &$4);
+ }
+/*
+ * TEXT/GLOBL
+ */
+| LTYPEB name ',' imm
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEB name ',' con ',' imm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * DATA
+ */
+| LTYPEC name '/' con ',' ximm
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+/*
+ * floating-type
+ */
+| LTYPED freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEE freg ',' freg
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+| LTYPEE freg ',' LFREG ',' freg
+ {
+ outcode($1, &$2, $4, &$6);
+ }
+| LTYPEF freg ',' LFREG comma
+ {
+ outcode($1, &$2, $4, &nullgen);
+ }
+/*
+ * coprocessor branch
+ */
+| LTYPEG comma rel
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * word
+ */
+| LTYPEH comma ximm
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+/*
+ * NOP
+ */
+| LTYPEI comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LTYPEI ',' vgen
+ {
+ outcode($1, &nullgen, NREG, &$3);
+ }
+| LTYPEI vgen comma
+ {
+ outcode($1, &$2, NREG, &nullgen);
+ }
+/*
+ * BREAK -- overloaded with CACHE opcode
+ */
+| LTYPEJ comma
+ {
+ outcode($1, &nullgen, NREG, &nullgen);
+ }
+| LTYPEJ vgen ',' vgen
+ {
+ outcode($1, &$2, NREG, &$4);
+ }
+
+comma:
+| ','
+
+rel:
+ con '(' LPC ')'
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.offset = $1 + pc;
+ }
+| LNAME offset
+ {
+ $$ = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", $1->name);
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LLAB offset
+ {
+ $$ = nullgen;
+ $$.type = D_BRANCH;
+ $$.sym = $1;
+ $$.offset = $1->value + $2;
+ }
+
+vlgen:
+ lgen
+| fgen
+| fccreg
+| fcsreg
+
+vgen:
+ gen
+| fgen
+| fccreg
+| fcsreg
+
+lgen:
+ gen
+| ximm
+
+fgen:
+ freg
+
+fccreg:
+ LFCCREG
+ {
+ $$ = nullgen;
+ $$.type = D_FCCREG;
+ $$.reg = $1;
+ }
+| LFCC '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCCREG;
+ $$.reg = $3;
+ }
+
+fcsreg:
+ LFCSREG
+ {
+ $$ = nullgen;
+ $$.type = D_FCSREG;
+ $$.reg = $1;
+ }
+| LFCSR '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCSREG;
+ $$.reg = $3;
+ }
+
+freg:
+ LFREG
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $1;
+ }
+| LF '(' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FREG;
+ $$.reg = $3;
+ }
+
+ximm: '$' con
+ {
+ $$ = nullgen;
+ if(isvconst($2))
+ $$.type = D_VCONST;
+ else
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+| '$' oreg
+ {
+ $$ = $2;
+ $$.type = D_CONST;
+ }
+| '$' '*' '$' oreg
+ {
+ $$ = $4;
+ $$.type = D_OCONST;
+ }
+| '$' LSCONST
+ {
+ $$ = nullgen;
+ $$.type = D_SCONST;
+ memcpy($$.sval, $2, sizeof($$.sval));
+ }
+| '$' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = $2;
+ }
+| '$' '-' LFCONST
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$3;
+ }
+
+nireg:
+ ireg
+| con ireg
+ {
+ if($1 != 0)
+ yyerror("offset must be zero");
+ $$ = $2;
+ }
+| name
+ {
+ $$ = $1;
+ if($1.name != D_EXTERN && $1.name != D_STATIC) {
+ }
+ }
+
+ireg:
+ '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+
+gen:
+ reg
+| con
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.offset = $1;
+ }
+| oreg
+
+oreg:
+ name
+| name '(' sreg ')'
+ {
+ $$ = $1;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ }
+| '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $2;
+ $$.offset = 0;
+ }
+| con '(' sreg ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.reg = $3;
+ $$.offset = $1;
+ }
+
+imr:
+ reg
+| imm
+
+imm: '$' con
+ {
+ $$ = nullgen;
+ if(isvconst($2))
+ $$.type = D_VCONST;
+ else
+ $$.type = D_CONST;
+ $$.offset = $2;
+ }
+
+reg:
+ sreg
+ {
+ $$ = nullgen;
+ $$.type = D_REG;
+ $$.reg = $1;
+ }
+
+sreg:
+ LREG
+| LR '(' con ')'
+ {
+ if($$ < 0 || $$ >= NREG)
+ print("register value out of range\n");
+ $$ = $3;
+ }
+
+name:
+ con '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $3;
+ $$.sym = S;
+ $$.offset = $1;
+ }
+| LNAME offset '(' pointer ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = $4;
+ $$.sym = $1;
+ $$.offset = $2;
+ }
+| LNAME '<' '>' offset '(' LSB ')'
+ {
+ $$ = nullgen;
+ $$.type = D_OREG;
+ $$.name = D_STATIC;
+ $$.sym = $1;
+ $$.offset = $4;
+ }
+
+offset:
+ {
+ $$ = 0;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+
+pointer:
+ LSB
+| LSP
+| LFP
+
+con:
+ LCONST
+| LVAR
+ {
+ $$ = $1->value;
+ }
+| '-' con
+ {
+ $$ = -$2;
+ }
+| '+' con
+ {
+ $$ = $2;
+ }
+| '~' con
+ {
+ $$ = ~$2;
+ }
+| '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+expr:
+ con
+| expr '+' expr
+ {
+ $$ = $1 + $3;
+ }
+| expr '-' expr
+ {
+ $$ = $1 - $3;
+ }
+| expr '*' expr
+ {
+ $$ = $1 * $3;
+ }
+| expr '/' expr
+ {
+ $$ = $1 / $3;
+ }
+| expr '%' expr
+ {
+ $$ = $1 % $3;
+ }
+| expr '<' '<' expr
+ {
+ $$ = $1 << $4;
+ }
+| expr '>' '>' expr
+ {
+ $$ = $1 >> $4;
+ }
+| expr '&' expr
+ {
+ $$ = $1 & $3;
+ }
+| expr '^' expr
+ {
+ $$ = $1 ^ $3;
+ }
+| expr '|' expr
+ {
+ $$ = $1 | $3;
+ }
+%%
+
+int
+isvconst(vlong con)
+{
+ long l;
+
+ l = con;
+ return (vlong)l != con;
+}
--- /dev/null
+++ b/sys/src/cmd/za/lex.c
@@ -1,0 +1,643 @@
+#define EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+ char *p;
+ int nout, nproc, status, i, c;
+
+ thechar = 'z';
+ thestring = "loong";
+ memset(debug, 0, sizeof(debug));
+ cinit();
+ outfile = 0;
+ include[ninclude++] = ".";
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 || c < sizeof(debug))
+ debug[c] = 1;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p)
+ Dlist[nDlist++] = p;
+ break;
+
+ case 'I':
+ p = ARGF();
+ setinclude(p);
+ break;
+ } ARGEND
+ if(*argv == 0) {
+ print("usage: %ca [-options] file.s\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't assemble multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ if(p = getenv("NPROC"))
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0)
+ errorexit();
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ print("%s:\n", *argv);
+ if(assemble(*argv))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+ if(assemble(argv[0]))
+ errorexit();
+ exits(0);
+}
+
+int
+assemble(char *file)
+{
+ char ofile[100], incfile[20], *p;
+ int i, of;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ include[0] = ofile;
+ *p++ = 0;
+ } else
+ p = ofile;
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile){
+ p = utfrrune(outfile, '.');
+ if(p)
+ if(p[1] == 's' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ } else
+ outfile = "/dev/null";
+ }
+ p = getenv("INCLUDE");
+ if(p) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile,"/%s/include", thestring);
+ setinclude(strdup(incfile));
+ }
+ }
+
+ of = mycreat(outfile, 0664);
+ if(of < 0) {
+ yyerror("%ca: cannot create %s", thechar, outfile);
+ errorexit();
+ }
+ Binit(&obuf, of, OWRITE);
+
+ pass = 1;
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ if(nerrors) {
+ cclean();
+ return nerrors;
+ }
+
+ pass = 2;
+ outhist();
+ pinit(file);
+ for(i=0; i<nDlist; i++)
+ dodefine(Dlist[i]);
+ yyparse();
+ cclean();
+ return nerrors;
+}
+
+struct
+{
+ char *name;
+ ushort type;
+ ushort value;
+} itab[] =
+{
+ "SP", LSP, D_AUTO,
+ "SB", LSB, D_EXTERN,
+ "FP", LFP, D_PARAM,
+ "PC", LPC, D_BRANCH,
+
+ "R", LR, 0,
+ "R0", LREG, 0,
+ "R1", LREG, 1,
+ "R2", LREG, 2,
+ "R3", LREG, 3,
+ "R4", LREG, 4,
+ "R5", LREG, 5,
+ "R6", LREG, 6,
+ "R7", LREG, 7,
+ "R8", LREG, 8,
+ "R9", LREG, 9,
+ "R10", LREG, 10,
+ "R11", LREG, 11,
+ "R12", LREG, 12,
+ "R13", LREG, 13,
+ "R14", LREG, 14,
+ "R15", LREG, 15,
+ "R16", LREG, 16,
+ "R17", LREG, 17,
+ "R18", LREG, 18,
+ "R19", LREG, 19,
+ "R20", LREG, 20,
+ "R21", LREG, 21,
+ "R22", LREG, 22,
+ "R23", LREG, 23,
+ "R24", LREG, 24,
+ "R25", LREG, 25,
+ "R26", LREG, 26,
+ "R27", LREG, 27,
+ "R28", LREG, 28,
+ "R29", LREG, 29,
+ "R30", LREG, 30,
+ "R31", LREG, 31,
+
+ "F", LF, 0,
+ "F0", LFREG, 0,
+ "F1", LFREG, 1,
+ "F2", LFREG, 2,
+ "F3", LFREG, 3,
+ "F4", LFREG, 4,
+ "F5", LFREG, 5,
+ "F6", LFREG, 6,
+ "F7", LFREG, 7,
+ "F8", LFREG, 8,
+ "F9", LFREG, 9,
+ "F10", LFREG, 10,
+ "F11", LFREG, 11,
+ "F12", LFREG, 12,
+ "F13", LFREG, 13,
+ "F14", LFREG, 14,
+ "F15", LFREG, 15,
+ "F16", LFREG, 16,
+ "F17", LFREG, 17,
+ "F18", LFREG, 18,
+ "F19", LFREG, 19,
+ "F20", LFREG, 20,
+ "F21", LFREG, 21,
+ "F22", LFREG, 22,
+ "F23", LFREG, 23,
+ "F24", LFREG, 24,
+ "F25", LFREG, 25,
+ "F26", LFREG, 26,
+ "F27", LFREG, 27,
+ "F28", LFREG, 28,
+ "F29", LFREG, 29,
+ "F30", LFREG, 30,
+ "F31", LFREG, 31,
+
+ "FCC", LFCC, 0,
+ "FCC0", LFCCREG, 0,
+ "FCC1", LFCCREG, 1,
+ "FCC2", LFCCREG, 2,
+ "FCC3", LFCCREG, 3,
+ "FCC4", LFCCREG, 4,
+ "FCC5", LFCCREG, 5,
+ "FCC6", LFCCREG, 6,
+ "FCC7", LFCCREG, 7,
+
+ "FCSR", LFCSR, 0,
+ "FCSR0", LFCSREG, 0,
+ "FCSR1", LFCSREG, 1,
+ "FCSR2", LFCSREG, 2,
+ "FCSR3", LFCSREG, 3,
+
+ "ADD", LTYPE1, AADD,
+ "ADDU", LTYPE1, AADDU,
+ "SUB", LTYPE1, ASUB, /* converted to ADD(-) in loader */
+ "SUBU", LTYPE1, ASUBU,
+ "SGT", LTYPE1, ASGT,
+ "SGTU", LTYPE1, ASGTU,
+ "AND", LTYPE1, AAND,
+ "OR", LTYPE1, AOR,
+ "XOR", LTYPE1, AXOR,
+ "SLL", LTYPE1, ASLL,
+ "SRL", LTYPE1, ASRL,
+ "SRA", LTYPE1, ASRA,
+
+ "ADDV", LTYPE1, AADDV,
+ "ADDVU", LTYPE1, AADDVU,
+ "SUBV", LTYPE1, ASUBV, /* converted to ADD(-) in loader */
+ "SUBVU", LTYPE1, ASUBVU,
+ "SLLV", LTYPE1, ASLLV,
+ "SRLV", LTYPE1, ASRLV,
+ "SRAV", LTYPE1, ASRAV,
+
+ "NOR", LTYPE2, ANOR,
+
+ "MOVB", LTYPE3, AMOVB,
+ "MOVBU", LTYPE3, AMOVBU,
+ "MOVH", LTYPE3, AMOVH,
+ "MOVHU", LTYPE3, AMOVHU,
+ "MOVWL", LTYPE3, AMOVWL,
+ "MOVWR", LTYPE3, AMOVWR,
+ "MOVVL", LTYPE3, AMOVVL,
+ "MOVVR", LTYPE3, AMOVVR,
+
+ "BREAK", LTYPEJ, ABREAK, /* overloaded CACHE opcode */
+ "END", LTYPE4, AEND,
+ "REM", LTYPE6, AREM,
+ "REMU", LTYPE6, AREMU,
+ "RET", LTYPE4, ARET,
+ "SYSCALL", LTYPE4, ASYSCALL,
+
+ "MOVW", LTYPE5, AMOVW,
+ "MOVV", LTYPE5, AMOVV,
+ "MOVD", LTYPE5, AMOVD,
+ "MOVF", LTYPE5, AMOVF,
+
+ "DIV", LTYPE6, ADIV,
+ "DIVU", LTYPE6, ADIVU,
+ "MUL", LTYPE6, AMUL,
+ "MULU", LTYPE6, AMULU,
+ "DIVV", LTYPE6, ADIVV,
+ "DIVVU", LTYPE6, ADIVVU,
+ "MULV", LTYPE6, AMULV,
+ "MULVU", LTYPE6, AMULVU,
+
+ "JMP", LTYPE7, AJMP,
+
+ "JAL", LTYPE8, AJAL,
+
+ "BEQ", LTYPE9, ABEQ,
+ "BNE", LTYPE9, ABNE,
+
+ "BGEZ", LTYPEA, ABGEZ,
+ "BGTZ", LTYPEA, ABGTZ,
+ "BLEZ", LTYPEA, ABLEZ,
+ "BLTZ", LTYPEA, ABLTZ,
+
+ "TEXT", LTYPEB, ATEXT,
+ "GLOBL", LTYPEB, AGLOBL,
+
+ "DATA", LTYPEC, ADATA,
+
+ "MOVDF", LTYPE5, AMOVDF,
+ "MOVDW", LTYPE5, AMOVDW,
+ "MOVFD", LTYPE5, AMOVFD,
+ "MOVFW", LTYPE5, AMOVFW,
+ "MOVWD", LTYPE5, AMOVWD,
+ "MOVWF", LTYPE5, AMOVWF,
+
+ "ABSD", LTYPED, AABSD,
+ "ABSF", LTYPED, AABSF,
+ "NEGD", LTYPED, ANEGD,
+ "NEGF", LTYPED, ANEGF,
+ "NEGW", LTYPED, ANEGW,
+
+ "CMPEQD", LTYPEF, ACMPEQD,
+ "CMPEQF", LTYPEF, ACMPEQF,
+ "CMPGED", LTYPEF, ACMPGED,
+ "CMPGEF", LTYPEF, ACMPGEF,
+ "CMPGTD", LTYPEF, ACMPGTD,
+ "CMPGTF", LTYPEF, ACMPGTF,
+
+ "ADDD", LTYPEE, AADDD,
+ "ADDF", LTYPEE, AADDF,
+ "ADDW", LTYPEE, AADDW,
+ "DIVD", LTYPEE, ADIVD,
+ "DIVF", LTYPEE, ADIVF,
+ "DIVW", LTYPEE, ADIVW,
+ "MULD", LTYPEE, AMULD,
+ "MULF", LTYPEE, AMULF,
+ "MULW", LTYPEE, AMULW,
+ "SUBD", LTYPEE, ASUBD,
+ "SUBF", LTYPEE, ASUBF,
+ "SUBW", LTYPEE, ASUBW,
+
+ "BFPT", LTYPEG, ABFPT,
+ "BFPF", LTYPEG, ABFPF,
+
+ "WORD", LTYPEH, AWORD,
+ "NOP", LTYPEI, ANOP,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+
+ nullgen.sym = S;
+ nullgen.offset = 0;
+ nullgen.type = D_NONE;
+ nullgen.name = D_NONE;
+ nullgen.reg = NREG;
+ if(FPCHIP)
+ nullgen.dval = 0;
+ for(i=0; i<sizeof(nullgen.sval); i++)
+ nullgen.sval[i] = 0;
+
+ nerrors = 0;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->type = itab[i].type;
+ s->value = itab[i].value;
+ }
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+}
+
+void
+syminit(Sym *s)
+{
+
+ s->type = LNAME;
+ s->value = 0;
+}
+
+int
+isreg(Gen *g)
+{
+
+ USED(g);
+ return 1;
+}
+
+void
+cclean(void)
+{
+
+ outcode(AEND, &nullgen, NREG, &nullgen);
+ Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, t); /* type */
+ Bputc(&obuf, s); /* sym */
+ while(*n) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+ long l;
+ int i;
+ char *n;
+ Ieee e;
+ vlong v;
+
+ Bputc(&obuf, a->type);
+ Bputc(&obuf, a->reg);
+ Bputc(&obuf, s);
+ Bputc(&obuf, a->name);
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ exits("arg");
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_FCCREG:
+ case D_FCSREG:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ case D_BRANCH:
+ l = a->offset;
+ Bputc(&obuf, l);
+ Bputc(&obuf, l>>8);
+ Bputc(&obuf, l>>16);
+ Bputc(&obuf, l>>24);
+ break;
+
+ case D_SCONST:
+ n = a->sval;
+ for(i=0; i<NSNAME; i++) {
+ Bputc(&obuf, *n);
+ n++;
+ }
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ Bputc(&obuf, e.l);
+ Bputc(&obuf, e.l>>8);
+ Bputc(&obuf, e.l>>16);
+ Bputc(&obuf, e.l>>24);
+ Bputc(&obuf, e.h);
+ Bputc(&obuf, e.h>>8);
+ Bputc(&obuf, e.h>>16);
+ Bputc(&obuf, e.h>>24);
+ break;
+
+ case D_VCONST:
+ v = a->offset;
+ Bputc(&obuf, v);
+ Bputc(&obuf, v>>8);
+ Bputc(&obuf, v>>16);
+ Bputc(&obuf, v>>24);
+ Bputc(&obuf, v>>32);
+ Bputc(&obuf, v>>40);
+ Bputc(&obuf, v>>48);
+ Bputc(&obuf, v>>56);
+ break;
+ }
+}
+
+void
+outcode(int a, Gen *g1, int reg, Gen *g2)
+{
+ int sf, st, t;
+ Sym *s;
+
+ if(pass == 1)
+ goto out;
+jackpot:
+ sf = 0;
+ s = g1->sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = g1->name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = g2->sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = g2->name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ zname(s->name, t, sym);
+ s->sym = sym;
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(&obuf, a);
+ Bputc(&obuf, reg);
+ Bputc(&obuf, lineno);
+ Bputc(&obuf, lineno>>8);
+ Bputc(&obuf, lineno>>16);
+ Bputc(&obuf, lineno>>24);
+ zaddr(g1, sf);
+ zaddr(g2, st);
+
+out:
+ if(a != AGLOBL && a != ADATA)
+ pc++;
+}
+
+void
+outhist(void)
+{
+ Gen g;
+ Hist *h;
+ char *p, *q, *op, c;
+ int n;
+
+ g = nullgen;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = strchr(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(&obuf, ANAME);
+ Bputc(&obuf, D_FILE); /* type */
+ Bputc(&obuf, 1); /* sym */
+ Bputc(&obuf, '<');
+ Bwrite(&obuf, p, n);
+ Bputc(&obuf, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ g.offset = h->offset;
+
+ Bputc(&obuf, AHISTORY);
+ Bputc(&obuf, 0);
+ Bputc(&obuf, h->line);
+ Bputc(&obuf, h->line>>8);
+ Bputc(&obuf, h->line>>16);
+ Bputc(&obuf, h->line>>24);
+ zaddr(&nullgen, 0);
+ zaddr(&g, 0);
+ }
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
+#include "../cc/compat"
--- /dev/null
+++ b/sys/src/cmd/za/mkfile
@@ -1,0 +1,19 @@
+</$objtype/mkfile
+
+TARG=za
+OFILES=\
+ y.tab.$O\
+ lex.$O\
+
+HFILES=\
+ ../zc/z.out.h\
+ y.tab.h\
+ a.h\
+
+YFILES=a.y\
+
+BIN=/$objtype/bin
+< /sys/src/cmd/mkone
+YFLAGS=-D1 -d
+
+lex.$O: ../cc/macbody ../cc/lexbody ../cc/compat
--- /dev/null
+++ b/sys/src/cmd/zc/cgen.c
@@ -1,0 +1,1177 @@
+#include "gc.h"
+
+static void genasop(int, Node*, Node*, Node*);
+
+void
+cgen(Node *n, Node *nn)
+{
+ Node *l, *r;
+ Prog *p1;
+ Node nod, nod1, nod2, nod3, nod4;
+ int o;
+ long v, curs;
+
+ if(debug['g']) {
+ prtree(nn, "cgen lhs");
+ prtree(n, "cgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(typesu[n->type->etype]) {
+ sugen(n, nn, n->type->width);
+ return;
+ }
+ l = n->left;
+ r = n->right;
+ o = n->op;
+ if(n->addable >= INDEXED) {
+ if(nn == Z) {
+ switch(o) {
+ default:
+ nullwarn(Z, Z);
+ break;
+ case OINDEX:
+ nullwarn(l, r);
+ break;
+ }
+ return;
+ }
+ gmove(n, nn);
+ return;
+ }
+ curs = cursafe;
+
+ if(n->complex >= FNX)
+ if(l->complex >= FNX)
+ if(r != Z && r->complex >= FNX)
+ switch(o) {
+ default:
+ regret(&nod, r);
+ cgen(r, &nod);
+
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ cgen(&nod, nn);
+ return;
+
+ case OFUNC:
+ case OCOMMA:
+ case OANDAND:
+ case OOROR:
+ case OCOND:
+ case ODOT:
+ break;
+ }
+
+ switch(o) {
+ default:
+ diag(n, "unknown op in cgen: %O", o);
+ break;
+
+ case OAS:
+ if(l->op == OBIT)
+ goto bitas;
+ if(l->addable >= INDEXED && l->complex < FNX) {
+ if(nn != Z || r->addable < INDEXED) {
+ if(r->complex >= FNX && nn == Z)
+ regret(&nod, r);
+ else
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gmove(&nod, l);
+ if(nn != Z)
+ gmove(&nod, nn);
+ regfree(&nod);
+ } else
+ gmove(r, l);
+ break;
+ }
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, l, Z);
+ if(r->addable >= INDEXED) {
+ gmove(r, &nod1);
+ if(nn != Z)
+ gmove(r, nn);
+ regfree(&nod1);
+ break;
+ }
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ reglcgen(&nod1, l, Z);
+ }
+ gmove(&nod, &nod1);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ bitas:
+ n = l->left;
+ regalloc(&nod, r, nn);
+ if(l->complex >= r->complex) {
+ reglcgen(&nod1, n, Z);
+ cgen(r, &nod);
+ } else {
+ cgen(r, &nod);
+ reglcgen(&nod1, n, Z);
+ }
+ regalloc(&nod2, n, Z);
+ gopcode(OAS, &nod1, Z, &nod2);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OBIT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ bitload(n, &nod, Z, Z, nn);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ /*
+ * immediate operands
+ */
+ if(nn != Z)
+ if(r->op == OCONST)
+ if(!typefd[n->type->etype]) {
+ cgen(l, nn);
+ if(r->vconst == 0)
+ if(o != OAND)
+ break;
+ if(nn != Z)
+ gopcode(o, r, Z, nn);
+ break;
+ }
+
+ case OLMUL:
+ case OLDIV:
+ case OLMOD:
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ if(o == OMUL || o == OLMUL) {
+ if(mulcon(n, nn))
+ break;
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ gopcode(o, &nod1, Z, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ gopcode(o, &nod, &nod1, &nod);
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+
+ case OASLSHR:
+ case OASASHL:
+ case OASASHR:
+ case OASAND:
+ case OASADD:
+ case OASSUB:
+ case OASXOR:
+ case OASOR:
+ if(l->op == OBIT)
+ goto asbitop;
+ if(r->op == OCONST)
+ if(!typefd[r->type->etype])
+ if(!typefd[n->type->etype]) {
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod, r, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ gopcode(o, r, Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+ }
+ genasop(o, l, r, nn);
+ break;
+
+ case OASLMUL:
+ case OASLDIV:
+ case OASLMOD:
+ case OASMUL:
+ case OASDIV:
+ case OASMOD:
+ if(l->op == OBIT)
+ goto asbitop;
+ genasop(o, l, r, nn);
+ break;
+
+ asbitop:
+ regalloc(&nod4, n, nn);
+ if(l->complex >= r->complex) {
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ } else {
+ regalloc(&nod3, r, Z);
+ cgen(r, &nod3);
+ bitload(l, &nod, &nod1, &nod2, &nod4);
+ }
+ gmove(&nod, &nod4);
+ gopcode(o, &nod3, Z, &nod4);
+ regfree(&nod3);
+ gmove(&nod4, &nod);
+ regfree(&nod4);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+
+ case OADDR:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ lcgen(l, nn);
+ break;
+
+ case OFUNC:
+ if(l->complex >= FNX) {
+ if(l->op != OIND)
+ diag(n, "bad function call");
+
+ regret(&nod, l->left);
+ cgen(l->left, &nod);
+ regsalloc(&nod1, l->left);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+
+ nod = *n;
+ nod.left = &nod2;
+ nod2 = *l;
+ nod2.left = &nod1;
+ nod2.complex = 1;
+ cgen(&nod, nn);
+
+ return;
+ }
+ o = reg[REGARG];
+ gargs(r, &nod, &nod1);
+ if(l->addable < INDEXED) {
+ reglcgen(&nod, l, Z);
+ gopcode(OFUNC, Z, Z, &nod);
+ regfree(&nod);
+ } else
+ gopcode(OFUNC, Z, Z, l);
+ if(REGARG)
+ if(o != reg[REGARG])
+ reg[REGARG]--;
+ if(nn != Z) {
+ regret(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ }
+ break;
+
+ case OIND:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ regialloc(&nod, n, nn);
+ r = l;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ cgen(l, &nod);
+ nod.xoffset += v;
+ r->vconst = v;
+ } else
+ cgen(l, &nod);
+ regind(&nod, n);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLO:
+ case OLS:
+ case OHI:
+ case OHS:
+ if(nn == Z) {
+ nullwarn(l, r);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ boolgen(n, 1, nn);
+ if(nn == Z)
+ patch(p, pc);
+ break;
+
+ case ONOT:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ boolgen(n, 1, nn);
+ break;
+
+ case OCOMMA:
+ cgen(l, Z);
+ cgen(r, nn);
+ break;
+
+ case OCAST:
+ if(nn == Z) {
+ nullwarn(l, Z);
+ break;
+ }
+ /*
+ * convert from types l->n->nn
+ */
+ if(nocast(l->type, n->type)) {
+ if(nocast(n->type, nn->type)) {
+ cgen(l, nn);
+ break;
+ }
+ }
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ regalloc(&nod1, n, &nod);
+ gopcode(OAS, &nod, Z, &nod1);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ regfree(&nod);
+ break;
+
+ case ODOT:
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod = *nodrat;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod.xoffset += (long)r->vconst;
+ nod.type = n->type;
+ cgen(&nod, nn);
+ }
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ cgen(r->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ cgen(r->right, nn);
+ patch(p1, pc);
+ break;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPOSTDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+ if(nn == Z)
+ goto pre;
+
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ regalloc(&nod1, l, Z);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, &nod, &nod1);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, &nod, &nod1);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), &nod, &nod1);
+ gopcode(OAS, &nod1, Z, &nod2);
+
+ regfree(&nod);
+ regfree(&nod1);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ v = 1;
+ if(l->type->etype == TIND)
+ v = l->type->link->width;
+ if(o == OPREDEC)
+ v = -v;
+ if(l->op == OBIT)
+ goto bitinc;
+
+ pre:
+ if(l->addable < INDEXED)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+
+ regalloc(&nod, l, nn);
+ gopcode(OAS, &nod2, Z, &nod);
+ if(typefd[l->type->etype]) {
+ regalloc(&nod3, l, Z);
+ if(v < 0) {
+ gopcode(OAS, nodfconst(-v), Z, &nod3);
+ gopcode(OSUB, &nod3, Z, &nod);
+ } else {
+ gopcode(OAS, nodfconst(v), Z, &nod3);
+ gopcode(OADD, &nod3, Z, &nod);
+ }
+ regfree(&nod3);
+ } else
+ gopcode(OADD, nodconst(v), Z, &nod);
+ gopcode(OAS, &nod, Z, &nod2);
+ if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */
+ gins(ANOP, l, Z);
+
+ regfree(&nod);
+ if(l->addable < INDEXED)
+ regfree(&nod2);
+ break;
+
+ bitinc:
+ if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+ bitload(l, &nod, &nod1, &nod2, Z);
+ gopcode(OAS, &nod, Z, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, Z);
+ break;
+ }
+ bitload(l, &nod, &nod1, &nod2, nn);
+ gopcode(OADD, nodconst(v), Z, &nod);
+ bitstore(l, &nod, &nod1, &nod2, nn);
+ break;
+ }
+ cursafe = curs;
+}
+
+static void
+genasop(int o, Node *l, Node *r, Node *nn)
+{
+ Node nod, nod1, nod2;
+ int hardleft;
+
+ hardleft = l->addable < INDEXED || l->complex >= FNX;
+ if(l->complex >= r->complex) {
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ } else {
+ regalloc(&nod1, r, Z);
+ cgen(r, &nod1);
+ if(hardleft)
+ reglcgen(&nod2, l, Z);
+ else
+ nod2 = *l;
+ }
+ if(nod1.type == nod2.type || !typefd[nod1.type->etype])
+ regalloc(&nod, &nod2, nn);
+ else
+ regalloc(&nod, &nod1, Z);
+ gmove(&nod2, &nod);
+ gopcode(o, &nod1, Z, &nod);
+ gmove(&nod, &nod2);
+ if(nn != Z)
+ gmove(&nod2, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ if(hardleft)
+ regfree(&nod2);
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+ Node *r;
+ long v;
+
+ regialloc(t, n, nn);
+ if(n->op == OIND) {
+ r = n->left;
+ while(r->op == OADD)
+ r = r->right;
+ if(sconst(r)) {
+ v = r->vconst;
+ r->vconst = 0;
+ lcgen(n, t);
+ t->xoffset += v;
+ r->vconst = v;
+ regind(t, n);
+ return;
+ }
+ }
+ lcgen(n, t);
+ regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+ Prog *p1;
+ Node nod;
+
+ if(debug['g']) {
+ prtree(nn, "lcgen lhs");
+ prtree(n, "lcgen");
+ }
+ if(n == Z || n->type == T)
+ return;
+ if(nn == Z) {
+ nn = &nod;
+ regalloc(&nod, n, Z);
+ }
+ switch(n->op) {
+ default:
+ if(n->addable < INDEXED) {
+ diag(n, "unknown op in lcgen: %O", n->op);
+ break;
+ }
+ nod = *n;
+ nod.op = OADDR;
+ nod.left = n;
+ nod.right = Z;
+ nod.type = types[TIND];
+ gopcode(OAS, &nod, Z, nn);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, n->left);
+ lcgen(n->right, nn);
+ break;
+
+ case OIND:
+ cgen(n->left, nn);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ lcgen(n->right->left, nn);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ lcgen(n->right->right, nn);
+ patch(p1, pc);
+ break;
+ }
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+ if(n->type == T)
+ gbranch(OGOTO);
+ else
+ boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+ int o;
+ Prog *p1, *p2;
+ Node *l, *r, nod, nod1;
+ long curs;
+
+ if(debug['g']) {
+ prtree(nn, "boolgen lhs");
+ prtree(n, "boolgen");
+ }
+ curs = cursafe;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ default:
+ regalloc(&nod, n, nn);
+ cgen(n, &nod);
+ if(nn == Z || typefd[n->type->etype]) {
+ o = ONE;
+ if(true)
+ o = comrel[relindex(o)];
+ if(typefd[n->type->etype]) {
+ regalloc(&nod1, n, Z);
+ gmove(nodfconst(0.0), &nod1);
+ gopcode(o, &nod, &nod1, Z);
+ regfree(&nod1);
+ } else
+ gopcode(o, &nod, Z, Z);
+ regfree(&nod);
+ goto com;
+ }
+ if(true)
+ gopcode(OCOND, &nod, nodconst(0), &nod);
+ else
+ gopcode(OCOND, nodconst(1), &nod, &nod);
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ break;
+
+ case OCONST:
+ o = vconst(n);
+ if(!true)
+ o = !o;
+ gbranch(OGOTO);
+ if(o) {
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ }
+ goto com;
+
+ case OCOMMA:
+ cgen(l, Z);
+ boolgen(r, true, nn);
+ break;
+
+ case ONOT:
+ boolgen(l, !true, nn);
+ break;
+
+ case OCOND:
+ bcgen(l, 1);
+ p1 = p;
+ bcgen(r->left, true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ bcgen(r->right, !true);
+ patch(p2, pc);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OANDAND:
+ if(!true)
+ goto caseor;
+
+ caseand:
+ bcgen(l, true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ patch(p1, pc);
+ gbranch(OGOTO);
+ patch(p2, pc);
+ goto com;
+
+ case OOROR:
+ if(!true)
+ goto caseand;
+
+ caseor:
+ bcgen(l, !true);
+ p1 = p;
+ bcgen(r, !true);
+ p2 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ patch(p2, pc);
+ goto com;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ o = n->op;
+ if(true)
+ o = comrel[relindex(o)];
+ if(l->complex >= FNX && r->complex >= FNX) {
+ regret(&nod, r);
+ cgen(r, &nod);
+ regsalloc(&nod1, r);
+ gopcode(OAS, &nod, Z, &nod1);
+ regfree(&nod);
+ nod = *n;
+ nod.right = &nod1;
+ boolgen(&nod, true, nn);
+ break;
+ }
+ if(nn != Z && !typefd[l->type->etype]) {
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ switch(o) {
+ case OEQ:
+ gopcode(OSUB, &nod1, &nod, &nod);
+ gopcode(OCOND, &nod, nodconst(0), &nod);
+ break;
+ case ONE:
+ gopcode(OSUB, &nod1, &nod, &nod);
+ gopcode(OCOND, nodconst(1), &nod, &nod);
+ break;
+ case OLE:
+ gopcode(OCOMMA, &nod1, &nod, &nod);
+ break;
+ case OGT:
+ gopcode(OCOMMA, &nod1, &nod, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OLT:
+ gopcode(OCOMMA, &nod, &nod1, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OGE:
+ gopcode(OCOMMA, &nod, &nod1, &nod);
+ break;
+ case OLS:
+ gopcode(OCOND, &nod1, &nod, &nod);
+ break;
+ case OHI:
+ gopcode(OCOND, &nod1, &nod, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OLO:
+ gopcode(OCOND, &nod, &nod1, &nod);
+ gopcode(OXOR, nodconst(1), &nod, &nod);
+ break;
+ case OHS:
+ gopcode(OCOND, &nod, &nod1, &nod);
+ break;
+ }
+ gopcode(OAS, &nod, Z, nn);
+ regfree(&nod);
+ regfree(&nod1);
+ break;
+ }
+ if(sconst(l)) {
+ switch(o) {
+ default:
+ if(l->vconst != 0)
+ break;
+
+ case OGT:
+ case OHI:
+ case OLE:
+ case OLS:
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ gopcode(o, l, &nod, Z);
+ regfree(&nod);
+ goto com;
+ }
+ }
+ if(sconst(r)) {
+ switch(o) {
+ default:
+ if(r->vconst != 0)
+ break;
+
+ case OGE:
+ case OHS:
+ case OLT:
+ case OLO:
+ regalloc(&nod, l, nn);
+ cgen(l, &nod);
+ gopcode(o, &nod, r, Z);
+ regfree(&nod);
+ goto com;
+ }
+ }
+ if(l->complex >= r->complex) {
+ regalloc(&nod1, l, nn);
+ cgen(l, &nod1);
+ regalloc(&nod, r, Z);
+ cgen(r, &nod);
+ } else {
+ regalloc(&nod, r, nn);
+ cgen(r, &nod);
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ }
+ gopcode(o, &nod1, &nod, Z);
+ regfree(&nod);
+ regfree(&nod1);
+
+ com:
+ if(nn != Z) {
+ p1 = p;
+ gopcode(OAS, nodconst(1), Z, nn);
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gopcode(OAS, nodconst(0), Z, nn);
+ patch(p2, pc);
+ }
+ break;
+ }
+ cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+ Prog *p1;
+ Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+ Type *t;
+ long pc1;
+ int i, m, c;
+
+ if(n == Z || n->type == T)
+ return;
+ if(debug['g']) {
+ prtree(nn, "sugen lhs");
+ prtree(n, "sugen");
+ }
+ if(nn == nodrat)
+ if(w > nrathole)
+ nrathole = w;
+ switch(n->op) {
+ case OIND:
+ if(nn == Z) {
+ nullwarn(n->left, Z);
+ break;
+ }
+
+ default:
+ goto copy;
+
+ case ODOT:
+ l = n->left;
+ sugen(l, nodrat, l->type->width);
+ if(nn != Z) {
+ warn(n, "non-interruptable temporary");
+ nod1 = *nodrat;
+ r = n->right;
+ if(!r || r->op != OCONST) {
+ diag(n, "DOT and no offset");
+ break;
+ }
+ nod1.xoffset += (long)r->vconst;
+ nod1.type = n->type;
+ sugen(&nod1, nn, w);
+ }
+ break;
+
+ case OSTRUCT:
+ /*
+ * rewrite so lhs has no side effects
+ */
+ if(nn != Z && side(nn)) {
+ nod1 = *n;
+ nod1.type = typ(TIND, n->type);
+ regalloc(&nod2, &nod1, Z);
+ lcgen(nn, &nod2);
+ regsalloc(&nod0, &nod1);
+ gopcode(OAS, &nod2, Z, &nod0);
+ regfree(&nod2);
+
+ nod1 = *n;
+ nod1.op = OIND;
+ nod1.left = &nod0;
+ nod1.right = Z;
+ nod1.complex = 1;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ r = n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ l = r;
+ if(r->op == OLIST) {
+ l = r->left;
+ r = r->right;
+ }
+ if(nn == Z) {
+ cgen(l, nn);
+ continue;
+ }
+ /*
+ * hand craft *(&nn + o) = l
+ */
+ nod0 = znode;
+ nod0.op = OAS;
+ nod0.type = t;
+ nod0.left = &nod1;
+ nod0.right = l;
+
+ nod1 = znode;
+ nod1.op = OIND;
+ nod1.type = t;
+ nod1.left = &nod2;
+
+ nod2 = znode;
+ nod2.op = OADD;
+ nod2.type = typ(TIND, t);
+ nod2.left = &nod3;
+ nod2.right = &nod4;
+
+ nod3 = znode;
+ nod3.op = OADDR;
+ nod3.type = nod2.type;
+ nod3.left = nn;
+
+ nod4 = znode;
+ nod4.op = OCONST;
+ nod4.type = nod2.type;
+ nod4.vconst = t->offset;
+
+ ccom(&nod0);
+ acom(&nod0);
+ xcom(&nod0);
+ nod0.addable = 0;
+
+ cgen(&nod0, Z);
+ }
+ break;
+
+ case OAS:
+ if(nn == Z) {
+ if(n->addable < INDEXED)
+ sugen(n->right, n->left, w);
+ break;
+ }
+ sugen(n->right, nodrat, w);
+ warn(n, "non-interruptable temporary");
+ sugen(nodrat, n->left, w);
+ sugen(nodrat, nn, w);
+ break;
+
+ case OFUNC:
+ if(nn == Z) {
+ sugen(n, nodrat, w);
+ break;
+ }
+ if(nn->op != OIND) {
+ nn = new1(OADDR, nn, Z);
+ nn->type = types[TIND];
+ nn->addable = 0;
+ } else
+ nn = nn->left;
+ n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+ n->type = types[TVOID];
+ n->left->type = types[TVOID];
+ cgen(n, Z);
+ break;
+
+ case OCOND:
+ bcgen(n->left, 1);
+ p1 = p;
+ sugen(n->right->left, nn, w);
+ gbranch(OGOTO);
+ patch(p1, pc);
+ p1 = p;
+ sugen(n->right->right, nn, w);
+ patch(p1, pc);
+ break;
+
+ case OCOMMA:
+ cgen(n->left, Z);
+ sugen(n->right, nn, w);
+ break;
+ }
+ return;
+
+copy:
+ if(nn == Z)
+ return;
+ if(n->complex >= FNX && nn->complex >= FNX) {
+ t = nn->type;
+ nn->type = types[TLONG];
+ regialloc(&nod1, nn, Z);
+ lcgen(nn, &nod1);
+ regsalloc(&nod2, nn);
+ nn->type = t;
+
+ gopcode(OAS, &nod1, Z, &nod2);
+ regfree(&nod1);
+
+ nod2.type = typ(TIND, t);
+
+ nod1 = nod2;
+ nod1.op = OIND;
+ nod1.left = &nod2;
+ nod1.right = Z;
+ nod1.complex = 1;
+ nod1.type = t;
+
+ sugen(n, &nod1, w);
+ return;
+ }
+
+ if(n->complex > nn->complex) {
+ t = n->type;
+ n->type = types[TVLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+
+ t = nn->type;
+ nn->type = types[TVLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+ } else {
+ t = nn->type;
+ nn->type = types[TVLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = t;
+
+ t = n->type;
+ n->type = types[TVLONG];
+ reglcgen(&nod1, n, Z);
+ n->type = t;
+ }
+
+ w /= SZ_VLONG;
+ if(w <= 5) {
+ layout(&nod1, &nod2, w, 0, Z);
+ goto out;
+ }
+
+ /*
+ * minimize space for unrolling loop
+ * 3,4,5 times. (6 or more is never minimum)
+ * if small structure, try 2 also.
+ */
+ c = 0; /* set */
+ m = 100;
+ i = 3;
+ if(w <= 15)
+ i = 2;
+ for(; i<=5; i++)
+ if(i + w%i <= m) {
+ c = i;
+ m = c + w%c;
+ }
+
+ regalloc(&nod3, ®node, Z);
+ layout(&nod1, &nod2, w%c, w/c, &nod3);
+
+ pc1 = pc;
+ layout(&nod1, &nod2, c, 0, Z);
+
+ gopcode(OSUB, nodconst(1), Z, &nod3);
+ nod1.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_VLONG), Z, &nod1);
+ nod2.op = OREGISTER;
+ gopcode(OADD, nodconst(c*SZ_VLONG), Z, &nod2);
+
+ gopcode(OEQ, &nod3, Z, Z);
+ p->as = ABGTZ;
+ patch(p, pc1);
+
+ regfree(&nod3);
+out:
+ regfree(&nod1);
+ regfree(&nod2);
+}
+
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+ Node t1, t2;
+
+ while(c > 3) {
+ layout(f, t, 2, 0, Z);
+ c -= 2;
+ }
+
+ regalloc(&t1, ®node, Z);
+ regalloc(&t2, ®node, Z);
+ t1.type = types[TVLONG];
+ t2.type = types[TVLONG];
+ if(c > 0) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_VLONG;
+ }
+ if(cn != Z)
+ gopcode(OAS, nodconst(cv), Z, cn);
+ if(c > 1) {
+ gopcode(OAS, f, Z, &t2);
+ f->xoffset += SZ_VLONG;
+ }
+ if(c > 0) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_VLONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, f, Z, &t1);
+ f->xoffset += SZ_VLONG;
+ }
+ if(c > 1) {
+ gopcode(OAS, &t2, Z, t);
+ t->xoffset += SZ_VLONG;
+ }
+ if(c > 2) {
+ gopcode(OAS, &t1, Z, t);
+ t->xoffset += SZ_VLONG;
+ }
+ regfree(&t1);
+ regfree(&t2);
+}
--- /dev/null
+++ b/sys/src/cmd/zc/enam.c
@@ -1,0 +1,116 @@
+char* anames[] =
+{
+ "XXX",
+ "ABSD",
+ "ABSF",
+ "ADD",
+ "ADDD",
+ "ADDF",
+ "ADDU",
+ "ADDW",
+ "AND",
+ "BEQ",
+ "BFPF",
+ "BFPT",
+ "BGEZ",
+ "BGTZ",
+ "BLEZ",
+ "BLTZ",
+ "BNE",
+ "BREAK",
+ "CMPEQD",
+ "CMPEQF",
+ "CMPGED",
+ "CMPGEF",
+ "CMPGTD",
+ "CMPGTF",
+ "DATA",
+ "DIV",
+ "DIVD",
+ "DIVF",
+ "DIVU",
+ "DIVW",
+ "GLOBL",
+ "GOK",
+ "HISTORY",
+ "JAL",
+ "JMP",
+ "MOVB",
+ "MOVBU",
+ "MOVD",
+ "MOVDF",
+ "MOVDW",
+ "MOVF",
+ "MOVFD",
+ "MOVFW",
+ "MOVH",
+ "MOVHU",
+ "MOVW",
+ "MOVWD",
+ "MOVWF",
+ "MOVWL",
+ "MOVWR",
+ "MUL",
+ "MULD",
+ "MULF",
+ "MULU",
+ "MULW",
+ "NAME32",
+ "NAME",
+ "NEGD",
+ "NEGF",
+ "NEGW",
+ "NOP",
+ "NOR",
+ "OR",
+ "REM",
+ "REMU",
+ "RET",
+ "SGT",
+ "SGTU",
+ "SLL",
+ "SRA",
+ "SRL",
+ "SUB",
+ "SUBD",
+ "SUBF",
+ "SUBU",
+ "SUBW",
+ "SYSCALL",
+ "TEXT",
+ "WORD",
+ "XOR",
+ "END",
+ "MOVV",
+ "MOVVL",
+ "MOVVR",
+ "SLLV",
+ "SRAV",
+ "SRLV",
+ "DIVV",
+ "DIVVU",
+ "REMV",
+ "REMVU",
+ "MULV",
+ "MULVU",
+ "ADDV",
+ "ADDVU",
+ "SUBV",
+ "SUBVU",
+ "DYNT",
+ "INIT",
+ "TRUNCFV",
+ "TRUNCDV",
+ "TRUNCFW",
+ "TRUNCDW",
+ "MOVWU",
+ "MOVFV",
+ "MOVDV",
+ "MOVVF",
+ "MOVVD",
+ "LU12IW",
+ "LU32ID",
+ "LU52ID",
+ "SIGNAME",
+ "LAST",
+};
--- /dev/null
+++ b/sys/src/cmd/zc/gc.h
@@ -1,0 +1,334 @@
+#include "../cc/cc.h"
+#include "../zc/z.out.h"
+
+/*
+ * zc/loong
+ * LoongArch
+ */
+#define SZ_CHAR 1
+#define SZ_SHORT 2
+#define SZ_INT 4
+#define SZ_LONG 4
+#define SZ_IND 8
+#define SZ_FLOAT 4
+#define SZ_VLONG 8
+#define SZ_DOUBLE 8
+#define FNX 100
+
+typedef struct Adr Adr;
+typedef struct Prog Prog;
+typedef struct Case Case;
+typedef struct C1 C1;
+typedef struct Multab Multab;
+typedef struct Hintab Hintab;
+typedef struct Var Var;
+typedef struct Reg Reg;
+typedef struct Rgn Rgn;
+
+struct Adr
+{
+ vlong offset;
+ double dval;
+ char sval[NSNAME];
+ Ieee ieee;
+
+ Sym* sym;
+ char type;
+ char reg;
+ char name;
+ char etype;
+};
+#define A ((Adr*)0)
+
+#define INDEXED 9
+struct Prog
+{
+ Adr from;
+ Adr to;
+ Prog* link;
+ long lineno;
+ char as;
+ char reg;
+};
+#define P ((Prog*)0)
+
+struct Case
+{
+ Case* link;
+ vlong val;
+ long label;
+ char def;
+ char isv;
+};
+#define C ((Case*)0)
+
+struct C1
+{
+ vlong val;
+ long label;
+};
+
+struct Multab
+{
+ long val;
+ char code[20];
+};
+
+struct Hintab
+{
+ ushort val;
+ char hint[10];
+};
+
+struct Var
+{
+ long offset;
+ Sym* sym;
+ char name;
+ char etype;
+};
+
+struct Reg
+{
+ long pc;
+ long rpo; /* reverse post ordering */
+
+ Bits set;
+ Bits use1;
+ Bits use2;
+
+ Bits refbehind;
+ Bits refahead;
+ Bits calbehind;
+ Bits calahead;
+ Bits regdiff;
+ Bits act;
+
+ long regu;
+ long loop; /* could be shorter */
+
+ Reg* log5;
+ long active;
+
+ Reg* p1;
+ Reg* p2;
+ Reg* p2link;
+ Reg* s1;
+ Reg* s2;
+ Reg* link;
+ Prog* prog;
+};
+#define R ((Reg*)0)
+
+#define NRGN 1000
+struct Rgn
+{
+ Reg* enter;
+ short cost;
+ short varno;
+ short regno;
+};
+
+EXTERN long breakpc;
+EXTERN long nbreak;
+EXTERN Case* cases;
+EXTERN Node constnode;
+EXTERN Node fconstnode;
+EXTERN long continpc;
+EXTERN long curarg;
+EXTERN long cursafe;
+EXTERN Prog* firstp;
+EXTERN Prog* lastp;
+EXTERN long maxargsafe;
+EXTERN int mnstring;
+EXTERN Multab multab[20];
+EXTERN int hintabsize;
+EXTERN Node* nodrat;
+EXTERN Node* nodret;
+EXTERN Node* nodsafe;
+EXTERN long nrathole;
+EXTERN long nstring;
+EXTERN Prog* p;
+EXTERN long pc;
+EXTERN Node regnode;
+EXTERN char string[NSNAME];
+EXTERN Sym* symrathole;
+EXTERN Node znode;
+EXTERN Prog zprog;
+EXTERN char reg[NREG+NREG];
+EXTERN long exregoffset;
+EXTERN long exfregoffset;
+
+#define BLOAD(r) band(bnot(r->refbehind), r->refahead)
+#define BSTORE(r) band(bnot(r->calbehind), r->calahead)
+#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z])
+#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z])
+
+#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32))
+
+#define CLOAD 4
+#define CREF 5
+#define CINF 1000
+#define LOOP 3
+
+EXTERN Rgn region[NRGN];
+EXTERN Rgn* rgp;
+EXTERN int nregion;
+EXTERN int nvar;
+
+EXTERN Bits externs;
+EXTERN Bits params;
+EXTERN Bits consts;
+EXTERN Bits addrs;
+
+EXTERN long regbits;
+EXTERN long exregbits;
+
+EXTERN int change;
+EXTERN int suppress;
+
+EXTERN Reg* firstr;
+EXTERN Reg* lastr;
+EXTERN Reg zreg;
+EXTERN Reg* freer;
+EXTERN Var var[NVAR];
+EXTERN long* idom;
+EXTERN Reg** rpo2r;
+EXTERN long maxnr;
+
+extern char* anames[];
+extern Hintab hintab[];
+
+/*
+ * sgen.c
+ */
+void codgen(Node*, Node*);
+void gen(Node*);
+void noretval(int);
+void xcom(Node*);
+int bcomplex(Node*, Node*);
+void usedset(Node*, int);
+
+/*
+ * cgen.c
+ */
+void cgen(Node*, Node*);
+void reglcgen(Node*, Node*, Node*);
+void lcgen(Node*, Node*);
+void bcgen(Node*, int);
+void boolgen(Node*, int, Node*);
+void sugen(Node*, Node*, long);
+void layout(Node*, Node*, int, int, Node*);
+
+/*
+ * txt.c
+ */
+void ginit(void);
+void gclean(void);
+void nextpc(void);
+void gargs(Node*, Node*, Node*);
+void garg1(Node*, Node*, Node*, int, Node**);
+Node* nodconst(long);
+Node* nod32const(vlong);
+Node* nodfconst(double);
+void nodreg(Node*, Node*, int);
+void regret(Node*, Node*);
+void regalloc(Node*, Node*, Node*);
+void regfree(Node*);
+void regialloc(Node*, Node*, Node*);
+void regsalloc(Node*, Node*);
+void regaalloc1(Node*, Node*);
+void regaalloc(Node*, Node*);
+void regind(Node*, Node*);
+void gprep(Node*, Node*);
+void raddr(Node*, Prog*);
+void naddr(Node*, Adr*);
+void gmove(Node*, Node*);
+void gins(int a, Node*, Node*);
+void gopcode(int, Node*, Node*, Node*);
+int samaddr(Node*, Node*);
+void gbranch(int);
+void patch(Prog*, vlong);
+int sconst(Node*);
+int llconst(Node*);
+int sval(long);
+void gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int swcmp(const void*, const void*);
+void doswit(Node*);
+void swit1(C1*, int, long, Node*);
+void swit2(C1*, int, long, Node*, Node*);
+void casf(void);
+void bitload(Node*, Node*, Node*, Node*, Node*);
+void bitstore(Node*, Node*, Node*, Node*, Node*);
+long outstring(char*, long);
+int mulcon(Node*, Node*);
+Multab* mulcon0(long);
+void nullwarn(Node*, Node*);
+void gextern(Sym*, Node*, long, long);
+void outcode(void);
+void ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void listinit(void);
+int Pconv(Fmt*);
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Sconv(Fmt*);
+int Nconv(Fmt*);
+int Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg* rega(void);
+int rcmp(const void*, const void*);
+void regopt(Prog*);
+void addmove(Reg*, int, int, int);
+Bits mkvar(Adr*, int);
+void prop(Reg*, Bits, Bits);
+void loopit(Reg*, long);
+void synch(Reg*, Bits);
+ulong allreg(ulong, Rgn*);
+void paint1(Reg*, int);
+ulong paint2(Reg*, int);
+void paint3(Reg*, int, long, int);
+void addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void peep(void);
+void excise(Reg*);
+Reg* uniqp(Reg*);
+Reg* uniqs(Reg*);
+int regtyp(Adr*);
+int regzer(Adr*);
+int anyvar(Adr*);
+int subprop(Reg*);
+int copyprop(Reg*);
+int copy1(Adr*, Adr*, Reg*, int);
+int copyu(Prog*, Adr*, Adr*);
+
+int copyas(Adr*, Adr*);
+int copyau(Adr*, Adr*);
+int copyau1(Prog*, Adr*);
+int copysub(Adr*, Adr*, Adr*, int);
+int copysub1(Prog*, Adr*, Adr*, int);
+
+long RtoB(int);
+long FtoB(int);
+int BtoR(long);
+int BtoF(long);
+
+#pragma varargck type "A" int
+#pragma varargck type "B" Bits
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
--- /dev/null
+++ b/sys/src/cmd/zc/lex.c
@@ -1,0 +1,1552 @@
+#include "cc.h"
+#include "y.tab.h"
+
+#ifndef CPP
+#define CPP "/bin/cpp"
+#endif
+
+/*
+ * known debug flags
+ * -a acid declaration output
+ * -A !B
+ * -B non ANSI
+ * -d print declarations
+ * -D name define
+ * -F format specification check
+ * -i print initialization
+ * -I path include
+ * -l generate little-endian code
+ * -L print every NAME symbol
+ * -M constant multiplication
+ * -m print add/sub/mul trees
+ * -n print acid to file (%.c=%.acid) (with -a or -aa)
+ * -o file output file
+ * -p use standard cpp ANSI preprocessor (not on windows)
+ * -r print registerization
+ * -s print structure offsets (with -a or -aa)
+ * -S print assembly
+ * -t print type trees
+ * -V enable void* conversion warnings
+ * -v verbose printing
+ * -w print warnings
+ * -X abort on error
+ * -. Inhibit search for includes in source directory
+ */
+
+void
+main(int argc, char *argv[])
+{
+ char **defs, **np, *p;
+ int nproc, nout, status, i, c, ndef, maxdef;
+
+ memset(debug, 0, sizeof(debug));
+ tinit();
+ cinit();
+ ginit();
+ arginit();
+
+ profileflg = 1; /* #pragma can turn it off */
+ tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+ maxdef = 0;
+ ndef = 0;
+ outfile = 0;
+ defs = nil;
+ setinclude(".");
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+
+ case 'o':
+ outfile = ARGF();
+ break;
+
+ case 'D':
+ p = ARGF();
+ if(p) {
+ if(ndef >= maxdef){
+ maxdef += 50;
+ np = alloc(maxdef * sizeof *np);
+ if(defs != nil)
+ memmove(np, defs, (maxdef - 50) * sizeof *np);
+ defs = np;
+ }
+ defs[ndef++] = p;
+ dodefine(p);
+ }
+ break;
+
+ case 'I':
+ p = ARGF();
+ if(p)
+ setinclude(p);
+ break;
+ } ARGEND
+ if(argc < 1 && outfile == 0) {
+ print("usage: %cc [-options] files\n", thechar);
+ errorexit();
+ }
+ if(argc > 1 && systemtype(Windows)){
+ print("can't compile multiple files on windows\n");
+ errorexit();
+ }
+ if(argc > 1 && !systemtype(Windows)) {
+ nproc = 1;
+ /*
+ * if we're writing acid to standard output, don't compile
+ * concurrently, to avoid interleaving output.
+ */
+ if(((!debug['a'] && !debug['Z']) || debug['n']) &&
+ (p = getenv("NPROC")) != nil)
+ nproc = atol(p); /* */
+ c = 0;
+ nout = 0;
+ for(;;) {
+ while(nout < nproc && argc > 0) {
+ i = myfork();
+ if(i < 0) {
+ i = mywait(&status);
+ if(i < 0) {
+ print("cannot create a process\n");
+ errorexit();
+ }
+ if(status)
+ c++;
+ nout--;
+ continue;
+ }
+ if(i == 0) {
+ fprint(2, "%s:\n", *argv);
+ if (compile(*argv, defs, ndef))
+ errorexit();
+ exits(0);
+ }
+ nout++;
+ argc--;
+ argv++;
+ }
+ i = mywait(&status);
+ if(i < 0) {
+ if(c)
+ errorexit();
+ exits(0);
+ }
+ if(status)
+ c++;
+ nout--;
+ }
+ }
+
+ if(argc == 0)
+ c = compile("stdin", defs, ndef);
+ else
+ c = compile(argv[0], defs, ndef);
+
+ if(c)
+ errorexit();
+ exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+ char ofile[400], incfile[20];
+ char *p, **av, opt[256];
+ int i, c, fd[2];
+ static int first = 1;
+
+ strcpy(ofile, file);
+ p = utfrrune(ofile, pathchar());
+ if(p) {
+ *p++ = 0;
+ if(!debug['.'])
+ include[0] = strdup(ofile);
+ } else
+ p = ofile;
+
+ if(outfile == 0) {
+ outfile = p;
+ if(outfile) {
+ if(p = utfrrune(outfile, '.'))
+ if(p[1] == 'c' && p[2] == 0)
+ p[0] = 0;
+ p = utfrune(outfile, 0);
+ if(debug['a'] && debug['n'])
+ strcat(p, ".acid");
+ else if(debug['Z'] && debug['n'])
+ strcat(p, "_pickle.c");
+ else {
+ p[0] = '.';
+ p[1] = thechar;
+ p[2] = 0;
+ }
+ } else
+ outfile = "/dev/null";
+ }
+
+ if(p = getenv("INCLUDE")) {
+ setinclude(p);
+ } else {
+ if(systemtype(Plan9)) {
+ sprint(incfile, "/%s/include", thestring);
+ setinclude(strdup(incfile));
+ setinclude("/sys/include");
+ }
+ }
+ if (first)
+ Binit(&diagbuf, 1, OWRITE);
+ /*
+ * if we're writing acid to standard output, don't keep scratching
+ * outbuf.
+ */
+ if((debug['a'] || debug['Z']) && !debug['n']) {
+ if (first) {
+ outfile = 0;
+ Binit(&outbuf, dup(1, -1), OWRITE);
+ dup(2, 1);
+ }
+ } else {
+ c = mycreat(outfile, 0664);
+ if(c < 0) {
+ diag(Z, "cannot open %s - %r", outfile);
+ outfile = 0;
+ errorexit();
+ }
+ Binit(&outbuf, c, OWRITE);
+ }
+ newio();
+ first = 0;
+
+ /* Use an ANSI preprocessor */
+ if(debug['p']) {
+ if(systemtype(Windows)) {
+ diag(Z, "-p option not supported on windows");
+ errorexit();
+ }
+ if(myaccess(file) < 0) {
+ diag(Z, "%s does not exist", file);
+ errorexit();
+ }
+ if(mypipe(fd) < 0) {
+ diag(Z, "pipe failed");
+ errorexit();
+ }
+ switch(myfork()) {
+ case -1:
+ diag(Z, "fork failed");
+ errorexit();
+ case 0:
+ close(fd[0]);
+ mydup(fd[1], 1);
+ close(fd[1]);
+ av = alloc((3 + ndef + ninclude + 2) * sizeof *av);
+ av[0] = CPP;
+ i = 1;
+ if(debug['.'])
+ av[i++] = strdup("-.");
+ /* 1999 ANSI C requires recognising // comments */
+ av[i++] = strdup("-+");
+ for(c = 0; c < ndef; c++) {
+ sprint(opt, "-D%s", defs[c]);
+ av[i++] = strdup(opt);
+ }
+ for(c = 0; c < ninclude; c++) {
+ sprint(opt, "-I%s", include[c]);
+ av[i++] = strdup(opt);
+ }
+ if(strcmp(file, "stdin") != 0)
+ av[i++] = file;
+ av[i] = 0;
+ if(debug['p'] > 1) {
+ for(c = 0; c < i; c++)
+ fprint(2, "%s ", av[c]);
+ fprint(2, "\n");
+ }
+ myexec(av[0], av);
+ fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+ errorexit();
+ default:
+ close(fd[1]);
+ newfile(file, fd[0]);
+ break;
+ }
+ } else {
+ if(strcmp(file, "stdin") == 0)
+ newfile(file, 0);
+ else
+ newfile(file, -1);
+ }
+ yyparse();
+ if(!debug['a'] && !debug['Z'])
+ gclean();
+ return nerrors;
+}
+
+void
+errorexit(void)
+{
+ if(outfile)
+ remove(outfile);
+ exits("error");
+}
+
+void
+pushio(void)
+{
+ Io *i;
+
+ i = iostack;
+ if(i == I) {
+ yyerror("botch in pushio");
+ errorexit();
+ }
+ i->p = fi.p;
+ i->c = fi.c;
+}
+
+void
+newio(void)
+{
+ Io *i;
+ static int pushdepth = 0;
+
+ i = iofree;
+ if(i == I) {
+ pushdepth++;
+ if(pushdepth > 1000) {
+ yyerror("macro/io expansion too deep");
+ errorexit();
+ }
+ i = alloc(sizeof(*i));
+ } else
+ iofree = i->link;
+ i->c = 0;
+ i->f = -1;
+ ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+ Io *i;
+
+ if(debug['e'])
+ print("%L: %s\n", lineno, s);
+
+ i = ionext;
+ i->link = iostack;
+ iostack = i;
+ i->f = f;
+ if(f < 0)
+ i->f = open(s, 0);
+ if(i->f < 0) {
+ yyerror("%cc: %r: %s", thechar, s);
+ errorexit();
+ }
+ fi.c = 0;
+ linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+ strcpy(symb, s);
+ return lookup();
+}
+
+Sym*
+lookup(void)
+{
+ Sym *s;
+ ulong h;
+ char *p;
+ int c, n;
+
+ h = 0;
+ for(p=symb; *p;) {
+ h = h * 3;
+ h += *p++;
+ }
+ n = (p - symb) + 1;
+ if((long)h < 0)
+ h = ~h;
+ h %= NHASH;
+ c = symb[0];
+ for(s = hash[h]; s != S; s = s->link) {
+ if(s->name[0] != c)
+ continue;
+ if(strcmp(s->name, symb) == 0)
+ return s;
+ }
+ s = alloc(sizeof(*s));
+ s->name = alloc(n);
+ memmove(s->name, symb, n);
+
+ strcpy(s->name, symb);
+ s->link = hash[h];
+ hash[h] = s;
+ syminit(s);
+
+ return s;
+}
+
+void
+syminit(Sym *s)
+{
+ s->lexical = LNAME;
+ s->block = 0;
+ s->offset = 0;
+ s->type = T;
+ s->suetag = T;
+ s->class = CXXX;
+ s->aused = 0;
+ s->sig = SIGNONE;
+}
+
+#define EOF (-1)
+#define IGN (-2)
+#define ESC (Runemask+1) /* Rune flag: a literal byte */
+#define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+ Numdec = 1<<0,
+ Numlong = 1<<1,
+ Numuns = 1<<2,
+ Numvlong = 1<<3,
+ Numflt = 1<<4,
+};
+
+long
+yylex(void)
+{
+ vlong vv;
+ long c, c1, t;
+ char *cp;
+ Rune rune;
+ Sym *s;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ goto l1;
+ }
+l0:
+ c = GETC();
+
+l1:
+ if(c >= Runeself) {
+ /*
+ * extension --
+ * all multibyte runes are alpha
+ */
+ cp = symb;
+ goto talph;
+ }
+ if(isspace(c)) {
+ if(c == '\n')
+ lineno++;
+ goto l0;
+ }
+ if(isalpha(c)) {
+ cp = symb;
+ if(c != 'L')
+ goto talph;
+ *cp++ = c;
+ c = GETC();
+ if(c == '\'') {
+ /* L'x' */
+ c = escchar('\'', 1, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 1, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ yylval.vval = convvtox(c, TRUNE);
+ return LUCONST;
+ }
+ if(c == '"') {
+ goto caselq;
+ }
+ goto talph;
+ }
+ if(isdigit(c))
+ goto tnum;
+ switch(c)
+ {
+
+ case EOF:
+ peekc = EOF;
+ return -1;
+
+ case '_':
+ cp = symb;
+ goto talph;
+
+ case '#':
+ domacro();
+ goto l0;
+
+ case '.':
+ c1 = GETC();
+ if(isdigit(c1)) {
+ cp = symb;
+ *cp++ = c;
+ c = c1;
+ c1 = 0;
+ goto casedot;
+ }
+ break;
+
+ case '"':
+ strcpy(symb, "\"<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+
+ /* "..." */
+ for(;;) {
+ c = escchar('"', 0, 1);
+ if(c == EOF)
+ break;
+ if(c & ESC) {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = c;
+ } else {
+ rune = c;
+ c = runelen(rune);
+ cp = allocn(cp, c1, c);
+ runetochar(cp+c1, &rune);
+ c1 += c;
+ }
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, 1);
+ cp[c1++] = 0;
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LSTRING;
+
+ caselq:
+ /* L"..." */
+ strcpy(symb, "\"L<string>\"");
+ cp = alloc(0);
+ c1 = 0;
+ for(;;) {
+ c = escchar('"', 1, 0);
+ if(c == EOF)
+ break;
+ cp = allocn(cp, c1, sizeof(TRune));
+ *(TRune*)(cp + c1) = c;
+ c1 += sizeof(TRune);
+ }
+ yylval.sval.l = c1;
+ do {
+ cp = allocn(cp, c1, sizeof(TRune));
+ *(TRune*)(cp + c1) = 0;
+ c1 += sizeof(TRune);
+ } while(c1 & MAXALIGN);
+ yylval.sval.s = cp;
+ return LLSTRING;
+
+ case '\'':
+ /* '.' */
+ c = escchar('\'', 0, 0);
+ if(c == EOF)
+ c = '\'';
+ c1 = escchar('\'', 0, 0);
+ if(c1 != EOF) {
+ yyerror("missing '");
+ peekc = c1;
+ }
+ vv = c;
+ yylval.vval = convvtox(vv, TUCHAR);
+ if(yylval.vval != vv)
+ yyerror("overflow in character constant: 0x%lx", c);
+ else
+ if(c & 0x80){
+ nearln = lineno;
+ warn(Z, "sign-extended character constant");
+ }
+ yylval.vval = convvtox(vv, TCHAR);
+ return LCONST;
+
+ case '/':
+ c1 = GETC();
+ if(c1 == '*') {
+ for(;;) {
+ c = getr();
+ while(c == '*') {
+ c = getr();
+ if(c == '/')
+ goto l0;
+ }
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '/') {
+ for(;;) {
+ c = getr();
+ if(c == '\n')
+ goto l0;
+ if(c == EOF) {
+ yyerror("eof in comment");
+ errorexit();
+ }
+ }
+ }
+ if(c1 == '=')
+ return LDVE;
+ break;
+
+ case '*':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMLE;
+ break;
+
+ case '%':
+ c1 = GETC();
+ if(c1 == '=')
+ return LMDE;
+ break;
+
+ case '+':
+ c1 = GETC();
+ if(c1 == '+')
+ return LPP;
+ if(c1 == '=')
+ return LPE;
+ break;
+
+ case '-':
+ c1 = GETC();
+ if(c1 == '-')
+ return LMM;
+ if(c1 == '=')
+ return LME;
+ if(c1 == '>')
+ return LMG;
+ break;
+
+ case '>':
+ c1 = GETC();
+ if(c1 == '>') {
+ c = LRSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LRSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LGE;
+ break;
+
+ case '<':
+ c1 = GETC();
+ if(c1 == '<') {
+ c = LLSH;
+ c1 = GETC();
+ if(c1 == '=')
+ return LLSHE;
+ break;
+ }
+ if(c1 == '=')
+ return LLE;
+ break;
+
+ case '=':
+ c1 = GETC();
+ if(c1 == '=')
+ return LEQ;
+ break;
+
+ case '!':
+ c1 = GETC();
+ if(c1 == '=')
+ return LNE;
+ break;
+
+ case '&':
+ c1 = GETC();
+ if(c1 == '&')
+ return LANDAND;
+ if(c1 == '=')
+ return LANDE;
+ break;
+
+ case '|':
+ c1 = GETC();
+ if(c1 == '|')
+ return LOROR;
+ if(c1 == '=')
+ return LORE;
+ break;
+
+ case '^':
+ c1 = GETC();
+ if(c1 == '=')
+ return LXORE;
+ break;
+
+ default:
+ return c;
+ }
+ peekc = c1;
+ return c;
+
+talph:
+ /*
+ * cp is set to symb and some
+ * prefix has been stored
+ */
+ for(;;) {
+ if(c >= Runeself) {
+ for(c1=0;;) {
+ cp[c1++] = c;
+ if(fullrune(cp, c1))
+ break;
+ c = GETC();
+ }
+ cp += c1;
+ c = GETC();
+ continue;
+ }
+ if(!isalnum(c) && c != '_')
+ break;
+ *cp++ = c;
+ c = GETC();
+ }
+ *cp = 0;
+ if(debug['L'])
+ print("%L: %s\n", lineno, symb);
+ peekc = c;
+ s = lookup();
+ if(s->macro) {
+ newio();
+ cp = ionext->b;
+ macexpand(s, cp);
+ pushio();
+ ionext->link = iostack;
+ iostack = ionext;
+ fi.p = cp;
+ fi.c = strlen(cp);
+ if(peekc != IGN) {
+ cp[fi.c++] = peekc;
+ cp[fi.c] = 0;
+ peekc = IGN;
+ }
+ goto l0;
+ }
+ yylval.sym = s;
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ return LTYPE;
+ return s->lexical;
+
+tnum:
+ c1 = 0;
+ cp = symb;
+ if(c != '0') {
+ c1 |= Numdec;
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ goto dc;
+ }
+ }
+ *cp++ = c;
+ c = GETC();
+ if(c == 'x' || c == 'X')
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(isdigit(c))
+ continue;
+ if(c >= 'a' && c <= 'f')
+ continue;
+ if(c >= 'A' && c <= 'F')
+ continue;
+ if(cp == symb+2)
+ yyerror("malformed hex constant");
+ goto ncu;
+ }
+ if(c < '0' || c > '7')
+ goto dc;
+ for(;;) {
+ if(c >= '0' && c <= '7') {
+ *cp++ = c;
+ c = GETC();
+ continue;
+ }
+ goto ncu;
+ }
+
+dc:
+ if(c == '.')
+ goto casedot;
+ if(c == 'e' || c == 'E')
+ goto casee;
+
+ncu:
+ if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+ c = GETC();
+ c1 |= Numuns;
+ goto ncu;
+ }
+ if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+ c = GETC();
+ if(c1 & Numlong)
+ c1 |= Numvlong;
+ c1 |= Numlong;
+ goto ncu;
+ }
+ *cp = 0;
+ peekc = c;
+ if(mpatov(symb, &yylval.vval))
+ yyerror("overflow in constant");
+
+ vv = yylval.vval;
+ if(c1 & Numvlong) {
+ if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
+ c = LUVLCONST;
+ t = TUVLONG;
+ goto nret;
+ }
+ c = LVLCONST;
+ t = TVLONG;
+ goto nret;
+ }
+ if(c1 & Numlong) {
+ if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
+ c = LULCONST;
+ t = TULONG;
+ goto nret;
+ }
+ c = LLCONST;
+ t = TLONG;
+ goto nret;
+ }
+ if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
+ c = LUCONST;
+ t = TUINT;
+ goto nret;
+ }
+ c = LCONST;
+ t = TINT;
+ goto nret;
+
+nret:
+ yylval.vval = convvtox(vv, t);
+ if(yylval.vval != vv){
+ nearln = lineno;
+ warn(Z, "truncated constant: %T %s", types[t], symb);
+ }
+ return c;
+
+casedot:
+ for(;;) {
+ *cp++ = c;
+ c = GETC();
+ if(!isdigit(c))
+ break;
+ }
+ if(c != 'e' && c != 'E')
+ goto caseout;
+
+casee:
+ *cp++ = 'e';
+ c = GETC();
+ if(c == '+' || c == '-') {
+ *cp++ = c;
+ c = GETC();
+ }
+ if(!isdigit(c))
+ yyerror("malformed fp constant exponent");
+ while(isdigit(c)) {
+ *cp++ = c;
+ c = GETC();
+ }
+
+caseout:
+ if(c == 'L' || c == 'l') {
+ c = GETC();
+ c1 |= Numlong;
+ } else
+ if(c == 'F' || c == 'f') {
+ c = GETC();
+ c1 |= Numflt;
+ }
+ *cp = 0;
+ peekc = c;
+ yylval.dval = strtod(symb, nil);
+ if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
+ yyerror("overflow in float constant");
+ yylval.dval = 0;
+ }
+ if(c1 & Numflt)
+ return LFCONST;
+ return LDCONST;
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+ vlong n, nn;
+ int c;
+
+ n = 0;
+ c = *s;
+ if(c == '0')
+ goto oct;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ nn = n*10 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+oct:
+ s++;
+ c = *s;
+ if(c == 'x' || c == 'X')
+ goto hex;
+ while(c = *s++) {
+ if(c >= '0' || c <= '7')
+ nn = n*8 + c-'0';
+ else
+ goto bad;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+ goto out;
+
+hex:
+ s++;
+ while(c = *s++) {
+ if(c >= '0' && c <= '9')
+ c += 0-'0';
+ else
+ if(c >= 'a' && c <= 'f')
+ c += 10-'a';
+ else
+ if(c >= 'A' && c <= 'F')
+ c += 10-'A';
+ else
+ goto bad;
+ nn = n*16 + c;
+ if(n < 0 && nn >= 0)
+ goto bad;
+ n = nn;
+ }
+out:
+ *v = n;
+ return 0;
+
+bad:
+ *v = ~0;
+ return 1;
+}
+
+int
+getc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ if(c == '\n')
+ lineno++;
+ if(c == EOF) {
+ yyerror("End of file");
+ errorexit();
+ }
+ return c;
+}
+
+long
+getr(void)
+{
+ int c, i;
+ char str[UTFmax+1];
+ Rune rune;
+
+
+ c = getc();
+ if(c < Runeself)
+ return c;
+ i = 0;
+ str[i++] = c;
+
+loop:
+ c = getc();
+ str[i++] = c;
+ if(!fullrune(str, i))
+ goto loop;
+ c = chartorune(&rune, str);
+ if(rune == Runeerror && c == 1) {
+ nearln = lineno;
+ diag(Z, "illegal rune in string");
+ for(c=0; c<i; c++)
+ print(" %.2x", *(uchar*)(str+c));
+ print("\n");
+ }
+ return rune;
+}
+
+int
+getnsc(void)
+{
+ int c;
+
+ if(peekc != IGN) {
+ c = peekc;
+ peekc = IGN;
+ } else
+ c = GETC();
+ for(;;) {
+ if(c >= Runeself || !isspace(c))
+ return c;
+ if(c == '\n') {
+ lineno++;
+ return c;
+ }
+ c = GETC();
+ }
+}
+
+void
+unget(int c)
+{
+
+ peekc = c;
+ if(c == '\n')
+ lineno--;
+}
+
+long
+escchar(long e, int longflg, int escflg)
+{
+ long c, l;
+ int i;
+
+loop:
+ c = getr();
+ if(c == '\n') {
+ yyerror("newline in string");
+ return EOF;
+ }
+ if(c != '\\') {
+ if(c == e)
+ c = EOF;
+ return c;
+ }
+ c = getr();
+ if(c == 'x') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 2 hex
+ */
+ i = 2;
+ if(longflg)
+ i = 6;
+ l = 0;
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '9') {
+ l = l*16 + c-'0';
+ continue;
+ }
+ if(c >= 'a' && c <= 'f') {
+ l = l*16 + c-'a' + 10;
+ continue;
+ }
+ if(c >= 'A' && c <= 'F') {
+ l = l*16 + c-'A' + 10;
+ continue;
+ }
+ unget(c);
+ break;
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ if(c >= '0' && c <= '7') {
+ /*
+ * note this is not ansi,
+ * supposed to only accept 3 oct
+ */
+ i = 2;
+ if(longflg)
+ i = 8;
+ l = c - '0';
+ for(; i>0; i--) {
+ c = getc();
+ if(c >= '0' && c <= '7') {
+ l = l*8 + c-'0';
+ continue;
+ }
+ unget(c);
+ }
+ if(escflg)
+ l |= ESC;
+ return l;
+ }
+ switch(c)
+ {
+ case '\n': goto loop;
+ case 'n': return '\n';
+ case 't': return '\t';
+ case 'b': return '\b';
+ case 'r': return '\r';
+ case 'f': return '\f';
+ case 'a': return '\a';
+ case 'v': return '\v';
+ }
+ return c;
+}
+
+struct
+{
+ char *name;
+ ushort lexical;
+ ushort type;
+} itab[] =
+{
+ "auto", LAUTO, 0,
+ "break", LBREAK, 0,
+ "case", LCASE, 0,
+ "char", LCHAR, TCHAR,
+ "const", LCONSTNT, 0,
+ "continue", LCONTINUE, 0,
+ "default", LDEFAULT, 0,
+ "do", LDO, 0,
+ "double", LDOUBLE, TDOUBLE,
+ "else", LELSE, 0,
+ "enum", LENUM, 0,
+ "extern", LEXTERN, 0,
+ "float", LFLOAT, TFLOAT,
+ "for", LFOR, 0,
+ "goto", LGOTO, 0,
+ "if", LIF, 0,
+ "inline", LINLINE, 0,
+ "int", LINT, TINT,
+ "long", LLONG, TLONG,
+ "register", LREGISTER, 0,
+ "restrict", LRESTRICT, 0,
+ "return", LRETURN, 0,
+ "SET", LSET, 0,
+ "short", LSHORT, TSHORT,
+ "signed", LSIGNED, 0,
+ "signof", LSIGNOF, 0,
+ "sizeof", LSIZEOF, 0,
+ "static", LSTATIC, 0,
+ "struct", LSTRUCT, 0,
+ "switch", LSWITCH, 0,
+ "typedef", LTYPEDEF, 0,
+ "typestr", LTYPESTR, 0,
+ "union", LUNION, 0,
+ "unsigned", LUNSIGNED, 0,
+ "USED", LUSED, 0,
+ "void", LVOID, TVOID,
+ "volatile", LVOLATILE, 0,
+ "while", LWHILE, 0,
+ 0
+};
+
+void
+cinit(void)
+{
+ Sym *s;
+ int i;
+ Type *t;
+
+ nerrors = 0;
+ lineno = 1;
+ iostack = I;
+ iofree = I;
+ peekc = IGN;
+ nhunk = 0;
+
+ types[TXXX] = T;
+ types[TCHAR] = typ(TCHAR, T);
+ types[TUCHAR] = typ(TUCHAR, T);
+ types[TSHORT] = typ(TSHORT, T);
+ types[TUSHORT] = typ(TUSHORT, T);
+ types[TINT] = typ(TINT, T);
+ types[TUINT] = typ(TUINT, T);
+ types[TLONG] = typ(TLONG, T);
+ types[TULONG] = typ(TULONG, T);
+ types[TVLONG] = typ(TVLONG, T);
+ types[TUVLONG] = typ(TUVLONG, T);
+ types[TFLOAT] = typ(TFLOAT, T);
+ types[TDOUBLE] = typ(TDOUBLE, T);
+ types[TVOID] = typ(TVOID, T);
+ types[TENUM] = typ(TENUM, T);
+ types[TFUNC] = typ(TFUNC, types[TINT]);
+ types[TIND] = typ(TIND, types[TVOID]);
+
+ for(i=0; i<NHASH; i++)
+ hash[i] = S;
+ for(i=0; itab[i].name; i++) {
+ s = slookup(itab[i].name);
+ s->lexical = itab[i].lexical;
+ if(itab[i].type != 0)
+ s->type = types[itab[i].type];
+ }
+ blockno = 0;
+ autobn = 0;
+ autoffset = 0;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+ symstring = slookup(".string");
+ symstring->class = CSTATIC;
+ symstring->type = t;
+
+ t = typ(TARRAY, types[TCHAR]);
+ t->width = 0;
+
+ nodproto = new(OPROTO, Z, Z);
+ dclstack = D;
+
+ pathname = allocn(pathname, 0, 100);
+ if(mygetwd(pathname, 99) == 0) {
+ pathname = allocn(pathname, 100, 900);
+ if(mygetwd(pathname, 999) == 0)
+ strcpy(pathname, "/???");
+ }
+
+ fmtinstall('O', Oconv);
+ fmtinstall('T', Tconv);
+ fmtinstall('F', FNconv);
+ fmtinstall('L', Lconv);
+ fmtinstall('Q', Qconv);
+ fmtinstall('|', VBconv);
+}
+
+int
+filbuf(void)
+{
+ Io *i;
+
+loop:
+ i = iostack;
+ if(i == I)
+ return EOF;
+ if(i->f < 0)
+ goto pop;
+ fi.c = read(i->f, i->b, BUFSIZ) - 1;
+ if(fi.c < 0) {
+ close(i->f);
+ linehist(0, 0);
+ goto pop;
+ }
+ fi.p = i->b + 1;
+ return i->b[0] & 0xff;
+
+pop:
+ iostack = i->link;
+ i->link = iofree;
+ iofree = i;
+ i = iostack;
+ if(i == I)
+ return EOF;
+ fi.p = i->p;
+ fi.c = i->c;
+ if(--fi.c < 0)
+ goto loop;
+ return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+ int a;
+
+ a = va_arg(fp->args, int);
+ if(a < OXXX || a > OEND)
+ return fmtprint(fp, "***badO %d***", a);
+
+ return fmtstrcpy(fp, onames[a]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+ char str[STRINGSZ], s[STRINGSZ];
+ Hist *h;
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ long idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ long ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ long l, d;
+ int i, n;
+
+ l = va_arg(fp->args, long);
+ n = 0;
+ for(h = hist; h != H; h = h->link) {
+ if(l < h->line)
+ break;
+ if(h->name) {
+ if(h->offset != 0) { /* #line directive, not #pragma */
+ if(n > 0 && n < HISTSZ && h->offset >= 0) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ if(n < HISTSZ) { /* beginning of file */
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+ if(n > HISTSZ)
+ n = HISTSZ;
+ str[0] = 0;
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
+ break;
+ strcat(str, " ");
+ }
+ if(a[i].line)
+ snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+ a[i].line->name, l-a[i].ldel+1,
+ a[i].incl->name, l-a[i].idel+1);
+ else
+ snprint(s, STRINGSZ, "%s:%ld",
+ a[i].incl->name, l-a[i].idel+1);
+ if(strlen(s)+strlen(str) >= STRINGSZ-10)
+ break;
+ strcat(str, s);
+ l = a[i].incl->line - 1; /* now print out start of this file */
+ }
+ if(n == 0)
+ strcat(str, "<eof>");
+ return fmtstrcpy(fp, str);
+}
+
+int
+Tconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], s[STRINGSZ+20];
+ Type *t, *t1;
+ int et;
+ long n;
+
+ str[0] = 0;
+ for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+ et = t->etype;
+ if(str[0])
+ strcat(str, " ");
+ if(t->garb&~GINCOMPLETE) {
+ sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ sprint(s, "%s", tnames[et]);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ if(et == TFUNC && (t1 = t->down)) {
+ sprint(s, "(%T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ while(t1 = t1->down) {
+ sprint(s, ", %T", t1);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, ")");
+ }
+ if(et == TARRAY) {
+ n = t->width;
+ if(t->link && t->link->width)
+ n /= t->link->width;
+ sprint(s, "[%ld]", n);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(t->nbits) {
+ sprint(s, " %d:%d", t->shift, t->nbits);
+ if(strlen(str) + strlen(s) < STRINGSZ)
+ strcat(str, s);
+ }
+ if(typesu[et]) {
+ if(t->tag) {
+ strcat(str, " ");
+ if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+ strcat(str, t->tag->name);
+ } else
+ strcat(str, " {}");
+ break;
+ }
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+FNconv(Fmt *fp)
+{
+ char *str;
+ Node *n;
+
+ n = va_arg(fp->args, Node*);
+ str = "<indirect>";
+ if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+ str = n->sym->name;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Qconv(Fmt *fp)
+{
+ char str[STRINGSZ+20], *s;
+ long b;
+ int i;
+
+ str[0] = 0;
+ for(b = va_arg(fp->args, long); b;) {
+ i = bitno(b);
+ if(str[0])
+ strcat(str, " ");
+ s = qnames[i];
+ if(strlen(str) + strlen(s) >= STRINGSZ)
+ break;
+ strcat(str, s);
+ b &= ~(1L << i);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+VBconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ int i, n, t, pc;
+
+ n = va_arg(fp->args, int);
+ pc = 0; /* BUG: was printcol */
+ i = 0;
+ while(pc < n) {
+ t = (pc+4) & ~3;
+ if(t <= n) {
+ str[i++] = '\t';
+ pc = t;
+ continue;
+ }
+ str[i++] = ' ';
+ pc++;
+ }
+ str[i] = 0;
+
+ return fmtstrcpy(fp, str);
+}
+
+/*
+ * real allocs
+ */
+void*
+alloc(long n)
+{
+ void *p;
+
+ while((uintptr)hunk & MAXALIGN) {
+ hunk++;
+ nhunk--;
+ }
+ while(nhunk < n)
+ gethunk();
+ p = hunk;
+ nhunk -= n;
+ hunk += n;
+ return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+ void *q;
+
+ q = (uchar*)p + on;
+ if(q != hunk || nhunk < n) {
+ while(nhunk < on+n)
+ gethunk();
+ memmove(hunk, p, on);
+ p = hunk;
+ hunk += on;
+ nhunk -= on;
+ }
+ hunk += n;
+ nhunk -= n;
+ return p;
+}
+
+void
+setinclude(char *p)
+{
+ int i;
+ char *e, **np;
+
+ while(*p != 0) {
+ e = strchr(p, ' ');
+ if(e != 0)
+ *e = '\0';
+
+ for(i=0; i < ninclude; i++)
+ if(strcmp(p, include[i]) == 0)
+ break;
+
+ if(i >= ninclude){
+ if(i >= maxinclude){
+ maxinclude += 20;
+ np = alloc(maxinclude * sizeof *np);
+ if(include != nil)
+ memmove(np, include, (maxinclude - 20) * sizeof *np);
+ include = np;
+ }
+ include[ninclude++] = p;
+ }
+
+ if(e == 0)
+ break;
+ p = e+1;
+ }
+}
--- /dev/null
+++ b/sys/src/cmd/zc/list.c
@@ -1,0 +1,236 @@
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+ fmtinstall('A', Aconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+ fmtinstall('B', Bconv);
+ fmtinstall('D', Dconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+ char str[STRINGSZ], ss[STRINGSZ], *s;
+ Bits bits;
+ int i;
+
+ str[0] = 0;
+ bits = va_arg(fp->args, Bits);
+ while(bany(&bits)) {
+ i = bnum(bits);
+ if(str[0])
+ strcat(str, " ");
+ if(var[i].sym == S) {
+ sprint(ss, "$%ld", var[i].offset);
+ s = ss;
+ } else
+ s = var[i].sym->name;
+ if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+ break;
+ strcat(str, s);
+ bits.b[i/32] &= ~(1L << (i%32));
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ a = p->as;
+ if(a == ADATA)
+ sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->as == ATEXT)
+ sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ if(p->reg == NREG)
+ sprint(str, " %A %D,%D", a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+ else
+ sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ sprint(str, "$%N(R%d)", a, a->reg);
+ else
+ sprint(str, "$%N", a);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCCREG:
+ sprint(str, "FCC%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCSREG:
+ sprint(str, "FCSR%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH:
+ sprint(str, "%lld(PC)", a->offset-pc);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%.17e", a->dval);
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+
+ case D_VCONST:
+ sprint(str, "$0x%llux", a->offset);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<NSNAME; i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ case '\r':
+ *p++ = 'r';
+ continue;
+ case '\f':
+ *p++ = 'f';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ if(s == S) {
+ sprint(str, "%lld", a->offset);
+ goto out;
+ }
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%lld", a->offset);
+ break;
+
+ case D_EXTERN:
+ sprint(str, "%s+%lld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ sprint(str, "%s-%lld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ sprint(str, "%s+%lld(FP)", s->name, a->offset);
+ break;
+ }
+out:
+ return fmtstrcpy(fp, str);
+}
--- /dev/null
+++ b/sys/src/cmd/zc/machcap.c
@@ -1,0 +1,77 @@
+#include "gc.h"
+
+int
+machcap(Node *n)
+{
+
+ if(n == Z)
+ return 1; /* test */
+
+ switch(n->op) {
+ case OMUL:
+ case OLMUL:
+ case OASMUL:
+ case OASLMUL:
+ if(typechlv[n->type->etype])
+ return 1;
+ break;
+
+ case OADD:
+ case OAND:
+ case OOR:
+ case OSUB:
+ case OXOR:
+ case OASHL:
+ case OLSHR:
+ case OASHR:
+ if(typechlv[n->left->type->etype])
+ return 1;
+ break;
+
+ case OCAST:
+ return 1;
+
+ case OCOND:
+ case OCOMMA:
+ case OLIST:
+ case OANDAND:
+ case OOROR:
+ case ONOT:
+ return 1;
+
+ case OASADD:
+ case OASSUB:
+ case OASAND:
+ case OASOR:
+ case OASXOR:
+ return 1;
+
+ case OASASHL:
+ case OASASHR:
+ case OASLSHR:
+ return 1;
+
+ case OPOSTINC:
+ case OPOSTDEC:
+ case OPREINC:
+ case OPREDEC:
+ return 1;
+
+ case OEQ:
+ case ONE:
+ case OLE:
+ case OGT:
+ case OLT:
+ case OGE:
+ case OHI:
+ case OHS:
+ case OLO:
+ case OLS:
+ return 1;
+
+ case OCOM:
+ case ONEG:
+ break;
+ }
+ return 0;
+}
--- /dev/null
+++ b/sys/src/cmd/zc/mkenam
@@ -1,0 +1,15 @@
+ed - ../zc/z.out.h <<'!'
+v/^ A/d
+,s/^ A/ "/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char* anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
--- /dev/null
+++ b/sys/src/cmd/zc/mkfile
@@ -1,0 +1,42 @@
+</$objtype/mkfile
+
+TARG=zc
+OFILES=\
+ cgen.$O\
+ enam.$O\
+ list.$O\
+ machcap.$O\
+ mul.$O\
+ peep.$O\
+ pgen.$O\
+ pswt.$O\
+ reg.$O\
+ sgen.$O\
+ swt.$O\
+ txt.$O\
+
+HFILES=\
+ gc.h\
+ z.out.h\
+ ../cc/compat.h\
+ ../cc/cc.h\
+
+LIB=../cc/cc.a$O
+
+BIN=/$objtype/bin
+</sys/src/cmd/mkone
+
+$LIB: ../cc/cc.h
+ cd ../cc
+ mk install
+
+%.$O: ../cc/%.c
+ $CC $CFLAGS ../cc/$stem.c
+
+t:V: $O.out
+ $O.out -S t
+ $LD -o t.out t.$O
+ t.out
+
+enam.c: z.out.h
+ rc mkenam
--- /dev/null
+++ b/sys/src/cmd/zc/mul.c
@@ -1,0 +1,608 @@
+#include "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ * lsl $(A-'a'),r0,r1
+ * [+][0-7]
+ * add r0,r1,r2
+ * [-][0-7]
+ * sub r0,r1,r2
+ */
+
+static int multabp;
+static long mulval;
+static char* mulcp;
+static long valmax;
+static int shmax;
+
+static int docode(char *hp, char *cp, int r0, int r1);
+static int gen1(int len);
+static int gen2(int len, long r1);
+static int gen3(int len, long r0, long r1, int flag);
+enum
+{
+ SR1 = 1<<0, /* r1 has been shifted */
+ SR0 = 1<<1, /* r0 has been shifted */
+ UR1 = 1<<2, /* r1 has not been used */
+ UR0 = 1<<3, /* r0 has not been used */
+};
+
+Multab*
+mulcon0(long v)
+{
+ int a1, a2, g;
+ Multab *m, *m1;
+ char hint[10];
+
+ if(v < 0)
+ v = -v;
+
+ /*
+ * look in cache
+ */
+ m = multab;
+ for(g=0; g<nelem(multab); g++) {
+ if(m->val == v) {
+ if(m->code[0] == 0)
+ return 0;
+ return m;
+ }
+ m++;
+ }
+
+ /*
+ * select a spot in cache to overwrite
+ */
+ multabp++;
+ if(multabp < 0 || multabp >= nelem(multab))
+ multabp = 0;
+ m = multab+multabp;
+ m->val = v;
+ mulval = v;
+
+ /*
+ * look in execption hint table
+ */
+ a1 = 0;
+ a2 = hintabsize;
+ for(;;) {
+ if(a1 >= a2)
+ goto no;
+ g = (a2 + a1)/2;
+ if(v < hintab[g].val) {
+ a2 = g;
+ continue;
+ }
+ if(v > hintab[g].val) {
+ a1 = g+1;
+ continue;
+ }
+ break;
+ }
+
+ if(docode(hintab[g].hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ m->code[0] = 0;
+ return 0;
+
+no:
+ /*
+ * try to search
+ */
+ hint[0] = 0;
+ for(g=1; g<=6; g++) {
+ if(g >= 6 && v >= 65535)
+ break;
+ mulcp = hint+g;
+ *mulcp = 0;
+ if(gen1(g)) {
+ if(docode(hint, m->code, 1, 0))
+ return m;
+ print("multiply table failure %ld\n", v);
+ break;
+ }
+ }
+
+ /*
+ * try a recur followed by a shift
+ */
+ g = 0;
+ while(!(v & 1)) {
+ g++;
+ v >>= 1;
+ }
+ if(g) {
+ m1 = mulcon0(v);
+ if(m1) {
+ strcpy(m->code, m1->code);
+ sprint(strchr(m->code, 0), "%c0", g+'a');
+ return m;
+ }
+ }
+ m->code[0] = 0;
+ return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+ int c, i;
+
+ c = *hp++;
+ *cp = c;
+ cp += 2;
+ switch(c) {
+ default:
+ c -= 'a';
+ if(c < 1 || c >= 30)
+ break;
+ for(i=0; i<4; i++) {
+ switch(i) {
+ case 0:
+ if(docode(hp, cp, r0<<c, r1))
+ goto out;
+ break;
+ case 1:
+ if(docode(hp, cp, r1<<c, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r0, r0<<c))
+ goto out;
+ break;
+ case 3:
+ if(docode(hp, cp, r0, r1<<c))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '+':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0+r1, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0+r1))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case '-':
+ for(i=0; i<8; i++) {
+ cp[-1] = i+'0';
+ switch(i) {
+ case 1:
+ if(docode(hp, cp, r0-r1, r1))
+ goto out;
+ break;
+ case 2:
+ if(docode(hp, cp, r1-r0, r1))
+ goto out;
+ break;
+ case 5:
+ if(docode(hp, cp, r0, r0-r1))
+ goto out;
+ break;
+ case 6:
+ if(docode(hp, cp, r0, r1-r0))
+ goto out;
+ break;
+ }
+ }
+ break;
+
+ case 0:
+ if(r0 == mulval)
+ return 1;
+ }
+ return 0;
+
+out:
+ cp[-1] = i+'0';
+ return 1;
+}
+
+static int
+gen1(int len)
+{
+ int i;
+
+ for(shmax=1; shmax<30; shmax++) {
+ valmax = 1<<shmax;
+ if(valmax >= mulval)
+ break;
+ }
+ if(mulval == 1)
+ return 1;
+
+ len--;
+ for(i=1; i<=shmax; i++)
+ if(gen2(len, 1<<i)) {
+ *--mulcp = 'a'+i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gen2(int len, long r1)
+{
+ int i;
+
+ if(len <= 0) {
+ if(r1 == mulval)
+ return 1;
+ return 0;
+ }
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(gen3(len, r1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, r1-1, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+ if(gen3(len, 1, r1+1, UR1)) {
+ i = '+';
+ goto out;
+ }
+ if(gen3(len, 1, r1-1, UR1)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ if(mulval == r1+1) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-1) {
+ i = '-';
+ goto out;
+ }
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+static int
+gen3(int len, long r0, long r1, int flag)
+{
+ int i, f1, f2;
+ long x;
+
+ if(r0 <= 0 ||
+ r0 >= r1 ||
+ r1 > valmax)
+ return 0;
+
+ len--;
+ if(len == 0)
+ goto calcr0;
+
+ if(!(flag & UR1)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & UR0)) {
+ f1 = UR1|SR1;
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r1, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR1)) {
+ f1 = UR1|SR1|(flag&UR0);
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x > valmax)
+ break;
+ if(gen3(len, r0, x, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ if(!(flag & SR0)) {
+ f1 = UR0|SR0|(flag&(SR1|UR1));
+
+ f2 = UR1|SR1;
+ if(flag & UR1)
+ f2 |= UR0;
+ if(flag & SR1)
+ f2 |= SR0;
+
+ for(i=1; i<=shmax; i++) {
+ x = r0<<i;
+ if(x > valmax)
+ break;
+ if(x > r1) {
+ if(gen3(len, r1, x, f2)) {
+ i += 'a';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r1, f1)) {
+ i += 'a';
+ goto out;
+ }
+ }
+ }
+
+ x = r1+r0;
+ if(gen3(len, r0, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ if(gen3(len, r1, x, UR1)) {
+ i = '+';
+ goto out;
+ }
+
+ x = r1-r0;
+ if(gen3(len, x, r1, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ if(x > r0) {
+ if(gen3(len, r0, x, UR1)) {
+ i = '-';
+ goto out;
+ }
+ } else
+ if(gen3(len, x, r0, UR0)) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+calcr0:
+ f1 = flag & (UR0|UR1);
+ if(f1 == UR1) {
+ for(i=1; i<=shmax; i++) {
+ x = r1<<i;
+ if(x >= mulval) {
+ if(x == mulval) {
+ i += 'a';
+ goto out;
+ }
+ break;
+ }
+ }
+ }
+
+ if(mulval == r1+r0) {
+ i = '+';
+ goto out;
+ }
+ if(mulval == r1-r0) {
+ i = '-';
+ goto out;
+ }
+
+ return 0;
+
+out:
+ *--mulcp = i;
+ return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ * all numbers
+ * <5000:
+ * ÷ by 5
+ * <10000:
+ * ÷ by 50
+ * <65536:
+ * ÷ by 250
+ */
+Hintab hintab[] =
+{
+ 683, "b++d+e+",
+ 687, "b+e++e-",
+ 691, "b++d+e+",
+ 731, "b++d+e+",
+ 811, "b++d+i+",
+ 821, "b++e+e+",
+ 843, "b+d++e+",
+ 851, "b+f-+e-",
+ 853, "b++e+e+",
+ 877, "c++++g-",
+ 933, "b+c++g-",
+ 981, "c-+e-d+",
+ 1375, "b+c+b+h-",
+ 1675, "d+b++h+",
+ 2425, "c++f-e+",
+ 2675, "c+d++f-",
+ 2750, "b+d-b+h-",
+ 2775, "c-+g-e-",
+ 3125, "b++e+g+",
+ 3275, "b+c+g+e+",
+ 3350, "c++++i+",
+ 3475, "c-+e-f-",
+ 3525, "c-+d+g-",
+ 3625, "c-+e-j+",
+ 3675, "b+d+d+e+",
+ 3725, "b+d-+h+",
+ 3925, "b+d+f-d-",
+ 4275, "b+g++e+",
+ 4325, "b+h-+d+",
+ 4425, "b+b+g-j-",
+ 4525, "b+d-d+f+",
+ 4675, "c++d-g+",
+ 4775, "b+d+b+g-",
+ 4825, "c+c-+i-",
+ 4850, "c++++i-",
+ 4925, "b++e-g-",
+ 4975, "c+f++e-",
+ 5500, "b+g-c+d+",
+ 6700, "d+b++i+",
+ 9700, "d++++j-",
+ 11000, "b+f-c-h-",
+ 11750, "b+d+g+j-",
+ 12500, "b+c+e-k+",
+ 13250, "b+d+e-f+",
+ 13750, "b+h-c-d+",
+ 14250, "b+g-c+e-",
+ 14500, "c+f+j-d-",
+ 14750, "d-g--f+",
+ 16750, "b+e-d-n+",
+ 17750, "c+h-b+e+",
+ 18250, "d+b+h-d+",
+ 18750, "b+g-++f+",
+ 19250, "b+e+b+h+",
+ 19750, "b++h--f-",
+ 20250, "b+e-l-c+",
+ 20750, "c++bi+e-",
+ 21250, "b+i+l+c+",
+ 22000, "b+e+d-g-",
+ 22250, "b+d-h+k-",
+ 22750, "b+d-e-g+",
+ 23250, "b+c+h+e-",
+ 23500, "b+g-c-g-",
+ 23750, "b+g-b+h-",
+ 24250, "c++g+m-",
+ 24750, "b+e+e+j-",
+ 25000, "b++dh+g+",
+ 25250, "b+e+d-g-",
+ 25750, "b+e+b+j+",
+ 26250, "b+h+c+e+",
+ 26500, "b+h+c+g+",
+ 26750, "b+d+e+g-",
+ 27250, "b+e+e+f+",
+ 27500, "c-i-c-d+",
+ 27750, "b+bd++j+",
+ 28250, "d-d-++i-",
+ 28500, "c+c-h-e-",
+ 29000, "b+g-d-f+",
+ 29500, "c+h+++e-",
+ 29750, "b+g+f-c+",
+ 30250, "b+f-g-c+",
+ 33500, "c-f-d-n+",
+ 33750, "b+d-b+j-",
+ 34250, "c+e+++i+",
+ 35250, "e+b+d+k+",
+ 35500, "c+e+d-g-",
+ 35750, "c+i-++e+",
+ 36250, "b+bh-d+e+",
+ 36500, "c+c-h-e-",
+ 36750, "d+e--i+",
+ 37250, "b+g+g+b+",
+ 37500, "b+h-b+f+",
+ 37750, "c+be++j-",
+ 38500, "b+e+b+i+",
+ 38750, "d+i-b+d+",
+ 39250, "b+g-l-+d+",
+ 39500, "b+g-c+g-",
+ 39750, "b+bh-c+f-",
+ 40250, "b+bf+d+g-",
+ 40500, "b+g-c+g+",
+ 40750, "c+b+i-e+",
+ 41250, "d++bf+h+",
+ 41500, "b+j+c+d-",
+ 41750, "c+f+b+h-",
+ 42500, "c+h++g+",
+ 42750, "b+g+d-f-",
+ 43250, "b+l-e+d-",
+ 43750, "c+bd+h+f-",
+ 44000, "b+f+g-d-",
+ 44250, "b+d-g--f+",
+ 44500, "c+e+c+h+",
+ 44750, "b+e+d-h-",
+ 45250, "b++g+j-g+",
+ 45500, "c+d+e-g+",
+ 45750, "b+d-h-e-",
+ 46250, "c+bd++j+",
+ 46500, "b+d-c-j-",
+ 46750, "e-e-b+g-",
+ 47000, "b+c+d-j-",
+ 47250, "b+e+e-g-",
+ 47500, "b+g-c-h-",
+ 47750, "b+f-c+h-",
+ 48250, "d--h+n-",
+ 48500, "b+c-g+m-",
+ 48750, "b+e+e-g+",
+ 49500, "c-f+e+j-",
+ 49750, "c+c+g++f-",
+ 50000, "b+e+e+k+",
+ 50250, "b++i++g+",
+ 50500, "c+g+f-i+",
+ 50750, "b+e+d+k-",
+ 51500, "b+i+c-f+",
+ 51750, "b+bd+g-e-",
+ 52250, "b+d+g-j+",
+ 52500, "c+c+f+g+",
+ 52750, "b+c+e+i+",
+ 53000, "b+i+c+g+",
+ 53500, "c+g+g-n+",
+ 53750, "b+j+d-c+",
+ 54250, "b+d-g-j-",
+ 54500, "c-f+e+f+",
+ 54750, "b+f-+c+g+",
+ 55000, "b+g-d-g-",
+ 55250, "b+e+e+g+",
+ 55500, "b+cd++j+",
+ 55750, "b+bh-d-f-",
+ 56250, "c+d-b+j-",
+ 56500, "c+d+c+i+",
+ 56750, "b+e+d++h-",
+ 57000, "b+d+g-f+",
+ 57250, "b+f-m+d-",
+ 57750, "b+i+c+e-",
+ 58000, "b+e+d+h+",
+ 58250, "c+b+g+g+",
+ 58750, "d-e-j--e+",
+ 59000, "d-i-+e+",
+ 59250, "e--h-m+",
+ 59500, "c+c-h+f-",
+ 59750, "b+bh-e+i-",
+ 60250, "b+bh-e-e-",
+ 60500, "c+c-g-g-",
+ 60750, "b+e-l-e-",
+ 61250, "b+g-g-c+",
+ 61750, "b+g-c+g+",
+ 62250, "f--+c-i-",
+ 62750, "e+f--+g+",
+ 64750, "b+f+d+p-",
+};
+int hintabsize = nelem(hintab);
--- /dev/null
+++ b/sys/src/cmd/zc/peep.c
@@ -1,0 +1,739 @@
+#include "gc.h"
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(/*p->as == AMOVW ||*/ p->as == AMOVV || p->as == AMOVF || p->as == AMOVD)
+ if(regtyp(&p->to)) {
+ if(regtyp(&p->from))
+ if(p->from.type == p->to.type) {
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ if(regzer(&p->from))
+ if(p->to.type == D_REG) {
+ p->from.type = D_REG;
+ p->from.reg = 0;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ } else
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ }
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVW:
+ case AMOVWU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regzer(Adr *a)
+{
+
+ if(a->type == D_CONST)
+ if(a->sym == S)
+ if(a->offset == 0)
+ return 1;
+ if(a->type == D_REG)
+ if(a->reg == 0)
+ return 1;
+ return 0;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG) {
+ if(a->reg != 0)
+ return 1;
+ return 0;
+ }
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case AJAL:
+ return 0;
+
+ case ASGT:
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDV:
+ case AADDVU:
+ case ASUBV:
+ case ASUBVU:
+ case ASLLV:
+ case ASRLV:
+ case ASRAV:
+ case AMULV:
+ case AMULVU:
+ case ADIVV:
+ case ADIVVU:
+
+ case AADDD:
+ case AADDF:
+ case ASUBD:
+ case ASUBF:
+ case AMULD:
+ case AMULF:
+ case ADIVD:
+ case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ case AMOVV:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (???)");
+ return 2;
+
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVV:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVFD:
+ case AMOVDF:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFW:
+ case AMOVWF:
+ case AMOVDV:
+ case AMOVVD:
+ case AMOVFV:
+ case AMOVVF:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ASGT: /* read, read, write */
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case ANOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDV:
+ case AADDVU:
+ case ASUBV:
+ case ASUBVU:
+ case ASLLV:
+ case ASRLV:
+ case ASRAV:
+ case AMULV:
+ case AMULVU:
+ case ADIVV:
+ case ADIVVU:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABGTZ:
+ case ABGEZ:
+ case ABLTZ:
+ case ABLEZ:
+
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+ case ABFPF:
+ case ABFPT:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AJMP: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case AJAL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(REGARG && v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+ case ABEQ:
+ case ABNE:
+ case ABGTZ:
+ case ABGEZ:
+ case ABLTZ:
+ case ABLEZ:
+
+ case ASGT:
+ case ASGTU:
+
+ case AADD:
+ case AADDU:
+ case ASUB:
+ case ASUBU:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AOR:
+ case AAND:
+ case AXOR:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case ADIVU:
+
+ case AADDV:
+ case AADDVU:
+ case ASUBV:
+ case ASUBVU:
+ case ASLLV:
+ case ASRLV:
+ case ASRAV:
+ case AMULV:
+ case AMULVU:
+ case ADIVV:
+ case ADIVVU:
+ return D_REG;
+
+ case ACMPEQD:
+ case ACMPEQF:
+ case ACMPGED:
+ case ACMPGEF:
+ case ACMPGTD:
+ case ACMPGTF:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v))
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG)
+ if(a->type == D_OREG)
+ if(v->reg == a->reg)
+ return 1;
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v))
+ if(p->from.type == v->type || p->to.type == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v))
+ a->reg = s->reg;
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
--- /dev/null
+++ b/sys/src/cmd/zc/reg
@@ -1,0 +1,213 @@
+cgen.c:1126: p->as = ABGTZ;
+lex.c:1290: a = va_arg(fp->args, int);
+lex.c:1312: l = va_arg(fp->args, long);
+lex.c:1345: if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
+lex.c:1375: for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+lex.c:1431: n = va_arg(fp->args, Node*);
+lex.c:1446: for(b = va_arg(fp->args, long); b;) {
+lex.c:1465: n = va_arg(fp->args, int);
+list.c:23: bits = va_arg(fp->args, Bits);
+list.c:48: p = va_arg(fp->args, Prog*);
+list.c:49: a = p->as;
+list.c:51: sprint(str, " %A %D/%d,%D", a, &p->from, p->reg, &p->to);
+list.c:53: if(p->as == ATEXT)
+list.c:54: sprint(str, " %A %D,%d,%D", a, &p->from, p->reg, &p->to);
+list.c:56: if(p->reg == NREG)
+list.c:57: sprint(str, " %A %D,%D", a, &p->from, &p->to);
+list.c:59: if(p->from.type != D_FREG)
+list.c:60: sprint(str, " %A %D,R%d,%D", a, &p->from, p->reg, &p->to);
+list.c:62: sprint(str, " %A %D,F%d,%D", a, &p->from, p->reg, &p->to);
+list.c:72: a = va_arg(fp->args, int);
+list.c:85: a = va_arg(fp->args, Adr*);
+list.c:155: a = va_arg(fp->args, char*);
+list.c:203: a = va_arg(fp->args, Adr*);
+mul.c:606: 64750, "b+f+d+p-",
+peep.c:19: switch(p->as) {
+peep.c:38: p = p->link;
+peep.c:46: if(/*p->as == AMOVW ||*/ p->as == AMOVV || p->as == AMOVF || p->as == AMOVD)
+peep.c:47: if(regtyp(&p->to)) {
+peep.c:48: if(regtyp(&p->from))
+peep.c:49: if(p->from.type == p->to.type) {
+peep.c:59: if(regzer(&p->from))
+peep.c:60: if(p->to.type == D_REG) {
+peep.c:61: p->from.type = D_REG;
+peep.c:62: p->from.reg = 0;
+peep.c:81: switch(p->as) {
+peep.c:90: if(p->to.type != D_REG)
+peep.c:98: if(p1->as != p->as)
+peep.c:100: if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+peep.c:102: if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+peep.c:114: p->as = ANOP;
+peep.c:115: p->from = zprog.from;
+peep.c:116: p->to = zprog.to;
+peep.c:117: p->reg = zprog.reg; /**/
+peep.c:203: v1 = &p->from;
+peep.c:206: v2 = &p->to;
+peep.c:213: switch(p->as) {
+peep.c:255: if(p->to.type == v1->type)
+peep.c:256: if(p->to.reg == v1->reg) {
+peep.c:257: if(p->reg == NREG)
+peep.c:258: p->reg = p->to.reg;
+peep.c:267: if(p->to.type == v1->type)
+peep.c:268: if(p->to.reg == v1->reg)
+peep.c:272: if(copyau(&p->from, v2) ||
+peep.c:274: copyau(&p->to, v2))
+peep.c:276: if(copysub(&p->from, v1, v2, 0) ||
+peep.c:278: copysub(&p->to, v1, v2, 0))
+peep.c:284: copysub(&p->to, v1, v2, 1);
+peep.c:287: if(p->from.type == v2->type)
+peep.c:293: copysub(&p->from, v1, v2, 1);
+peep.c:295: copysub(&p->to, v1, v2, 1);
+peep.c:327: v1 = &p->from;
+peep.c:328: v2 = &p->to;
+peep.c:424: switch(p->as) {
+peep.c:452: if(copysub(&p->from, v, s, 1))
+peep.c:454: if(!copyas(&p->to, v))
+peep.c:455: if(copysub(&p->to, v, s, 1))
+peep.c:459: if(copyas(&p->to, v)) {
+peep.c:460: if(copyau(&p->from, v))
+peep.c:464: if(copyau(&p->from, v))
+peep.c:466: if(copyau(&p->to, v))
+peep.c:510: if(copysub(&p->from, v, s, 1))
+peep.c:514: if(!copyas(&p->to, v))
+peep.c:515: if(copysub(&p->to, v, s, 1))
+peep.c:519: if(copyas(&p->to, v)) {
+peep.c:520: if(p->reg == NREG)
+peep.c:521: p->reg = p->to.reg;
+peep.c:522: if(copyau(&p->from, v))
+peep.c:528: if(copyau(&p->from, v))
+peep.c:532: if(copyau(&p->to, v))
+peep.c:552: if(copysub(&p->from, v, s, 1))
+peep.c:556: if(copyau(&p->from, v))
+peep.c:564: if(copysub(&p->to, v, s, 1))
+peep.c:568: if(copyau(&p->to, v))
+peep.c:592: if(copysub(&p->to, v, s, 1))
+peep.c:596: if(copyau(&p->to, v))
+peep.c:612: switch(p->as) {
+peep.c:708: if(p->from.type == v->type || p->to.type == v->type)
+peep.c:709: if(p->reg == v->reg) {
+reg.c:71: lp->m = val;
+reg.c:72: lp->c = 0;
+reg.c:73: lp->p = R;
+reg.c:78: for(; p != P; p = p->link) {
+reg.c:79: switch(p->as) {
+reg.c:102: lp->c--;
+reg.c:103: if(lp->c <= 0) {
+reg.c:104: lp->c = lp->m;
+reg.c:105: if(lp->p != R)
+reg.c:106: lp->p->log5 = r;
+reg.c:107: lp->p = r;
+reg.c:127: bit = mkvar(&p->from, p->as==AMOVW);
+reg.c:134: bit = mkvar(&p->to, 0);
+reg.c:136: switch(p->as) {
+reg.c:138: diag(Z, "reg: unknown asop: %A", p->as);
+reg.c:178: if(p->to.type == D_BRANCH) {
+reg.c:179: val = p->to.offset - initpc;
+reg.c:192: nearln = p->lineno;
+reg.c:197: nearln = p->lineno;
+reg.c:208: print("\n%L %D\n", p->lineno, &p->from);
+reg.c:332: rgp->enter = r;
+reg.c:333: rgp->varno = i;
+reg.c:345: rgp->cost = change;
+reg.c:364: bit = blsh(rgp->varno);
+reg.c:365: vreg = paint2(rgp->enter, rgp->varno);
+reg.c:368: if(rgp->regno >= NREG)
+reg.c:370: rgp->enter->prog->lineno,
+reg.c:371: rgp->cost,
+reg.c:372: rgp->regno-NREG,
+reg.c:376: rgp->enter->prog->lineno,
+reg.c:377: rgp->cost,
+reg.c:378: rgp->regno,
+reg.c:381: if(rgp->regno != 0)
+reg.c:382: paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+reg.c:387: * peep-hole on basic block
+reg.c:404: for(; p != p1; p = p->link) {
+reg.c:405: switch(p->as) {
+reg.c:431: if(p->to.type == D_BRANCH)
+reg.c:432: p->to.offset = r->s2->pc;
+reg.c:441: for(p = firstr->prog; p != P; p = p->link){
+reg.c:442: while(p->link && p->link->as == ANOP)
+reg.c:443: p->link = p->link->link;
+reg.c:493: p1->link = p->link;
+reg.c:494: p->link = p1;
+reg.c:495: p1->lineno = p->lineno;
+reg.c:1052: addreg(&p->from, rn);
+reg.c:1059: addreg(&p->to, rn);
+sgen.c:9: p->to.type = D_REG;
+sgen.c:10: p->to.reg = REGRET;
+sgen.c:14: p->to.type = D_FREG;
+sgen.c:15: p->to.reg = FREGRET;
+swt.c:136: p->from.offset += nstring - NSNAME;
+swt.c:137: p->reg = NSNAME;
+swt.c:138: p->to.type = D_SCONST;
+swt.c:139: memmove(p->to.sval, string, NSNAME);
+swt.c:247: p->from.offset += o;
+swt.c:248: p->reg = 4;
+swt.c:253: p->from.offset += o + 4;
+swt.c:254: p->reg = 4;
+swt.c:258: p->from.offset += o;
+swt.c:259: p->reg = w;
+swt.c:260: if(p->to.type == D_OREG)
+swt.c:261: p->to.type = D_CONST;
+swt.c:274: bf[0] = p->as;
+swt.c:275: bf[1] = p->reg;
+swt.c:276: bf[2] = p->lineno;
+swt.c:277: bf[3] = p->lineno>>8;
+swt.c:278: bf[4] = p->lineno>>16;
+swt.c:279: bf[5] = p->lineno>>24;
+swt.c:280: bp = zaddr(bf+6, &p->from, sf);
+swt.c:281: bp = zaddr(bp, &p->to, st);
+swt.c:282: Bwrite(b, bf, bp-bf);
+swt.c:294: for(p = firstp; p != P; p = p->link)
+swt.c:295: if(p->as != ADATA && p->as != AGLOBL)
+swt.c:297: for(p = firstp; p != P; p = p->link) {
+swt.c:299: if(p->as != ADATA && p->as != AGLOBL)
+swt.c:309: for(p = firstp; p != P; p = p->link) {
+swt.c:312: s = p->from.sym;
+swt.c:317: t = p->from.name;
+swt.c:332: s = p->to.sym;
+swt.c:337: t = p->to.name;
+txt.c:123: p->as = AEND;
+txt.c:133: p->lineno = nearln;
+txt.c:140: lastp->link = p;
+txt.c:435: p->reg = NREG;
+txt.c:437: p->reg = a.reg;
+txt.c:726: p->as = ATRUNCFW;
+txt.c:736: p->as = ATRUNCFV;
+txt.c:753: p->reg = FREGZERO;
+txt.c:768: p->reg = FREGZERO;
+txt.c:942: p->as = a;
+txt.c:944: naddr(f, &p->from);
+txt.c:946: naddr(t, &p->to);
+txt.c:1112: naddr(f1, &p->from);
+txt.c:1117: p->as = a;
+txt.c:1121: p->as = AMOVW;
+txt.c:1123: p->as = AMOVV;
+txt.c:1127: p->from.type = a;
+txt.c:1128: naddr(t, &p->to);
+txt.c:1166: p->as = a;
+txt.c:1167: naddr(f1, &p->from);
+txt.c:1175: p->as = a;
+txt.c:1209: naddr(f1, &p->from);
+txt.c:1212: naddr(f2, &p->from);
+txt.c:1215: naddr(®node, &p->to);
+txt.c:1216: p->to.reg = tmpreg();
+txt.c:1220: p->as = a;
+txt.c:1225: naddr(®node, &p->from);
+txt.c:1226: p->from.reg = tmpreg();
+txt.c:1230: p->as = a;
+txt.c:1238: p->as = a;
+txt.c:1240: naddr(f1, &p->from);
+txt.c:1243: p->reg = ta.reg;
+txt.c:1245: p->reg = REGZERO;
+txt.c:1248: naddr(t, &p->to);
+txt.c:1288: p->as = a;
+txt.c:1295: op->to.offset = pc;
+txt.c:1296: op->to.type = D_BRANCH;
+txt.c:1304: p->as = a;
+txt.c:1305: p->from.type = D_OREG;
+txt.c:1306: p->from.sym = s;
+txt.c:1308: p->reg = (profileflg ? 0 : NOPROF);
+txt.c:1309: p->from.name = D_EXTERN;
+txt.c:1311: p->from.name = D_STATIC;
+txt.c:1312: naddr(n, &p->to);
--- /dev/null
+++ b/sys/src/cmd/zc/reg.c
@@ -1,0 +1,1150 @@
+#include "gc.h"
+
+void addsplits(void);
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = alloc(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+ Reg *r, *r1, *r2;
+ Prog *p1;
+ int i, z;
+ long initpc, val, npc;
+ ulong vreg;
+ Bits bit;
+ struct
+ {
+ long m;
+ long c;
+ Reg* p;
+ } log5[6], *lp;
+
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ }
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ val = 5L * 5L * 5L * 5L * 5L;
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->m = val;
+ lp->c = 0;
+ lp->p = R;
+ val /= 5L;
+ lp++;
+ }
+ val = 0;
+ for(; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ r->pc = val;
+ val++;
+
+ lp = log5;
+ for(i=0; i<5; i++) {
+ lp->c--;
+ if(lp->c <= 0) {
+ lp->c = lp->m;
+ if(lp->p != R)
+ lp->p->log5 = r;
+ lp->p = r;
+ (lp+1)->c = 0;
+ break;
+ }
+ lp++;
+ }
+
+ r1 = r->p1;
+ if(r1 != R)
+ switch(r1->prog->as) {
+ case ARET:
+ case AJMP:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(&p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(&p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ diag(Z, "reg: unknown asop: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVV:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case AJAL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+ }
+ if(firstr == R)
+ return;
+ initpc = pc - val;
+ npc = val;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ val = p->to.offset - initpc;
+ r1 = firstr;
+ while(r1 != R) {
+ r2 = r1->log5;
+ if(r2 != R && val >= r2->pc) {
+ r1 = r2;
+ continue;
+ }
+ if(r1->pc == val)
+ break;
+ r1 = r1->link;
+ }
+ if(r1 == R) {
+ nearln = p->lineno;
+ diag(Z, "ref not found\n%P", p);
+ continue;
+ }
+ if(r1 == r) {
+ nearln = p->lineno;
+ diag(Z, "ref to self\n%P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, npc);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] && debug['v']) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%ld:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%B", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%B", r->use2);
+ if(bany(&r->set))
+ print(" st=%B", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%B", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%B", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%B", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%B", r->calbehind);
+ if(bany(&r->regdiff))
+ print(" rd=%B", r->regdiff);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "used and not set: %B", bit);
+ if(debug['R'] && !debug['w'])
+ print("used and not set: %B\n", bit);
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit)) {
+ nearln = r->prog->lineno;
+ warn(Z, "set and not used: %B", bit);
+ if(debug['R'])
+ print("set and not used: %B\n", bit);
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] && debug['v'])
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %B\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ warn(Z, "too many regions");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %B\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P'])
+ peep();
+
+ /*
+ * pass 8
+ * recalculate pc
+ */
+ val = initpc;
+ for(r = firstr; r != R; r = r1) {
+ r->pc = val;
+ p = r->prog;
+ p1 = P;
+ r1 = r->link;
+ if(r1 != R)
+ p1 = r1->prog;
+ for(; p != p1; p = p->link) {
+ switch(p->as) {
+ default:
+ val++;
+ break;
+
+ case ANOP:
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ break;
+ }
+ }
+ }
+ pc = val;
+
+ /*
+ * fix up branches
+ */
+ if(debug['R'])
+ if(bany(&addrs))
+ print("addrs: %B\n", addrs);
+
+ r1 = 0; /* set */
+ for(r = firstr; r != R; r = r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH)
+ p->to.offset = r->s2->pc;
+ r1 = r;
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstr->prog; p != P; p = p->link){
+ while(p->link && p->link->as == ANOP)
+ p->link = p->link->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == AJAL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = alloc(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ p1->as = AMOVW;
+ if(v->etype == TCHAR || v->etype == TUCHAR)
+ p1->as = AMOVB;
+ if(v->etype == TSHORT || v->etype == TUSHORT)
+ p1->as = AMOVH;
+ if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
+ p1->as = AMOVV;
+ if(v->etype == TFLOAT)
+ p1->as = AMOVF;
+ if(v->etype == TDOUBLE)
+ p1->as = AMOVD;
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUCHAR)
+ p1->as = AMOVBU;
+ if(v->etype == TUSHORT)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z;
+ long o;
+ Bits bit;
+ Sym *s;
+
+ t = a->type;
+ if(t == D_REG && a->reg != NREG)
+ regbits |= RtoB(a->reg);
+ if(t == D_FREG && a->reg != NREG)
+ regbits |= FtoB(a->reg);
+ s = a->sym;
+ o = a->offset;
+ et = a->etype;
+ if(s == S) {
+ if(t != D_CONST || !docon || a->reg != NREG)
+ goto none;
+ et = TLONG;
+ }
+ if(t == D_CONST) {
+ if(s == S && sval(o))
+ goto none;
+ }
+
+ n = a->name;
+ v = var;
+ for(i=0; i<nvar; i++) {
+ if(s == v->sym)
+ if(n == v->name)
+ if(o == v->offset)
+ goto out;
+ v++;
+ }
+ if(s)
+ if(s->name[0] == '.')
+ goto none;
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ warn(Z, "variable not optimized: %s", s->name);
+ goto none;
+ }
+ i = nvar;
+ nvar++;
+ v = &var[i];
+ v->sym = s;
+ v->offset = o;
+ v->etype = et;
+ v->name = n;
+ if(debug['R'])
+ print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ if(v->etype != et || (!typechlpfd[et] && !typev[et])) /* funny punning */
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ if(t == D_CONST) {
+ if(s == S) {
+ for(z=0; z<BITS; z++)
+ consts.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(et != TARRAY)
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+ return bit;
+ }
+ if(t == D_OREG)
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case AJAL:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z];
+ ref.b[z] = 0;
+ }
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+ long t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal(Z, "bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+ long src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+ Reg *r1;
+ long i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = alloc(nr * sizeof(Reg*));
+ idom = alloc(nr * sizeof(long));
+ maxnr = nr;
+ }
+
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal(Z, "too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+ break;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TARRAY:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TDOUBLE:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tld %B $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu1 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tu2 %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] && debug['v'])
+ print("%ld%P\tst %B $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ ulong bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ ulong bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R3
+ * 1 R4
+ * ... ...
+ * 19 R22
+ * 20 R23
+ */
+long
+RtoB(int r)
+{
+
+ if(r >= REGMIN || r <= REGMAX)
+ return 1L << (r-REGMIN);
+ return 0;
+}
+
+BtoR(long b)
+{
+ b &= (1 << (1+REGMAX-REGMIN))-1;
+ b &= ~(1 << (REGTMP-REGMIN));
+ if(b == 0)
+ return 0;
+ return bitno(b) + REGMIN;
+}
+
+/*
+ * bit reg
+ * 22 F4
+ * 23 F6
+ * ... ...
+ * 31 F22
+ */
+long
+FtoB(int f)
+{
+ if(f < FREGMIN || f >= FREGEXT)
+ return 0;
+ return 1L << (f - FREGMIN + 22);
+}
+
+int
+BtoF(long b)
+{
+ b &= ((1 << (FREGEXT - FREGMIN))-1) << 22;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 22 + FREGMIN;
+}
--- /dev/null
+++ b/sys/src/cmd/zc/sgen.c
@@ -1,0 +1,223 @@
+#include "gc.h"
+
+void
+noretval(int n)
+{
+
+ if(n & 1) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_REG;
+ p->to.reg = REGRET;
+ }
+ if(n & 2) {
+ gins(ANOP, Z, Z);
+ p->to.type = D_FREG;
+ p->to.reg = FREGRET;
+ }
+}
+
+/*
+ * calculate addressability as follows
+ * CONST ==> 20 $value
+ * NAME ==> 10 name
+ * REGISTER ==> 11 register
+ * INDREG ==> 12 *[(reg)+offset]
+ * &10 ==> 2 $name
+ * ADD(2, 20) ==> 2 $name+offset
+ * ADD(3, 20) ==> 3 $(reg)+offset
+ * &12 ==> 3 $(reg)+offset
+ * *11 ==> 11 ??
+ * *2 ==> 10 name
+ * *3 ==> 12 *(reg)+offset
+ * calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ n->addable = 0;
+ n->complex = 0;
+ switch(n->op) {
+ case OCONST:
+ n->addable = 20;
+ return;
+
+ case OREGISTER:
+ n->addable = 11;
+ return;
+
+ case OINDREG:
+ n->addable = 12;
+ return;
+
+ case ONAME:
+ n->addable = 10;
+ return;
+
+ case OADDR:
+ xcom(l);
+ if(l->addable == 10)
+ n->addable = 2;
+ if(l->addable == 12)
+ n->addable = 3;
+ break;
+
+ case OIND:
+ xcom(l);
+ if(l->addable == 11)
+ n->addable = 12;
+ if(l->addable == 3)
+ n->addable = 12;
+ if(l->addable == 2)
+ n->addable = 10;
+ break;
+
+ case OADD:
+ xcom(l);
+ xcom(r);
+ if(l->addable == 20) {
+ if(r->addable == 2)
+ n->addable = 2;
+ if(r->addable == 3)
+ n->addable = 3;
+ }
+ if(r->addable == 20) {
+ if(l->addable == 2)
+ n->addable = 2;
+ if(l->addable == 3)
+ n->addable = 3;
+ }
+ break;
+
+ case OASLMUL:
+ case OASMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OMUL:
+ case OLMUL:
+ xcom(l);
+ xcom(r);
+ t = vlog(l);
+ if(t >= 0) {
+ n->left = r;
+ n->right = l;
+ l = r;
+ r = n->right;
+ }
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASHL;
+ r->vconst = t;
+ r->type = types[TINT];
+ simplifyshift(n);
+ }
+ break;
+
+ case OASLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ }
+ break;
+
+ case OLDIV:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OLSHR;
+ r->vconst = t;
+ r->type = types[TINT];
+ simplifyshift(n);
+ }
+ break;
+
+ case OASLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OASAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLMOD:
+ xcom(l);
+ xcom(r);
+ t = vlog(r);
+ if(t >= 0) {
+ n->op = OAND;
+ r->vconst--;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ xcom(l);
+ xcom(r);
+ simplifyshift(n);
+ break;
+
+ default:
+ if(l != Z)
+ xcom(l);
+ if(r != Z)
+ xcom(r);
+ break;
+ }
+ if(n->addable >= 10)
+ return;
+
+ if(l != Z)
+ n->complex = l->complex;
+ if(r != Z) {
+ if(r->complex == n->complex)
+ n->complex = r->complex+1;
+ else
+ if(r->complex > n->complex)
+ n->complex = r->complex;
+ }
+ if(n->complex == 0)
+ n->complex++;
+
+ switch(n->op) {
+ case OFUNC:
+ n->complex = FNX;
+ break;
+
+ case OADD:
+ case OXOR:
+ case OAND:
+ case OOR:
+ case OEQ:
+ case ONE:
+ /*
+ * immediate operators, make const on right
+ */
+ if(l->op == OCONST) {
+ n->left = r;
+ n->right = l;
+ }
+ break;
+ }
+}
--- /dev/null
+++ b/sys/src/cmd/zc/swt.c
@@ -1,0 +1,606 @@
+#include "gc.h"
+
+void
+swit1(C1 *q, int nc, long def, Node *n)
+{
+ Node tn;
+
+ regalloc(&tn, ®node, Z);
+ swit2(q, nc, def, n, &tn);
+ regfree(&tn);
+}
+
+void
+swit2(C1 *q, int nc, long def, Node *n, Node *tn)
+{
+ C1 *r;
+ int i;
+ Prog *sp;
+
+ if(nc < 5) {
+ for(i=0; i<nc; i++) {
+ if(debug['K'])
+ print("case = %.8llux\n", q->val);
+ gmove(nodconst(q->val), tn);
+ gopcode(OEQ, n, tn, Z);
+ patch(p, q->label);
+ q++;
+ }
+ gbranch(OGOTO);
+ patch(p, def);
+ return;
+ }
+ i = nc / 2;
+ r = q+i;
+ if(debug['K'])
+ print("case > %.8llux\n", r->val);
+ gmove(nodconst(r->val), tn);
+ gopcode(OLT, tn, n, Z);
+ sp = p;
+ gopcode(OEQ, n, tn, Z);
+ patch(p, r->label);
+ swit2(q, i, def, n, tn);
+
+ if(debug['K'])
+ print("case < %.8llux\n", r->val);
+ patch(sp, pc);
+ swit2(r+1, nc-i-1, def, n, tn);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ int sh;
+ long v;
+ Node *l;
+
+ /*
+ * n1 gets adjusted/masked value
+ * n2 gets address of cell
+ * n3 gets contents of cell
+ */
+ l = b->left;
+ if(n2 != Z) {
+ regalloc(n1, l, nn);
+ reglcgen(n2, l, Z);
+ regalloc(n3, l, Z);
+ gopcode(OAS, n2, Z, n3);
+ gopcode(OAS, n3, Z, n1);
+ } else {
+ regalloc(n1, l, nn);
+ cgen(l, n1);
+ }
+ if(b->type->shift == 0 && typeu[b->type->etype]) {
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ } else {
+ sh = 32 - b->type->shift - b->type->nbits;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, n1);
+ sh += b->type->shift;
+ if(sh > 0)
+ if(typeu[b->type->etype])
+ gopcode(OLSHR, nodconst(sh), Z, n1);
+ else
+ gopcode(OASHR, nodconst(sh), Z, n1);
+ }
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+ long v;
+ Node nod, *l;
+ int sh;
+
+ /*
+ * n1 has adjusted/masked value
+ * n2 has address of cell
+ * n3 has contents of cell
+ */
+ l = b->left;
+ regalloc(&nod, l, Z);
+ v = ~0 + (1L << b->type->nbits);
+ gopcode(OAND, nodconst(v), Z, n1);
+ gopcode(OAS, n1, Z, &nod);
+ if(nn != Z)
+ gopcode(OAS, n1, Z, nn);
+ sh = b->type->shift;
+ if(sh > 0)
+ gopcode(OASHL, nodconst(sh), Z, &nod);
+ v <<= sh;
+ gopcode(OAND, nodconst(~v), Z, n3);
+ gopcode(OOR, n3, Z, &nod);
+ gopcode(OAS, &nod, Z, n2);
+
+ regfree(&nod);
+ regfree(n1);
+ regfree(n2);
+ regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+ long r;
+
+ if(suppress)
+ return nstring;
+ r = nstring;
+ while(n) {
+ string[mnstring] = *s++;
+ mnstring++;
+ nstring++;
+ if(mnstring >= NSNAME) {
+ gpseudo(ADATA, symstring, nodconst(0L));
+ p->from.offset += nstring - NSNAME;
+ p->reg = NSNAME;
+ p->to.type = D_SCONST;
+ memmove(p->to.sval, string, NSNAME);
+ mnstring = 0;
+ }
+ n--;
+ }
+ return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+ Node *l, *r, nod1, nod2;
+ Multab *m;
+ long v;
+ int o;
+ char code[sizeof(m->code)+2], *p;
+
+ if(typefd[n->type->etype])
+ return 0;
+ l = n->left;
+ r = n->right;
+ if(l->op == OCONST) {
+ l = r;
+ r = n->left;
+ }
+ if(r->op != OCONST)
+ return 0;
+ v = convvtox(r->vconst, n->type->etype);
+ if(v != r->vconst) {
+ if(debug['M'])
+ print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ m = mulcon0(v);
+ if(!m) {
+ if(debug['M'])
+ print("%L multiply table: %lld\n", n->lineno, r->vconst);
+ return 0;
+ }
+ if(debug['M'] && debug['v'])
+ print("%L multiply: %ld\n", n->lineno, v);
+
+ memmove(code, m->code, sizeof(m->code));
+ code[sizeof(m->code)] = 0;
+
+ p = code;
+ if(p[1] == 'i')
+ p += 2;
+ regalloc(&nod1, n, nn);
+ cgen(l, &nod1);
+ if(v < 0)
+ gopcode(OSUB, &nod1, nodconst(0), &nod1);
+ regalloc(&nod2, n, Z);
+
+loop:
+ switch(*p) {
+ case 0:
+ regfree(&nod2);
+ gopcode(OAS, &nod1, Z, nn);
+ regfree(&nod1);
+ return 1;
+ case '+':
+ o = OADD;
+ goto addsub;
+ case '-':
+ o = OSUB;
+ addsub: /* number is r,n,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&4)
+ r = &nod2;
+ n = &nod1;
+ if(v&2)
+ n = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ gopcode(o, l, n, r);
+ break;
+ default: /* op is shiftcount, number is r,l */
+ v = p[1] - '0';
+ r = &nod1;
+ if(v&2)
+ r = &nod2;
+ l = &nod1;
+ if(v&1)
+ l = &nod2;
+ v = *p - 'a';
+ if(v < 0 || v >= 32) {
+ diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+ break;
+ }
+ gopcode(OASHL, nodconst(v), l, r);
+ break;
+ }
+ p += 2;
+ goto loop;
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+
+ if(a->op == OCONST && typev[a->type->etype]) {
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ p->from.offset += o;
+ p->reg = 4;
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ gpseudo(ADATA, s, nod32const(a->vconst));
+ else
+ gpseudo(ADATA, s, nod32const(a->vconst>>32));
+ p->from.offset += o + 4;
+ p->reg = 4;
+ return;
+ }
+ gpseudo(ADATA, s, a);
+ p->from.offset += o;
+ p->reg = w;
+ if(p->to.type == D_OREG)
+ p->to.type = D_CONST;
+}
+
+void zname(Biobuf*, Sym*, int);
+char* zaddr(char*, Adr*, int);
+void zwrite(Biobuf*, Prog*, int, int);
+void outhist(Biobuf*);
+
+void
+zwrite(Biobuf *b, Prog *p, int sf, int st)
+{
+ char bf[100], *bp;
+
+ bf[0] = p->as;
+ bf[1] = p->reg;
+ bf[2] = p->lineno;
+ bf[3] = p->lineno>>8;
+ bf[4] = p->lineno>>16;
+ bf[5] = p->lineno>>24;
+ bp = zaddr(bf+6, &p->from, sf);
+ bp = zaddr(bp, &p->to, st);
+ Bwrite(b, bf, bp-bf);
+}
+
+void
+outcode(void)
+{
+ struct { Sym *sym; short type; } h[NSYM];
+ Prog *p;
+ Sym *s;
+ int sf, st, t, sym;
+
+ if(debug['S']) {
+ for(p = firstp; p != P; p = p->link)
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc--;
+ for(p = firstp; p != P; p = p->link) {
+ print("%P\n", p);
+ if(p->as != ADATA && p->as != AGLOBL)
+ pc++;
+ }
+ }
+ outhist(&outbuf);
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+ for(p = firstp; p != P; p = p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.name;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.name;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(&outbuf, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ zwrite(&outbuf, p, sf, st);
+ }
+ firstp = P;
+ lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+ Hist *h;
+ char *p, *q, *op, c;
+ Prog pg;
+ int n;
+
+ pg = zprog;
+ pg.as = AHISTORY;
+ c = pathchar();
+ for(h = hist; h != H; h = h->link) {
+ p = h->name;
+ op = 0;
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && p && p[1] == ':'){
+ p += 2;
+ c = *p;
+ }
+ if(p && p[0] != c && h->offset == 0 && pathname){
+ /* on windows skip drive specifier in pathname */
+ if(systemtype(Windows) && pathname[1] == ':') {
+ op = p;
+ p = pathname+2;
+ c = *p;
+ } else if(pathname[0] == c){
+ op = p;
+ p = pathname;
+ }
+ }
+ while(p) {
+ q = utfrune(p, c);
+ if(q) {
+ n = q-p;
+ if(n == 0){
+ n = 1; /* leading "/" */
+ *p = '/'; /* don't emit "\" on windows */
+ }
+ q++;
+ } else {
+ n = strlen(p);
+ q = 0;
+ }
+ if(n) {
+ Bputc(b, ANAME);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+ }
+ p = q;
+ if(p == 0 && op) {
+ p = op;
+ op = 0;
+ }
+ }
+ pg.lineno = h->line;
+ pg.to.type = zprog.to.type;
+ pg.to.offset = h->offset;
+ if(h->offset)
+ pg.to.type = D_CONST;
+
+ zwrite(b, &pg, 0, 0);
+ }
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n, bf[7];
+ ulong sig;
+
+ n = s->name;
+ if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+ sig = sign(s);
+ bf[0] = ASIGNAME;
+ bf[1] = sig;
+ bf[2] = sig>>8;
+ bf[3] = sig>>16;
+ bf[4] = sig>>24;
+ bf[5] = t;
+ bf[6] = s->sym;
+ Bwrite(b, bf, 7);
+ s->sig = SIGDONE;
+ }
+ else{
+ bf[0] = ANAME;
+ bf[1] = t; /* type */
+ bf[2] = s->sym; /* sym */
+ Bwrite(b, bf, 3);
+ }
+ Bwrite(b, n, strlen(n)+1);
+}
+
+char*
+zaddr(char *bp, Adr *a, int s)
+{
+ long l;
+ Ieee e;
+
+ if(a->type == D_CONST) {
+ l = a->offset;
+ if((vlong)l != a->offset)
+ a->type = D_VCONST;
+ }
+ bp[0] = a->type;
+ bp[1] = a->reg;
+ bp[2] = s;
+ bp[3] = a->name;
+ bp += 4;
+ switch(a->type) {
+ default:
+ diag(Z, "unknown type %d in zaddr", a->type);
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_FCCREG:
+ case D_FCSREG:
+ break;
+
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_SCONST:
+ memmove(bp, a->sval, NSNAME);
+ bp += NSNAME;
+ break;
+
+ case D_FCONST:
+ ieeedtod(&e, a->dval);
+ l = e.l;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = e.h;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+
+ case D_VCONST:
+ l = a->offset;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ l = a->offset>>32;
+ bp[0] = l;
+ bp[1] = l>>8;
+ bp[2] = l>>16;
+ bp[3] = l>>24;
+ bp += 4;
+ break;
+ }
+ return bp;
+}
+
+long
+align(long i, Type *t, int op)
+{
+ long o;
+ Type *v;
+ int w;
+
+ o = i;
+ w = 1;
+ switch(op) {
+ default:
+ diag(Z, "unknown align opcode %d", op);
+ break;
+
+ case Asu2: /* padding at end of a struct */
+ w = SZ_VLONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael1: /* initial allign of struct element */
+ for(v=t; v->etype==TARRAY; v=v->link)
+ ;
+ w = ewidth[v->etype];
+ if(w <= 0 || w >= SZ_VLONG)
+ w = SZ_VLONG;
+ if(packflg)
+ w = packflg;
+ break;
+
+ case Ael2: /* width of a struct element */
+ o += t->width;
+ break;
+
+ case Aarg0: /* initial passbyptr argument in arg list */
+ if(typesu[t->etype]) {
+ o = align(o, types[TIND], Aarg1);
+ o = align(o, types[TIND], Aarg2);
+ }
+ break;
+
+ case Aarg1: /* initial allign of parameter */
+ w = ewidth[t->etype];
+ if(w <= 0 || w >= SZ_VLONG) {
+ w = SZ_VLONG;
+ break;
+ }
+ if(thechar == '4')
+ o += SZ_VLONG - w; /* big endian adjustment */
+ w = 1;
+ break;
+
+ case Aarg2: /* width of a parameter */
+ o += t->width;
+ w = SZ_VLONG;
+ break;
+
+ case Aaut3: /* total allign of automatic */
+ o = align(o, t, Ael1);
+ o = align(o, t, Ael2);
+ break;
+ }
+ o = round(o, w);
+ if(debug['A'])
+ print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ return o;
+}
+
+long
+maxround(long max, long v)
+{
+ v = round(v, SZ_VLONG);
+ if(v > max)
+ return v;
+ return max;
+}
--- /dev/null
+++ b/sys/src/cmd/zc/txt.c
@@ -1,0 +1,1414 @@
+#include "gc.h"
+
+static char resvreg[nelem(reg)];
+
+void
+ginit(void)
+{
+ Type *t;
+
+ thechar = 'z';
+ thestring = "loong";
+ exregoffset = REGEXT;
+ exfregoffset = FREGEXT;
+ listinit();
+ nstring = 0;
+ mnstring = 0;
+ nrathole = 0;
+ pc = 0;
+ breakpc = -1;
+ continpc = -1;
+ cases = C;
+ firstp = P;
+ lastp = P;
+ tfield = types[TLONG];
+
+ /* 64-bit machine */
+ typeword = typechlvp;
+ typeswitch = typechlv;
+ typecmplx = typesu;
+
+ zprog.link = P;
+ zprog.as = AGOK;
+ zprog.reg = NREG;
+ zprog.from.type = D_NONE;
+ zprog.from.name = D_NONE;
+ zprog.from.reg = NREG;
+ zprog.to = zprog.from;
+
+ regnode.op = OREGISTER;
+ regnode.class = CEXREG;
+ regnode.reg = REGTMP;
+ regnode.complex = 0;
+ regnode.addable = 11;
+ regnode.type = types[TLONG];
+
+ constnode.op = OCONST;
+ constnode.class = CXXX;
+ constnode.complex = 0;
+ constnode.addable = 20;
+ constnode.type = types[TLONG];
+
+ fconstnode.op = OCONST;
+ fconstnode.class = CXXX;
+ fconstnode.complex = 0;
+ fconstnode.addable = 20;
+ fconstnode.type = types[TDOUBLE];
+
+ nodsafe = new(ONAME, Z, Z);
+ nodsafe->sym = slookup(".safe");
+ nodsafe->type = types[TINT];
+ nodsafe->etype = types[TINT]->etype;
+ nodsafe->class = CAUTO;
+ complex(nodsafe);
+
+ t = typ(TARRAY, types[TCHAR]);
+ symrathole = slookup(".rathole");
+ symrathole->class = CGLOBL;
+ symrathole->type = t;
+
+ nodrat = new(ONAME, Z, Z);
+ nodrat->sym = symrathole;
+ nodrat->type = types[TIND];
+ nodrat->etype = TVOID;
+ nodrat->class = CGLOBL;
+ complex(nodrat);
+ nodrat->type = t;
+
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret->class = CPARAM;
+ nodret = new(OIND, nodret, Z);
+ complex(nodret);
+
+ memset(reg, 0, sizeof(reg));
+ reg[REGTMP] = 1;
+ reg[REGSB] = 1;
+ reg[REGLINK] = 1;
+ reg[REGSP] = 1;
+ reg[REGZERO] = 1;
+ reg[REGEXT] = 1;
+ reg[REGEXT-1] = 1;
+ memmove(resvreg, reg, sizeof(reg));
+}
+
+void
+gclean(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NREG; i++)
+ if(reg[i] && !resvreg[i])
+ diag(Z, "reg %d left allocated", i);
+ for(i=NREG; i<NREG+NREG; i++)
+ if(reg[i] && !resvreg[i])
+ diag(Z, "freg %d left allocated", i-NREG);
+ while(mnstring)
+ outstring("", 1L);
+ symstring->type->width = nstring;
+ symrathole->type->width = nrathole;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type == T)
+ continue;
+ if(s->type->width == 0)
+ continue;
+ if(s->class != CGLOBL && s->class != CSTATIC)
+ continue;
+ if(s->type == types[TENUM])
+ continue;
+ gpseudo(AGLOBL, s, nodconst(s->type->width));
+ }
+ nextpc();
+ p->as = AEND;
+ outcode();
+}
+
+void
+nextpc(void)
+{
+
+ p = alloc(sizeof(*p));
+ *p = zprog;
+ p->lineno = nearln;
+ pc++;
+ if(firstp == P) {
+ firstp = p;
+ lastp = p;
+ return;
+ }
+ lastp->link = p;
+ lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+ long regs;
+ Node fnxargs[20], *fnxp;
+
+ regs = cursafe;
+
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
+
+ curarg = 0;
+ fnxp = fnxargs;
+ garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
+
+ cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+ Node nod;
+
+ if(n == Z)
+ return;
+ if(n->op == OLIST) {
+ garg1(n->left, tn1, tn2, f, fnxp);
+ garg1(n->right, tn1, tn2, f, fnxp);
+ return;
+ }
+ if(f == 0) {
+ if(n->complex >= FNX) {
+ regsalloc(*fnxp, n);
+ nod = znode;
+ nod.op = OAS;
+ nod.left = *fnxp;
+ nod.right = n;
+ nod.type = n->type;
+ cgen(&nod, Z);
+ (*fnxp)++;
+ }
+ return;
+ }
+ if(typesu[n->type->etype]) {
+ regaalloc(tn2, n);
+ if(n->complex >= FNX) {
+ sugen(*fnxp, tn2, n->type->width);
+ (*fnxp)++;
+ } else
+ sugen(n, tn2, n->type->width);
+ return;
+ }
+ if(REGARG && curarg == 0 && typeword[n->type->etype]) {
+ regaalloc1(tn1, n);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ return;
+ }
+ if(vconst(n) == 0) {
+ regaalloc(tn2, n);
+ gopcode(OAS, n, Z, tn2);
+ return;
+ }
+ regalloc(tn1, n, Z);
+ if(n->complex >= FNX) {
+ cgen(*fnxp, tn1);
+ (*fnxp)++;
+ } else
+ cgen(n, tn1);
+ regaalloc(tn2, n);
+ gopcode(OAS, tn1, Z, tn2);
+ regfree(tn1);
+}
+
+Node*
+nodconst(long v)
+{
+ constnode.vconst = v;
+ return &constnode;
+}
+
+Node*
+nod32const(vlong v)
+{
+ constnode.vconst = v & MASK(32);
+ return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+ fconstnode.fconst = d;
+ return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+ *n = regnode;
+ n->reg = reg;
+ n->type = nn->type;
+ n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+ int r;
+
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+}
+
+int
+tmpreg(void)
+{
+ int i;
+
+ for(i=REGRET+1; i<NREG; i++)
+ if(reg[i] == 0)
+ return i;
+ diag(Z, "out of fixed registers");
+ return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+ int i, j;
+ static int lasti;
+
+ switch(tn->type->etype) {
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ case TUVLONG:
+ case TVLONG:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i > 0 && i < NREG)
+ goto out;
+ }
+ j = lasti + REGRET+1;
+ for(i=REGRET+1; i<NREG; i++) {
+ if(j >= NREG)
+ j = REGRET+1;
+ if(reg[j] == 0 && resvreg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j++;
+ }
+ diag(tn, "out of fixed registers");
+ goto err;
+
+ case TFLOAT:
+ case TDOUBLE:
+ if(o != Z && o->op == OREGISTER) {
+ i = o->reg;
+ if(i >= NREG && i < NREG+NREG)
+ goto out;
+ }
+ j = 0*2 + NREG;
+ for(i=NREG; i<NREG+NREG; i+=2) {
+ if(j >= NREG+NREG)
+ j = NREG;
+ if(reg[j] == 0) {
+ i = j;
+ goto out;
+ }
+ j += 2;
+ }
+ diag(tn, "out of float registers");
+ goto err;
+ }
+ diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+ nodreg(n, tn, 0);
+ return;
+out:
+ reg[i]++;
+ lasti++;
+ if(lasti >= 5)
+ lasti = 0;
+ nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+ Node nod;
+
+ nod = *tn;
+ nod.type = types[TIND];
+ regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ i = 0;
+ if(n->op != OREGISTER && n->op != OINDREG)
+ goto err;
+ i = n->reg;
+ if(i < 0 || i >= sizeof(reg))
+ goto err;
+ if(reg[i] <= 0)
+ goto err;
+ reg[i]--;
+ return;
+err:
+ diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+ cursafe = align(cursafe, nn->type, Aaut3);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+ *n = *nodsafe;
+ n->xoffset = -(stkoff + cursafe);
+ n->type = nn->type;
+ n->etype = nn->type->etype;
+ n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+ nodreg(n, nn, REGARG);
+ reg[REGARG]++;
+ curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+ curarg = align(curarg, nn->type, Aarg1);
+ *n = *nn;
+ n->op = OINDREG;
+ n->reg = REGSP;
+ n->xoffset = curarg + SZ_VLONG;
+ n->complex = 0;
+ n->addable = 20;
+ curarg = align(curarg, nn->type, Aarg2);
+ maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+ if(n->op != OREGISTER) {
+ diag(n, "regind not OREGISTER");
+ return;
+ }
+ n->op = OINDREG;
+ n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+ Adr a;
+
+ naddr(n, &a);
+ if(a.type == D_CONST && a.offset == 0) {
+ a.type = D_REG;
+ a.reg = 0;
+ }
+ if(a.type != D_REG && a.type != D_FREG) {
+ if(n)
+ diag(n, "bad in raddr: %O", n->op);
+ else
+ diag(n, "bad in raddr: <null>");
+ p->reg = NREG;
+ } else
+ p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+ long v;
+
+ a->type = D_NONE;
+ if(n == Z)
+ return;
+ switch(n->op) {
+ default:
+ bad:
+ diag(n, "bad in naddr: %O", n->op);
+ break;
+
+ case OREGISTER:
+ a->type = D_REG;
+ a->sym = S;
+ a->reg = n->reg;
+ if(a->reg >= NREG) {
+ a->type = D_FREG;
+ a->reg -= NREG;
+ }
+ break;
+
+ case OIND:
+ naddr(n->left, a);
+ if(a->type == D_REG) {
+ a->type = D_OREG;
+ break;
+ }
+ if(a->type == D_CONST) {
+ a->type = D_OREG;
+ break;
+ }
+ goto bad;
+
+ case OINDREG:
+ a->type = D_OREG;
+ a->sym = S;
+ a->offset = n->xoffset;
+ a->reg = n->reg;
+ break;
+
+ case ONAME:
+ a->etype = n->etype;
+ a->type = D_OREG;
+ a->name = D_STATIC;
+ a->sym = n->sym;
+ a->offset = n->xoffset;
+ if(n->class == CSTATIC)
+ break;
+ if(n->class == CEXTERN || n->class == CGLOBL) {
+ a->name = D_EXTERN;
+ break;
+ }
+ if(n->class == CAUTO) {
+ a->name = D_AUTO;
+ break;
+ }
+ if(n->class == CPARAM) {
+ a->name = D_PARAM;
+ break;
+ }
+ goto bad;
+
+ case OCONST:
+ a->sym = S;
+ a->reg = NREG;
+ if(typefd[n->type->etype]) {
+ a->type = D_FCONST;
+ a->dval = n->fconst;
+ } else {
+ a->type = D_CONST;
+ a->offset = n->vconst;
+ }
+ break;
+
+ case OADDR:
+ naddr(n->left, a);
+ if(a->type == D_OREG) {
+ a->type = D_CONST;
+ break;
+ }
+ goto bad;
+
+ case OADD:
+ if(n->left->op == OCONST) {
+ naddr(n->left, a);
+ v = a->offset;
+ naddr(n->right, a);
+ } else {
+ naddr(n->right, a);
+ v = a->offset;
+ naddr(n->left, a);
+ }
+ a->offset += v;
+ break;
+
+ }
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+ Node nod1, nod2, nod3;
+
+ nodreg(&nod1, t, NREG+f1);
+ nodreg(&nod2, t, NREG+f2);
+ regalloc(&nod3, t, t);
+ gopcode(as, &nod1, &nod2, &nod3);
+ gmove(&nod3, t);
+ regfree(&nod3);
+}
+
+void
+gmove(Node *f, Node *t)
+{
+ int ft, tt, a;
+ Node nod;
+ Prog *p1;
+
+ ft = f->type->etype;
+ tt = t->type->etype;
+
+ /*
+ * a load --
+ * put it into a register then
+ * worry what to do with it.
+ */
+ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+ switch(ft) {
+ default:
+ if(typefd[tt]) {
+ /* special case can load mem to Freg */
+ regalloc(&nod, t, t);
+ gins(AMOVW, f, &nod);
+ a = AMOVWD;
+ if(tt == TFLOAT)
+ a = AMOVWF;
+ gins(a, &nod, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+ a = AMOVW;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TUVLONG:
+ case TVLONG:
+ case TIND:
+ a = AMOVV;
+ break;
+ }
+ if(typechlp[ft] && typeilp[tt])
+ regalloc(&nod, t, t);
+ else
+ regalloc(&nod, f, t);
+ gins(a, f, &nod);
+ gmove(&nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * a store --
+ * put it into a register then
+ * store it.
+ */
+ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+ switch(tt) {
+ default:
+ a = AMOVW;
+ break;
+ case TUCHAR:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ a = AMOVB;
+ break;
+ case TUSHORT:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ a = AMOVH;
+ break;
+ case TFLOAT:
+ a = AMOVF;
+ break;
+ case TDOUBLE:
+ a = AMOVD;
+ break;
+ case TUVLONG:
+ case TVLONG:
+ case TIND:
+ a = AMOVV;
+ break;
+ }
+ if(!typefd[ft] && vconst(f) == 0) {
+ gins(a, f, t);
+ return;
+ }
+ if(ft == tt)
+ regalloc(&nod, t, f);
+ else
+ regalloc(&nod, t, Z);
+ gmove(f, &nod);
+ gins(a, &nod, t);
+ regfree(&nod);
+ return;
+ }
+
+ /*
+ * type x type cross table
+ */
+ a = AGOK;
+ switch(ft) {
+ case TUVLONG:
+ case TVLONG:
+ case TIND:
+ switch(tt) {
+ case TUVLONG:
+ case TVLONG:
+ case TIND:
+ a = AMOVV;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ case TDOUBLE:
+ gins(AMOVV, f, t);
+ gins(AMOVVD, t, t);
+ return;
+ case TFLOAT:
+ gins(AMOVV, f, t);
+ gins(AMOVVF, t, t);
+ return;
+ }
+ break;
+ case TDOUBLE:
+ case TFLOAT:
+ switch(tt) {
+ case TDOUBLE:
+ a = AMOVD;
+ if(ft == TFLOAT)
+ a = AMOVFD;
+ break;
+ case TFLOAT:
+ a = AMOVDF;
+ if(ft == TFLOAT)
+ a = AMOVF;
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ regalloc(&nod, f, Z);
+ gins(ATRUNCDW, f, &nod);
+ if(ft == TFLOAT)
+ p->as = ATRUNCFW;
+ gins(AMOVW, &nod, t);
+ regfree(&nod);
+ return;
+ case TUVLONG:
+ case TVLONG:
+ case TIND:
+ regalloc(&nod, f, Z);
+ gins(ATRUNCDV, f, &nod);
+ if(ft == TFLOAT)
+ p->as = ATRUNCFV;
+ gins(AMOVV, &nod, t);
+ regfree(&nod);
+ return;
+ }
+ break;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ switch(tt) {
+ case TDOUBLE:
+ diag(Z, "TODO long -> double");
+#ifdef TODO
+ gins(AMOVW, f, t);
+ gins(AMOVWD, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGED, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVD, nodfconst(4294967296.), &nod);
+ gins(AADDD, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+#endif
+ return;
+ case TFLOAT:
+ diag(Z, "TODO long -> float");
+#ifdef TODO
+ gins(AMOVW, f, t);
+ gins(AMOVWF, t, t);
+ if(ft == TULONG || ft == TUINT) {
+ regalloc(&nod, t, Z);
+ gins(ACMPGEF, t, Z);
+ p->reg = FREGZERO;
+ gins(ABFPT, Z, Z);
+ p1 = p;
+ gins(AMOVF, nodfconst(4294967296.), &nod);
+ gins(AADDF, &nod, t);
+ patch(p1, pc);
+ regfree(&nod);
+ }
+#endif
+ return;
+ case TUVLONG:
+ case TVLONG:
+ case TIND:
+ if(ft == TULONG || ft == TUINT) {
+ a = AMOVWU;
+ break;
+ }
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVW;
+ break;
+ }
+ break;
+ case TSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVH, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVH;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVV;
+ break;
+ }
+ break;
+ case TUSHORT:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVHU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ a = AMOVHU;
+ break;
+ case TSHORT:
+ case TUSHORT:
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVV;
+ break;
+ }
+ break;
+ case TCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVB, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVB;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVV;
+ break;
+ }
+ break;
+ case TUCHAR:
+ switch(tt) {
+ case TDOUBLE:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWD, t, t);
+ regfree(&nod);
+ return;
+ case TFLOAT:
+ regalloc(&nod, f, Z);
+ gins(AMOVBU, f, &nod);
+ gins(AMOVW, &nod, t);
+ gins(AMOVWF, t, t);
+ regfree(&nod);
+ return;
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TVLONG:
+ case TUVLONG:
+ case TIND:
+ case TSHORT:
+ case TUSHORT:
+ a = AMOVBU;
+ break;
+ case TCHAR:
+ case TUCHAR:
+ a = AMOVV;
+ break;
+ }
+ break;
+ }
+ if(a == AGOK)
+ diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+ if((a == AMOVW && ewidth[ft] == ewidth[tt]) || a == AMOVF || a == AMOVD || a == AMOVV)
+ if(samaddr(f, t))
+ return;
+ gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+ nextpc();
+ p->as = a;
+ if(f != Z)
+ naddr(f, &p->from);
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+ int a, et, ett;
+ Adr ta;
+ Node nod;
+
+ et = TLONG;
+ if(f1 != Z && f1->type != T)
+ if(f1-> op == OCONST && t != Z && t->type != T)
+ et = t->type->etype;
+ else
+ et = f1->type->etype;
+ ett = TLONG;
+ if(t != Z && t->type != T)
+ ett = t->type->etype;
+ if(llconst(f1) && o != OAS) {
+ regalloc(&nod, f1, Z);
+ gmove(f1, &nod);
+ gopcode(o, &nod, f2, t);
+ regfree(&nod);
+ return;
+ }
+ a = AGOK;
+ switch(o) {
+ case OAS:
+ gmove(f1, t);
+ return;
+
+ case OASADD:
+ case OADD:
+ a = AADDU;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AADDVU;
+ else
+ if(et == TFLOAT)
+ a = AADDF;
+ else
+ if(et == TDOUBLE)
+ a = AADDD;
+ break;
+
+ case OASSUB:
+ case OSUB:
+ a = ASUBU;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ASUBVU;
+ else
+ if(et == TFLOAT)
+ a = ASUBF;
+ else
+ if(et == TDOUBLE)
+ a = ASUBD;
+ break;
+
+ case OASOR:
+ case OOR:
+ a = AOR;
+ break;
+
+ case OASAND:
+ case OAND:
+ a = AAND;
+ break;
+
+ case OASXOR:
+ case OXOR:
+ a = AXOR;
+ break;
+
+ case OASLSHR:
+ case OLSHR:
+ a = ASRL;
+ if(ett == TVLONG || ett == TUVLONG || et == TIND)
+ a = ASRLV;
+ break;
+
+ case OASASHR:
+ case OASHR:
+ a = ASRA;
+ if(ett == TVLONG || ett == TUVLONG || et == TIND)
+ a = ASRAV;
+ break;
+
+ case OASASHL:
+ case OASHL:
+ a = ASLL;
+ if(ett == TVLONG || ett == TUVLONG || et == TIND)
+ a = ASLLV;
+ break;
+
+ case OFUNC:
+ a = AJAL;
+ break;
+
+ case OCOND:
+ a = ASGTU;
+ break;
+
+ case OCOMMA:
+ a = ASGT;
+ break;
+
+ case OASMUL:
+ case OMUL:
+ if(et == TFLOAT) {
+ a = AMULF;
+ break;
+ } else
+ if(et == TDOUBLE) {
+ a = AMULD;
+ break;
+ }
+ a = AMUL;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AMULV;
+ break;
+
+ case OASDIV:
+ case ODIV:
+ if(et == TFLOAT) {
+ a = ADIVF;
+ break;
+ } else
+ if(et == TDOUBLE) {
+ a = ADIVD;
+ break;
+ }
+ a = ADIV;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVV;
+ break;
+
+ case OASMOD:
+ case OMOD:
+ a = ADIV;
+ o = OMOD;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVV;
+ break;
+
+ case OASLMUL:
+ case OLMUL:
+ a = AMULU;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = AMULVU;
+ break;
+
+ case OASLMOD:
+ case OLMOD:
+ o = OMOD;
+
+ case OASLDIV:
+ case OLDIV:
+ a = ADIVU;
+ if(et == TVLONG || et == TUVLONG || et == TIND)
+ a = ADIVVU;
+ break;
+
+ case OEQ:
+ if(!typefd[et]) {
+ a = ABEQ;
+ break;
+ }
+
+ case ONE:
+ if(!typefd[et]) {
+ a = ABNE;
+ break;
+ }
+
+ case OLT:
+ case OLE:
+ case OGE:
+ case OGT:
+ if(typefd[et]) {
+ nextpc();
+ if(et == TFLOAT) {
+ a = ACMPGTF;
+ if(o == OEQ || o == ONE)
+ a = ACMPEQF;
+ else
+ if(o == OLT || o == OGE)
+ a = ACMPGEF;
+ } else {
+ a = ACMPGTD;
+ if(o == OEQ || o == ONE)
+ a = ACMPEQD;
+ else
+ if(o == OLT || o == OGE)
+ a = ACMPGED;
+ }
+ p->as = a;
+ naddr(f1, &p->from);
+ raddr(f2, p);
+ if(debug['g'])
+ print("%P\n", p);
+ nextpc();
+ a = ABFPF;
+ if(o == OEQ || o == OGE || o == OGT)
+ a = ABFPT;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+ }
+ if(vconst(f1) == 0 || vconst(f2) == 0) {
+ if(vconst(f1) == 0) {
+ o = invrel[relindex(o)];
+ f1 = f2;
+ }
+ switch(o) {
+ case OLT:
+ a = ABLTZ;
+ break;
+ case OLE:
+ a = ABLEZ;
+ break;
+ case OGE:
+ a = ABGEZ;
+ break;
+ case OGT:
+ a = ABGTZ;
+ break;
+ }
+ f2 = Z;
+ break;
+ }
+
+ case OLO:
+ case OLS:
+ case OHS:
+ case OHI:
+ nextpc();
+ if(o == OLE || o == OGT || o == OLS || o == OHI) {
+ naddr(f1, &p->from);
+ raddr(f2, p);
+ } else {
+ naddr(f2, &p->from);
+ raddr(f1, p);
+ }
+ naddr(®node, &p->to);
+ p->to.reg = tmpreg();
+ a = ASGT;
+ if(o == OLO || o == OLS || o == OHS || o == OHI)
+ a = ASGTU;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+
+ nextpc();
+ naddr(®node, &p->from);
+ p->from.reg = tmpreg();
+ a = ABEQ;
+ if(o == OLT || o == OGT || o == OLO || o == OHI)
+ a = ABNE;
+ p->as = a;
+ if(debug['g'])
+ print("%P\n", p);
+ return;
+ }
+ if(a == AGOK)
+ diag(Z, "bad in gopcode %O", o);
+ nextpc();
+ p->as = a;
+ if(f1 != Z)
+ naddr(f1, &p->from);
+ if(f2 != Z) {
+ naddr(f2, &ta);
+ p->reg = ta.reg;
+ if(ta.type == D_CONST && ta.offset == 0)
+ p->reg = REGZERO;
+ }
+ if(t != Z)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+ switch(f->op) {
+
+ case OREGISTER:
+ if(f->reg != t->reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+void
+gbranch(int o)
+{
+ int a;
+
+ a = AGOK;
+ switch(o) {
+ case ORETURN:
+ a = ARET;
+ break;
+ case OGOTO:
+ a = AJMP;
+ break;
+ }
+ nextpc();
+ if(a == AGOK) {
+ diag(Z, "bad in gbranch %O", o);
+ nextpc();
+ }
+ p->as = a;
+}
+
+void
+patch(Prog *op, vlong pc)
+{
+
+ op->to.offset = pc;
+ op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+ nextpc();
+ p->as = a;
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ if(a == ATEXT)
+ p->reg = (profileflg ? 0 : NOPROF);
+ p->from.name = D_EXTERN;
+ if(s->class == CSTATIC)
+ p->from.name = D_STATIC;
+ naddr(n, &p->to);
+ if(a == ADATA || a == AGLOBL)
+ pc--;
+}
+
+int
+sconst(Node *n)
+{
+ vlong vv;
+
+ if(n->op == OCONST) {
+ if(!typefd[n->type->etype]) {
+ vv = n->vconst;
+ if(vv >= (vlong)(-32766) && vv < (vlong)32766)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+llconst(Node *n)
+{
+ long l;
+
+ if(n != Z && n->op == OCONST) {
+ if(typev[n->type->etype] || n->type->etype == TIND) {
+ l = n->vconst;
+ return (vlong)l != n->vconst;
+ }
+ }
+ return 0;
+}
+
+int
+sval(long v)
+{
+ if(v >= -32766L && v < 32766L)
+ return 1;
+ return 0;
+}
+
+long
+exreg(Type *t)
+{
+ long o;
+
+ if(typechlp[t->etype]) {
+ if(exregoffset <= REGEXT-2)
+ return 0;
+ o = exregoffset;
+ if(reg[o] && !resvreg[o])
+ return 0;
+ resvreg[o] = reg[o] = 1;
+ exregoffset--;
+ return o;
+ }
+ if(typefd[t->etype]) {
+ if(exfregoffset <= NFREG-1)
+ return 0;
+ o = exfregoffset + NREG;
+ if(reg[o] && !resvreg[o])
+ return 0;
+ resvreg[o] = reg[o] = 1;
+ exfregoffset--;
+ return o;
+ }
+ return 0;
+}
+
+schar ewidth[NTYPE] =
+{
+ -1, /* [TXXX] */
+ SZ_CHAR, /* [TCHAR] */
+ SZ_CHAR, /* [TUCHAR] */
+ SZ_SHORT, /* [TSHORT] */
+ SZ_SHORT, /* [TUSHORT] */
+ SZ_INT, /* [TINT] */
+ SZ_INT, /* [TUINT] */
+ SZ_LONG, /* [TLONG] */
+ SZ_LONG, /* [TULONG] */
+ SZ_VLONG, /* [TVLONG] */
+ SZ_VLONG, /* [TUVLONG] */
+ SZ_FLOAT, /* [TFLOAT] */
+ SZ_DOUBLE, /* [TDOUBLE] */
+ SZ_IND, /* [TIND] */
+ 0, /* [TFUNC] */
+ -1, /* [TARRAY] */
+ 0, /* [TVOID] */
+ -1, /* [TSTRUCT] */
+ -1, /* [TUNION] */
+ SZ_INT, /* [TENUM] */
+};
+
+long ncast[NTYPE] =
+{
+ 0, /* [TXXX] */
+ BCHAR|BUCHAR, /* [TCHAR] */
+ BCHAR|BUCHAR, /* [TUCHAR] */
+ BSHORT|BUSHORT, /* [TSHORT] */
+ BSHORT|BUSHORT, /* [TUSHORT] */
+ BINT|BUINT|BLONG|BULONG, /* [TINT] */
+ BINT|BUINT|BLONG|BULONG, /* [TUINT] */
+ BINT|BUINT|BLONG|BULONG, /* [TLONG] */
+ BINT|BUINT|BLONG|BULONG, /* [TULONG] */
+ BVLONG|BUVLONG|BIND, /* [TVLONG] */
+ BVLONG|BUVLONG|BIND, /* [TUVLONG] */
+ BFLOAT, /* [TFLOAT] */
+ BDOUBLE, /* [TDOUBLE] */
+ BVLONG|BUVLONG|BIND, /* [TIND] */
+ 0, /* [TFUNC] */
+ 0, /* [TARRAY] */
+ 0, /* [TVOID] */
+ BSTRUCT, /* [TSTRUCT] */
+ BUNION, /* [TUNION] */
+ 0, /* [TENUM] */
+};
--- /dev/null
+++ b/sys/src/cmd/zc/z.out.h
@@ -1,0 +1,197 @@
+#define NSNAME 8
+#define NSYM 50
+#define NREG 32
+
+#define NOPROF (1<<0)
+#define DUPOK (1<<1)
+
+#define REGRET 4
+#define REGARG 4
+/* compiler allocates R4 up as temps */
+/* compiler allocates register variables R3-R23 */
+#define REGMIN 5
+#define REGMAX 28
+#define REGTMP 17
+/* compiler allocates external registers R30 down */
+#define REGEXT 30
+#define REGSP 3
+#define REGSB 31
+#define REGLINK 1
+#define REGZERO 0
+
+#define NFREG 32
+#define FREGRET 0
+#define FREGMIN 7
+/* compiler allocates register variables F0 up */
+/* compiler allocates external registers F31 down */
+#define FREGEXT 31
+
+enum as
+{
+ AXXX,
+
+ AABSD,
+ AABSF,
+ AADD,
+ AADDD,
+ AADDF,
+ AADDU,
+ AADDW,
+ AAND,
+ ABEQ,
+ ABFPF,
+ ABFPT,
+ ABGEZ,
+ ABGTZ,
+ ABLEZ,
+ ABLTZ,
+ ABNE,
+ ABREAK,
+ ACMPEQD,
+ ACMPEQF,
+ ACMPGED,
+ ACMPGEF,
+ ACMPGTD,
+ ACMPGTF,
+ ADATA,
+ ADIV,
+ ADIVD,
+ ADIVF,
+ ADIVU,
+ ADIVW,
+ AGLOBL,
+ AGOK,
+ AHISTORY,
+ AJAL,
+ AJMP,
+ AMOVB,
+ AMOVBU,
+ AMOVD,
+ AMOVDF,
+ AMOVDW,
+ AMOVF,
+ AMOVFD,
+ AMOVFW,
+ AMOVH,
+ AMOVHU,
+ AMOVW,
+ AMOVWD,
+ AMOVWF,
+ AMOVWL,
+ AMOVWR,
+ AMUL,
+ AMULD,
+ AMULF,
+ AMULU,
+ AMULW,
+ ANAME32,
+ ANAME,
+ ANEGD,
+ ANEGF,
+ ANEGW,
+ ANOP,
+ ANOR,
+ AOR,
+ AREM,
+ AREMU,
+ ARET,
+ ASGT,
+ ASGTU,
+ ASLL,
+ ASRA,
+ ASRL,
+ ASUB,
+ ASUBD,
+ ASUBF,
+ ASUBU,
+ ASUBW,
+ ASYSCALL,
+ ATEXT,
+ AWORD,
+ AXOR,
+
+ AEND,
+
+ AMOVV,
+ AMOVVL,
+ AMOVVR,
+ ASLLV,
+ ASRAV,
+ ASRLV,
+ ADIVV,
+ ADIVVU,
+ AREMV,
+ AREMVU,
+ AMULV,
+ AMULVU,
+ AADDV,
+ AADDVU,
+ ASUBV,
+ ASUBVU,
+
+ ADYNT,
+ AINIT,
+
+ ATRUNCFV,
+ ATRUNCDV,
+ ATRUNCFW,
+ ATRUNCDW,
+ AMOVWU,
+ AMOVFV,
+ AMOVDV,
+ AMOVVF,
+ AMOVVD,
+
+ ALU12IW,
+ ALU32ID,
+ ALU52ID,
+
+ ASIGNAME,
+
+ ALAST,
+};
+
+/* type/name */
+enum
+{
+ D_GOK = 0,
+ D_NONE,
+
+/* name */
+ D_EXTERN,
+ D_STATIC,
+ D_AUTO,
+ D_PARAM,
+
+/* type */
+ D_BRANCH,
+ D_OREG,
+ D_CONST,
+ D_FCONST,
+ D_SCONST,
+ D_REG,
+ D_FREG,
+ D_FCCREG,
+ D_FCSREG,
+ D_FILE,
+ D_OCONST,
+ D_FILE1,
+ D_VCONST,
+};
+
+/*
+ * this is the ranlib header
+ */
+#define SYMDEF "__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef struct ieee Ieee;
+struct ieee
+{
+ long l; /* contains ls-man 0xffffffff */
+ long h; /* contains sign 0x80000000
+ exp 0x7ff00000
+ ms-man 0x000fffff */
+};
--- /dev/null
+++ b/sys/src/cmd/zl/asm.c
@@ -1,0 +1,1290 @@
+#include "l.h"
+
+long OFFSET;
+
+#define PADDR(a) ((a) & ~0xfffffffff0000000ull)
+
+#define VPUT(v) VLEPUT(v)
+
+#define VLEPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp[1] = (c)>>8;\
+ cbp[2] = (c)>>16;\
+ cbp[3] = (c)>>24;\
+ cbp[4] = (c)>>32;\
+ cbp[5] = (c)>>40;\
+ cbp[6] = (c)>>48;\
+ cbp[7] = (c)>>56;\
+ cbp += 8;\
+ cbc -= 8;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define VBEPUT(c)\
+ {\
+ cbp[0] = (c)>>56;\
+ cbp[1] = (c)>>48;\
+ cbp[2] = (c)>>40;\
+ cbp[3] = (c)>>32;\
+ cbp[4] = (c)>>24;\
+ cbp[5] = (c)>>16;\
+ cbp[6] = (c)>>8;\
+ cbp[7] = (c);\
+ cbp += 8;\
+ cbc -= 8;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define LPUT(l) LLEPUT(l)
+
+#define LLEPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp[1] = (c)>>8;\
+ cbp[2] = (c)>>16;\
+ cbp[3] = (c)>>24;\
+ cbp += 4;\
+ cbc -= 4;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define LBEPUT(c)\
+ {\
+ cbp[0] = (c)>>24;\
+ cbp[1] = (c)>>16;\
+ cbp[2] = (c)>>8;\
+ cbp[3] = (c);\
+ cbp += 4;\
+ cbc -= 4;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define HPUT(h) HLEPUT(h)
+
+#define HLEPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp[1] = (c)>>8;\
+ cbp += 2;\
+ cbc -= 2;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+#define HBEPUT(c)\
+ {\
+ cbp[0] = (c)>>8;\
+ cbp[1] = (c);\
+ cbp += 2;\
+ cbc -= 2;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+
+#define CPUT(c)\
+ {\
+ cbp[0] = (c);\
+ cbp++;\
+ cbc--;\
+ if(cbc <= 0)\
+ cflush();\
+ }
+
+void
+cput(long l)
+{
+ CPUT(l);
+}
+
+void
+objput(long l) /* emit long in byte order appropriate to object machine */
+{
+ LPUT(l);
+}
+
+void
+objhput(short s)
+{
+ HPUT(s);
+}
+
+void
+wput(long l)
+{
+
+ cbp[0] = l>>8;
+ cbp[1] = l;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+wputl(long l)
+{
+
+ cbp[0] = l;
+ cbp[1] = l>>8;
+ cbp += 2;
+ cbc -= 2;
+ if(cbc <= 0)
+ cflush();
+}
+
+void
+lput(long l) /* emit long in big-endian byte order */
+{
+ LBEPUT(l);
+}
+
+void
+lputl(long l) /* emit long in big-endian byte order */
+{
+ LLEPUT(l);
+}
+
+void
+llput(vlong v)
+{
+ lput(v>>32);
+ lput(v);
+}
+
+void
+llputl(vlong v)
+{
+ lputl(v);
+ lputl(v>>32);
+}
+
+vlong
+entryvalue(void)
+{
+ char *a;
+ Sym *s;
+
+ a = INITENTRY;
+ if(*a >= '0' && *a <= '9')
+ return atolwhex(a);
+ s = lookup(a, 0);
+ if(s->type == 0)
+ return INITTEXT;
+ if(s->type != STEXT && s->type != SLEAF)
+ diag("entry not text: %s", s->name);
+ return s->value;
+}
+
+void
+asmb(void)
+{
+ Prog *p;
+ long magic;
+ vlong vl, t, etext;
+ Optab *o;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f asm\n", cputime());
+ Bflush(&bso);
+ OFFSET = HEADR;
+ seek(cout, OFFSET, 0);
+ pc = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 8;
+ }
+ if(p->pc != pc) {
+ diag("phase error %llux sb %llux", p->pc, pc);
+ if(!debug['a'])
+ prasm(curp);
+ pc = p->pc;
+ }
+ curp = p;
+ o = oplook(p); /* could probably avoid this call */
+ if(asmout(p, o, 0)) {
+ p = p->link;
+ pc += 4;
+ }
+ pc += o->size;
+ }
+ if(debug['a'])
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ cflush();
+
+ etext = INITTEXT + textsize;
+ for(t = pc; t < etext; t += sizeof(buf)-100) {
+ if(etext-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100, 1);
+ else
+ datblk(t, etext-t, 1);
+ }
+
+ Bflush(&bso);
+ cflush();
+
+ curtext = P;
+ switch(HEADTYPE) {
+ case 0:
+ case 2:
+ OFFSET = HEADR+textsize;
+ seek(cout, OFFSET, 0);
+ break;
+ case 6: /* no header, padded */
+ OFFSET = rnd(HEADR+textsize, INITRND);
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ for(t = 0; t < datsize; t += sizeof(buf)-100) {
+ if(datsize-t > sizeof(buf)-100)
+ datblk(t, sizeof(buf)-100, 0);
+ else
+ datblk(t, datsize-t, 0);
+ }
+
+ symsize = 0;
+ lcsize = 0;
+ if(!debug['s']) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f sym\n", cputime());
+ Bflush(&bso);
+ switch(HEADTYPE) {
+ case 0:
+ debug['s'] = 1;
+ break;
+ case 2:
+ OFFSET = HEADR+textsize+datsize;
+ seek(cout, OFFSET, 0);
+ break;
+ case 6: /* no header, padded */
+ OFFSET += rnd(datsize, INITRND);
+ seek(cout, OFFSET, 0);
+ break;
+ }
+ if(!debug['s'])
+ asmsym();
+ if(debug['v'])
+ Bprint(&bso, "%5.2f pc\n", cputime());
+ Bflush(&bso);
+ if(!debug['s'])
+ asmlc();
+ cflush();
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f header\n", cputime());
+ Bflush(&bso);
+ OFFSET = 0;
+ seek(cout, OFFSET, 0);
+ switch(HEADTYPE) {
+ case 0: /* no header */
+ case 6: /* no header, padded */
+ break;
+ case 2:
+ magic = 4*29*29+7;
+ magic |= 0x00008000;
+ lput(magic); /* magic */
+ lput(textsize); /* sizes */
+ lput(datsize);
+ lput(bsssize);
+ lput(symsize); /* nsyms */
+ vl = entryvalue();
+ lput(PADDR(vl)); /* va of entry */
+ lput(0L);
+ lput(lcsize);
+ llput(vl); /* va of entry */
+ break;
+ }
+ cflush();
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s; s++){
+ CPUT(*s);
+ n--;
+ }
+ for(; n > 0; n--)
+ CPUT(0);
+}
+
+void
+cflush(void)
+{
+ int n;
+
+ n = sizeof(buf.cbuf) - cbc;
+ if(n)
+ write(cout, buf.cbuf, n);
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+}
+
+void
+nopstat(char *f, Count *c)
+{
+ if(c->outof)
+ Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
+ c->outof - c->count, c->outof,
+ (double)(c->outof - c->count)/c->outof);
+}
+
+void
+asmsym(void)
+{
+ Prog *p;
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+
+ for(h=0; h<NHASH; h++)
+ for(s=hash[h]; s!=S; s=s->link)
+ switch(s->type) {
+ case SCONST:
+ putsymb(s->name, 'D', s->value, s->version);
+ continue;
+
+ case SSTRING:
+ putsymb(s->name, 'T', s->value, s->version);
+ continue;
+
+ case SDATA:
+ putsymb(s->name, 'D', s->value+INITDAT, s->version);
+ continue;
+
+ case SBSS:
+ putsymb(s->name, 'B', s->value+INITDAT, s->version);
+ continue;
+
+ case SFILE:
+ putsymb(s->name, 'f', s->value, s->version);
+ continue;
+ }
+
+ for(p=textp; p!=P; p=p->cond) {
+ s = p->from.sym;
+ if(s->type != STEXT && s->type != SLEAF)
+ continue;
+
+ /* filenames first */
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_FILE)
+ putsymb(a->asym->name, 'z', a->aoffset, 0);
+ else
+ if(a->type == D_FILE1)
+ putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+ if(s->type == STEXT)
+ putsymb(s->name, 'T', s->value, s->version);
+ else
+ putsymb(s->name, 'L', s->value, s->version);
+
+ /* frame, auto and param after */
+ putsymb(".frame", 'm', p->to.offset+8, 0);
+ for(a=p->to.autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ putsymb(a->asym->name, 'a', -a->aoffset, 0);
+ else
+ if(a->type == D_PARAM)
+ putsymb(a->asym->name, 'p', a->aoffset, 0);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %lud\n", symsize);
+ Bflush(&bso);
+}
+
+void
+putsymb(char *s, int t, vlong v, int ver)
+{
+ int i, f;
+ long l;
+
+ if(t == 'f')
+ s++;
+ if(HEADTYPE == 2) {
+ l = v >> 32;
+ LBEPUT(l);
+ }
+ l = v;
+ LBEPUT(l);
+ if(ver)
+ t += 'a' - 'A';
+ CPUT(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ CPUT(s[0]);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+ CPUT(s[i]);
+ CPUT(s[i+1]);
+ }
+ CPUT(0);
+ CPUT(0);
+ i++;
+ }
+ else {
+ for(i=0; s[i]; i++)
+ CPUT(s[i]);
+ CPUT(0);
+ }
+ symsize += 4 + 1 + i + 1;
+ if(HEADTYPE == 2)
+ symsize += 4;
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8llux ", t, v);
+ for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+ f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver);
+ else
+ Bprint(&bso, "%c %.8llux %s\n", t, v, s);
+ }
+}
+
+#define MINLC 4
+void
+asmlc(void)
+{
+ long oldlc, v, s;
+ vlong oldpc;
+ Prog *p;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(debug['V'])
+ Bprint(&bso, "%6llux %P\n", p->pc, p);
+ continue;
+ }
+ if(debug['V'])
+ Bprint(&bso, "\t\t%6ld", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ CPUT(s+128); /* 129-255 +pc */
+ if(debug['V'])
+ Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ CPUT(0); /* 0 vv +lc */
+ CPUT(s>>24);
+ CPUT(s>>16);
+ CPUT(s>>8);
+ CPUT(s);
+ if(debug['V']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%ld(%d,%ld)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%ld(%d,%ld)\n",
+ s, 0, s);
+ Bprint(&bso, "%6llux %P\n", p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ if(s > 0) {
+ CPUT(0+s); /* 1-64 +lc */
+ if(debug['V']) {
+ Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+ Bprint(&bso, "%6llux %P\n", p->pc, p);
+ }
+ } else {
+ CPUT(64-s); /* 65-128 -lc */
+ if(debug['V']) {
+ Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+ Bprint(&bso, "%6llux %P\n", p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ while(lcsize & 1) {
+ s = 129;
+ CPUT(s);
+ lcsize++;
+ }
+ if(debug['v'] || debug['V'])
+ Bprint(&bso, "lcsize = %ld\n", lcsize);
+ Bflush(&bso);
+}
+
+void
+datblk(long s, long n, int str)
+{
+ Prog *p;
+ char *cast;
+ long l, fl, j;
+ vlong d;
+ int i, c;
+
+ memset(buf.dbuf, 0, n+100);
+ for(p = datap; p != P; p = p->link) {
+ curp = p;
+ if(str != (p->from.sym->type == SSTRING))
+ continue;
+ l = p->from.sym->value + p->from.offset - s;
+ c = p->reg;
+ i = 0;
+ if(l < 0) {
+ if(l+c <= 0)
+ continue;
+ while(l < 0) {
+ l++;
+ i++;
+ }
+ }
+ if(l >= n)
+ continue;
+ if(p->as != AINIT && p->as != ADYNT) {
+ for(j=l+(c-i)-1; j>=l; j--)
+ if(buf.dbuf[j]) {
+ print("%P\n", p);
+ diag("multiple initialization");
+ break;
+ }
+ }
+ switch(p->to.type) {
+ default:
+ diag("unknown mode in initialization\n%P", p);
+ break;
+
+ case D_FCONST:
+ switch(c) {
+ default:
+ case 4:
+ fl = ieeedtof(p->to.ieee);
+ cast = (char*)&fl;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ cast = (char*)p->to.ieee;
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[fnuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(; i<c; i++) {
+ buf.dbuf[l] = p->to.sval[i];
+ l++;
+ }
+ break;
+
+ case D_CONST:
+ d = p->to.offset;
+ if(p->to.sym) {
+ switch(p->to.sym->type) {
+ case STEXT:
+ case SLEAF:
+ case SSTRING:
+ d += p->to.sym->value;
+ break;
+ case SDATA:
+ case SBSS:
+ d += p->to.sym->value + INITDAT;
+ break;
+ }
+ }
+ cast = (char*)&d;
+ switch(c) {
+ default:
+ diag("bad nuxi %d %d\n%P", c, i, curp);
+ break;
+ case 1:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi1[i]];
+ l++;
+ }
+ break;
+ case 2:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi2[i]];
+ l++;
+ }
+ break;
+ case 4:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi4[i]];
+ l++;
+ }
+ break;
+ case 8:
+ for(; i<c; i++) {
+ buf.dbuf[l] = cast[inuxi8[i]];
+ l++;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ write(cout, buf.dbuf, n);
+}
+
+#define OP_RRR(op,r1,r2,r3)\
+ (op|(((r1)&0x1FL)<<10)|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0))
+#define OP_RR(op,r2,r3)\
+ (op|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0))
+#define OP_16IR_5I(op,i,r2)\
+ (op|(((i)&0xFFFFL)<<10)|(((r2)&0x1FL)<<5)|(((i)>>16)&0x1FL))
+#define OP_16IRR(op,i,r2,r3)\
+ (op|(((i)&0xFFFFL)<<10)|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0))
+#define OP_12IRR(op,i,r2,r3)\
+ (op|(((i)&0xFFFL)<<10)|(((r2)&0x1FL)<<5)|(((r3)&0x1FL)<<0))
+#define OP_IR(op,i,r2)\
+ (op|(((i)&0xFFFFFL)<<5)|(((r2)&0x1FL)<<0))
+#define OP_B_BL(op,i)\
+ (op|(((i)&0xFFFFL)<<10)|(((i)>>16)&0x3FFL))
+
+#define OP(x,y)\
+ (((x)<<3)|((y)<<0))
+#define SP(x,y)\
+ (((x)<<29)|((y)<<26))
+#define OP_TEN(x,y)\
+ (((x)<<21)|((y)<<10))
+
+int vshift(int);
+
+int
+asmout(Prog *p, Optab *o, int aflag)
+{
+ long o1, o2, o3, o4, o5;
+ vlong v;
+ Prog *ct;
+ int r, a;
+
+ o1 = 0;
+ o2 = 0;
+ o3 = 0;
+ o4 = 0;
+ o5 = 0;
+ switch(o->type) {
+ default:
+ diag("unknown type %d", o->type);
+ if(!debug['a'])
+ prasm(p);
+ break;
+
+ case 0: /* pseudo ops */
+ if(aflag) {
+ if(p->link) {
+ if(p->as == ATEXT) {
+ ct = curtext;
+ o2 = autosize;
+ curtext = p;
+ autosize = p->to.offset + 8;
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ curtext = ct;
+ autosize = o2;
+ } else
+ o1 = asmout(p->link, oplook(p->link), aflag);
+ }
+ return o1;
+ }
+ break;
+
+ case 1: /* mov[v] r1,r2 ==> OR r1,r0,r2 */
+ o1 = OP_RRR(oprrr(AOR), REGZERO, p->from.reg, p->to.reg);
+ break;
+
+ case 2: /* add/sub r1,[r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 3: /* mov $soreg, r ==> or/add $i,o,r */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ a = AADDVU;
+ if(o->a1 == C_ANDCON)
+ a = AOR;
+ o1 = OP_12IRR(opirr(a), v, r, p->to.reg);
+ break;
+
+ case 4: /* add $scon,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_12IRR(opirr(p->as), v, r, p->to.reg);
+ break;
+
+ case 5: /* syscall */
+ if(aflag)
+ return 0;
+ o1 = oprrr(p->as);
+ break;
+
+ case 6: /* beq r1,[r2],sbra */
+ if(aflag)
+ return 0;
+ v = 0;
+ if(p->cond != P)
+ v = (p->cond->pc - pc) >> 2;
+ if(((v << 16) >> 16) != v)
+ diag("short branch too far: %lld\n%P", v, p);
+ o1 = OP_16IRR(opirr(p->as), v, p->from.reg, p->reg);
+ break;
+
+ case 7: /* mov r, soreg ==> sw o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ o1 = OP_12IRR(opirr(p->as), v, r, p->from.reg);
+ break;
+
+ case 8: /* mov soreg, r ==> lw o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ o1 = OP_12IRR(opirr(p->as+ALAST), v, r, p->to.reg);
+ break;
+
+ case 9: /* asl r1,[r2],r3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), r, p->from.reg, p->to.reg);
+ break;
+
+ case 10: /* add $con,[r1],r2 ==> mov $con,t; add t,[r1],r2 */
+ v = regoff(&p->from);
+ r = AOR;
+ if(v < 0)
+ r = AADDU;
+ o1 = OP_12IRR(opirr(r), v, 0, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 11: /* jmp lbra */
+ if(aflag)
+ return 0;
+ v = 0;
+ if(p->cond != P)
+ v = (p->cond->pc - pc) >> 2;
+ o1 = OP_B_BL(opirr(p->as), v);
+ break;
+
+ case 12: /* movbs r,r */
+ v = 16;
+ if(p->as == AMOVB)
+ v = 24;
+ o1 = OP_16IRR(opirr(ASLL), v, p->from.reg, p->to.reg);
+ o2 = OP_16IRR(opirr(ASRA), v, p->to.reg, p->to.reg);
+ break;
+
+ case 13: /* movbu r,r */
+ if(p->as == AMOVBU)
+ o1 = OP_12IRR(opirr(AAND), 0xffL, p->from.reg, p->to.reg);
+ else
+ o1 = (0x33c0<<10) | ((p->from.reg&0x1FL)<<5) | (p->to.reg&0x1FL);
+ break;
+
+ case 14: /* movwu r,r */
+ o1 = OP_16IRR(opirr(ASLLV+ALAST), 32, p->from.reg, p->to.reg);
+ o2 = OP_16IRR(opirr(ASRLV+ALAST), 32, p->to.reg, p->to.reg);
+ break;
+
+ case 16: /* sll $c,[r1],r2 */
+ v = regoff(&p->from);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+
+ /* OP_SRR will use only the low 5 bits of the shift value */
+ if(v >= 32 && vshift(p->as))
+ o1 = OP_16IRR(opirr(p->as+ALAST), v&0x3FL, r, p->to.reg);
+ else
+ o1 = OP_16IRR(opirr(p->as), v&0x1FL, r, p->to.reg);
+ break;
+
+ case 18: /* jmp [r1],0(r2) */
+ if(aflag)
+ return 0;
+ r = p->reg;
+ if(r == NREG)
+ r = o->param;
+ o1 = OP_RRR(oprrr(p->as), 0, p->to.reg, r);
+ break;
+
+ case 19: /* mov $lcon,r ==> lu+or */
+ v = regoff(&p->from);
+ o1 = OP_IR(opir(ALU12IW), v>>12, p->to.reg);
+ o2 = OP_12IRR(opirr(AOR), v, p->to.reg, p->to.reg);
+ break;
+
+ case 23: /* add $lcon,r1,r2 ==> lu+or+add */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP || p->reg == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IR(opir(ALU12IW), v>>12, REGTMP);
+ o2 = OP_12IRR(opirr(AOR), v, REGTMP, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o3 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 24: /* mov $ucon,,r ==> lu r */
+ v = regoff(&p->from);
+ o1 = OP_IR(opir(ALU12IW), v>>12, p->to.reg);
+ break;
+
+ case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */
+ v = regoff(&p->from);
+ o1 = OP_IR(opir(ALU12IW), v>>12, REGTMP);
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o2 = OP_RRR(oprrr(p->as), REGTMP, r, p->to.reg);
+ break;
+
+ case 26: /* mov $lsext/auto/oreg,,r2 ==> lu+or+add */
+ v = regoff(&p->from);
+ if(p->to.reg == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IR(opir(ALU12IW), v>>12, REGTMP);
+ o2 = OP_12IRR(opirr(AOR), v, REGTMP, REGTMP);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ o3 = OP_RRR(oprrr(AADDVU), REGTMP, r, p->to.reg);
+ break;
+
+ case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->from);
+ a = AMOVF+ALAST;
+ if(p->as == AMOVD)
+ a = AMOVD+ALAST;
+ switch(o->size) {
+ case 12:
+ o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP);
+ o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP);
+ o3 = OP_12IRR(opirr(a), v, REGTMP, p->to.reg);
+ break;
+ case 4:
+ o1 = OP_12IRR(opirr(a), v, r, p->to.reg);
+ break;
+ default:
+ diag("bad 27 op size");
+ }
+ break;
+
+ case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ v = regoff(&p->to);
+ a = AMOVF;
+ if(p->as == AMOVD)
+ a = AMOVD;
+ switch(o->size) {
+ case 12:
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP);
+ o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP);
+ o3 = OP_12IRR(opirr(a), v, REGTMP, p->from.reg);
+ break;
+ case 4:
+ o1 = OP_12IRR(opirr(a), v, r, p->from.reg);
+ break;
+ default:
+ diag("bad 28 op size");
+ }
+ break;
+
+ case 30: /* movw r,fr */
+ a = OP_TEN(8, 1321); /* movgr2fr.w */
+ o1 = OP_RR(a, p->from.reg, p->to.reg);
+ break;
+
+ case 31: /* movw fr,r */
+ a = OP_TEN(8, 1325); /* movfr2gr.s */
+ o1 = OP_RR(a, p->to.reg, p->from.reg);
+ break;
+
+ case 32: /* fadd fr1,[fr2],fr3 */
+ r = p->reg;
+ if(r == NREG)
+ r = p->to.reg;
+ o1 = OP_RRR(oprrr(p->as), p->from.reg, r, p->to.reg);
+ break;
+
+ case 33: /* fabs fr1,fr3 */
+ o1 = OP_RRR(oprrr(p->as), 0, p->from.reg, p->to.reg);
+ break;
+
+ case 34: /* mov $con,fr ==> or/add $i,r,r2 */
+ v = regoff(&p->from);
+ r = AADDU;
+ if(o->a1 == C_ANDCON)
+ r = AOR;
+ o1 = OP_12IRR(opirr(r), v, 0, REGTMP);
+ o2 = OP_RRR(OP_TEN(8, 1321), REGTMP, 0, p->to.reg); /* movgr2fr.w */
+ break;
+
+ case 35: /* mov r,lext/luto/oreg ==> sw o(r) */
+ v = regoff(&p->to);
+ r = p->to.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP);
+ o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP);
+ o3 = OP_12IRR(opirr(p->as), r, REGTMP, p->from.reg);
+ break;
+
+ case 36: /* mov lext/lauto/lreg,r ==> lw o(r30) */
+ v = regoff(&p->from);
+ r = p->from.reg;
+ if(r == NREG)
+ r = o->param;
+ if(r == REGTMP)
+ diag("cant synthesize large constant\n%P", p);
+ o1 = OP_IR(opir(ALU12IW), (v+1<<11)>>12, REGTMP);
+ o2 = OP_RRR(oprrr(AADDVU), r, REGTMP, REGTMP);
+ o3 = OP_12IRR(opirr(p->as+ALAST), v, REGTMP, p->to.reg);
+ break;
+
+#ifdef TODO
+ case 37: /* movw r,mr */
+ a = OP_TEN(); /* movgr2cf */
+ o1 = OP_RR(a, p->from.reg, p->to.reg);
+ break;
+
+ case 38: /* movw mr,r */
+ a = OP_TEN(); /* movcf2gr */
+ o1 = OP_RR(a, p->to.reg, p->from.reg);
+ break;
+#endif
+
+ case 40: /* word */
+ if(aflag)
+ return 0;
+ o1 = regoff(&p->to);
+ break;
+
+#ifdef TODO
+ case 41: /* movw r,fcr */
+ a = OP_TEN(); /* movgr2fcsr */
+ o1 = OP_RR(a, p->from.reg, p->to.reg);
+ break;
+
+ case 42: /* movw fcr,r */
+ a = OP_TEN(); /* movfcsr2gr */
+ o1 = OP_RR(a, p->to.reg, p->from.reg);
+ break;
+#endif
+
+#ifdef TODO
+ case 47: /* movv r,fr */
+ r = SP(2,1)|(5<<21); /* dmtc1 */
+ o1 = OP_RRR(r, p->from.reg, 0, p->to.reg);
+ break;
+
+ case 48: /* movv fr,r */
+ r = SP(2,1)|(1<<21); /* dmfc1 */
+ o1 = OP_RRR(r, p->to.reg, 0, p->from.reg);
+ break;
+#endif
+ }
+ if(aflag)
+ return o1;
+ v = p->pc;
+ switch(o->size) {
+ default:
+ if(debug['a'])
+ Bprint(&bso, " %.16llux:\t\t%P\n", v, p);
+ break;
+ case 4:
+ if(debug['a'])
+ Bprint(&bso, " %.16llux: %.8lux\t%P\n", v, o1, p);
+ LPUT(o1);
+ break;
+ case 8:
+ if(debug['a'])
+ Bprint(&bso, " %.16llux: %.8lux %.8lux\t%P\n", v, o1, o2, p);
+ LPUT(o1);
+ LPUT(o2);
+ break;
+ case 12:
+ if(debug['a'])
+ Bprint(&bso, " %.16llux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ break;
+ case 16:
+ if(debug['a'])
+ Bprint(&bso, " %.16llux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ break;
+ case 20:
+ if(debug['a'])
+ Bprint(&bso, " %.16llux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ v, o1, o2, o3, o4, o5, p);
+ LPUT(o1);
+ LPUT(o2);
+ LPUT(o3);
+ LPUT(o4);
+ LPUT(o5);
+ break;
+ }
+ return 0;
+}
+
+int
+isnop(Prog *p)
+{
+ if(p->as != ANOR)
+ return 0;
+ if(p->reg != REGZERO && p->reg != NREG)
+ return 0;
+ if(p->from.type != D_REG || p->from.reg != REGZERO)
+ return 0;
+ if(p->to.type != D_REG || p->to.reg != REGZERO)
+ return 0;
+ return 1;
+}
+
+long
+oprrr(int a)
+{
+ switch(a) {
+ case AADD:
+ case AADDU: return 0x20<<15;
+ case ASGT: return 0x24<<15;
+ case ASGTU: return 0x25<<15;
+ case AAND: return 0x29<<15;
+ case AOR: return 0x2a<<15;
+ case AXOR: return 0x2b<<15;
+ case ASUB:
+ case ASUBU: return 0x22<<15;
+ case ANOR: return 0x28<<15;
+ case ASLL: return 0x2e<<15;
+ case ASRL: return 0x2f<<15;
+ case ASRA: return 0x30<<15;
+
+ case ASLLV: return 0x31<<15;
+ case ASRLV: return 0x32<<15;
+ case ASRAV: return 0x33<<15;
+
+ case AADDV:
+ case AADDVU: return 0x21<<15;
+ case ASUBV:
+ case ASUBVU: return 0x23<<15;
+ case AREM: return 0x41<<15;
+ case ADIV: return 0x40<<15;
+ case AREMU: return 0x43<<15;
+ case ADIVU: return 0x42<<15;
+ case AMUL:
+ case AMULU: return 0x38<<15;
+
+ case AREMV: return 0x45<<15;
+ case ADIVV: return 0x44<<15;
+ case AREMVU: return 0x47<<15;
+ case ADIVVU: return 0x46<<15;
+ case AMULV:
+ case AMULVU: return 0x3b<<15;
+
+ case AJMP: return 0x13<<26;
+ case AJAL: return (0x13<<26)|1;
+
+ case ABREAK: return 0x54<<15;
+ case ASYSCALL: return 0x56<<15;
+
+ case ADIVF: return 0x20d<<15;
+ case ADIVD: return 0x20e<<15;
+ case AMULF: return 0x209<<15;
+ case AMULD: return 0x20a<<15;
+ case ASUBF: return 0x205<<15;
+ case ASUBD: return 0x206<<15;
+ case AADDF: return 0x201<<15;
+ case AADDD: return 0x202<<15;
+
+ case ATRUNCFV: return 0x46a9<<10;
+ case ATRUNCDV: return 0x46aa<<10;
+ case ATRUNCFW: return 0x46a1<<10;
+ case ATRUNCDW: return 0x46a2<<10;
+ case AMOVFV: return 0x46c9<<10;
+ case AMOVDV: return 0x46ca<<10;
+ case AMOVVF: return 0x4746<<10;
+ case AMOVVD: return 0x474a<<10;
+
+ case AMOVFW: return 0x46c1<<10;
+ case AMOVDW: return 0x46c2<<10;
+ case AMOVWF: return 0x4744<<10;
+ case AMOVDF: return 0x4646<<10;
+ case AMOVWD: return 0x4748<<10;
+ case AMOVFD: return 0x4649<<10;
+ case AABSF: return 0x4501<<10;
+ case AABSD: return 0x4502<<10;
+ case AMOVF: return 0x4525<<10;
+ case AMOVD: return 0x4526<<10;
+ case ANEGF: return 0x4505<<10;
+ case ANEGD: return 0x4506<<10;
+
+ case ACMPEQF: return (0xc1<<20) | (0x4<<15);
+ case ACMPEQD: return (0xc2<<20) | (0x4<<15);
+ case ACMPGTF: return (0xc1<<20) | (0x3<<15);
+ case ACMPGTD: return (0xc2<<20) | (0x3<<15);
+ case ACMPGEF: return (0xc1<<20) | (0x7<<15);
+ case ACMPGED: return (0xc2<<20) | (0x7<<15);
+ }
+ if(a >= ALAST)
+ diag("bad rrr %A+ALAST", a-ALAST);
+ else
+ diag("bad rrr %A", a);
+ return 0;
+}
+
+long
+opir(int a)
+{
+ switch(a){
+ case ALU12IW: return 0xa<<25;
+ case ALU32ID: return 0xb<<25;
+ }
+ diag("bad ir %d", a);
+ return 0;
+}
+
+long
+opirr(int a)
+{
+ switch(a) {
+ case AADD:
+ case AADDU: return 0xa<<22;
+ case ASGT: return 0x8<<22;
+ case ASGTU: return 0x9<<22;
+ case AAND: return 0xd<<22;
+ case AOR: return 0xe<<22;
+ case AXOR: return 0xf<<22;
+ case ASLL: return 0x81<<15;
+ case ASRL: return 0x89<<15;
+ case ASRA: return 0x91<<15;
+
+ case AADDV:
+ case AADDVU: return 0xb<<22;
+
+ case AJMP: return 0x14<<26;
+ case AJAL: return 0x15<<26;
+ case ABEQ: return 0x16<<26;
+ case ABEQ+ALAST: return 0x10<<26; /* likely */
+ case ABNE: return 0x17<<26;
+ case ABNE+ALAST: return 0x11<<26; /* likely */
+
+ case ABLEZ:
+ case ABGEZ: return 0x19<<26;
+ case ABLTZ:
+ case ABGTZ: return 0x18<<26;
+
+ case ABFPT: return (0x12<<26) | (0x1<<8);
+ case ABFPF: return 0x12<<26;
+
+ case AMOVB:
+ case AMOVBU: return 0xa4<<22;
+ case AMOVH:
+ case AMOVHU: return 0xa5<<22;
+ case AMOVW: return 0xa6<<22;
+ case AMOVV: return 0xa7<<22;
+ case AMOVF: return 0xad<<22;
+ case AMOVD: return 0xaf<<22;
+ case AMOVWL: return 0xbc<<22;
+ case AMOVWR: return 0xbd<<22;
+ case AMOVVL: return 0xbe<<22;
+ case AMOVVR: return 0xbf<<22;
+
+ case ABREAK: return 0x18<<22;
+
+ case AMOVWL+ALAST: return 0xb8<<22;
+ case AMOVWR+ALAST: return 0xb9<<22;
+ case AMOVVL+ALAST: return 0xba<<22;
+ case AMOVVR+ALAST: return 0xbb<<22;
+ case AMOVB+ALAST: return 0xa0<<22;
+ case AMOVBU+ALAST: return 0xa8<<22;
+ case AMOVH+ALAST: return 0xa1<<22;
+ case AMOVHU+ALAST: return 0xa9<<22;
+ case AMOVW+ALAST: return 0xa2<<22;
+ case AMOVV+ALAST: return 0xa3<<22;
+ case AMOVF+ALAST: return 0xac<<22;
+ case AMOVD+ALAST: return 0xae<<22;
+
+ case ASLLV:
+ case ASLLV+ALAST: return 0x41<<16;
+ case ASRLV:
+ case ASRLV+ALAST: return 0x45<<16;
+ case ASRAV:
+ case ASRAV+ALAST: return 0x49<<16;
+
+ case ALU52ID: return 0xc<<22;
+ }
+ if(a >= ALAST)
+ diag("bad irr %A+ALAST", a-ALAST);
+ else
+ diag("bad irr %A", a);
+ return 0;
+}
+
+int
+vshift(int a)
+{
+ switch(a){
+ case ASLLV: return 1;
+ case ASRLV: return 1;
+ case ASRAV: return 1;
+ }
+ return 0;
+}
--- /dev/null
+++ b/sys/src/cmd/zl/compat.c
@@ -1,0 +1,2 @@
+#include "l.h"
+#include "../cc/compat"
--- /dev/null
+++ b/sys/src/cmd/zl/l.h
@@ -1,0 +1,341 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "../zc/z.out.h"
+#include "../cc/compat.h"
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+#define LIBNAMELEN 300
+
+typedef struct Adr Adr;
+typedef struct Sym Sym;
+typedef struct Autom Auto;
+typedef struct Prog Prog;
+typedef struct Optab Optab;
+typedef struct Oprang Oprang;
+typedef uchar Opcross[32][2][32];
+typedef struct Count Count;
+
+#define P ((Prog*)0)
+#define S ((Sym*)0)
+#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+
+struct Adr
+{
+ union
+ {
+ vlong u0offset;
+ char* u0sval;
+ Ieee* u0ieee;
+ } u0;
+ union
+ {
+ Auto* u1autom;
+ Sym* u1sym;
+ } u1;
+ char type;
+ char reg;
+ char name;
+ char class;
+};
+
+#define offset u0.u0offset
+#define sval u0.u0sval
+#define ieee u0.u0ieee
+
+#define autom u1.u1autom
+#define sym u1.u1sym
+
+struct Prog
+{
+ Adr from;
+ Adr to;
+ union
+ {
+ long u0regused;
+ Prog* u0forwd;
+ } u0;
+ Prog* cond;
+ Prog* link;
+ vlong pc;
+ long line;
+ uchar mark;
+ uchar optab;
+ char as;
+ char reg;
+};
+#define regused u0.u0regused
+#define forwd u0.u0forwd
+
+struct Sym
+{
+ char *name;
+ short type;
+ short version;
+ short become;
+ short frame;
+ vlong value;
+ Sym* link;
+};
+struct Autom
+{
+ Sym* asym;
+ Auto* link;
+ long aoffset;
+ short type;
+};
+struct Optab
+{
+ char as;
+ char a1;
+ char a2;
+ char a3;
+ char type;
+ char size;
+ char param;
+};
+struct Oprang
+{
+ Optab* start;
+ Optab* stop;
+};
+struct Count
+{
+ long count;
+ long outof;
+};
+
+enum
+{
+ STEXT = 1,
+ SDATA,
+ SBSS,
+ SDATA1,
+ SXREF,
+ SLEAF,
+ SFILE,
+ SCONST,
+ SSTRING,
+
+ C_NONE = 0,
+ C_REG,
+ C_FREG,
+ C_FCCREG,
+ C_FCSREG,
+ C_ZCON,
+ C_SCON,
+ C_ADD0CON,
+ C_AND0CON,
+ C_ADDCON,
+ C_ANDCON,
+ C_UCON,
+ C_LCON,
+ C_SACON,
+ C_SECON,
+ C_LACON,
+ C_LECON,
+ C_SBRA,
+ C_LBRA,
+ C_SAUTO,
+ C_SEXT,
+ C_LAUTO,
+ C_LEXT,
+ C_ZOREG,
+ C_SOREG,
+ C_LOREG,
+ C_GOK,
+
+/* mark flags */
+ FOLL = 1<<0,
+ LABEL = 1<<1,
+ LEAF = 1<<2,
+ SYNC = 1<<3,
+ BRANCH = 1<<4,
+ LOAD = 1<<5,
+ FCMP = 1<<6,
+
+ BIG = 2046,
+ STRINGSZ = 200,
+ NHASH = 10007,
+ NHUNK = 100000,
+ MINSIZ = 64,
+ NENT = 100,
+ MAXIO = 8192,
+ MAXHIST = 20, /* limit of path elements for history symbols */
+};
+
+EXTERN union
+{
+ struct
+ {
+ uchar obuf[MAXIO]; /* output buffer */
+ uchar ibuf[MAXIO]; /* input buffer */
+ } u;
+ char dbuf[1];
+} buf;
+
+#define cbuf u.obuf
+#define xbuf u.ibuf
+
+EXTERN long HEADR; /* length of header */
+EXTERN int HEADTYPE; /* type of header */
+EXTERN vlong INITDAT; /* data location */
+EXTERN vlong INITRND; /* data round above text location */
+EXTERN vlong INITTEXT; /* text location */
+EXTERN vlong INITTEXTP; /* text location (physical) */
+EXTERN char* INITENTRY; /* entry point */
+EXTERN long autosize;
+EXTERN Biobuf bso;
+EXTERN long bsssize;
+EXTERN int cbc;
+EXTERN uchar* cbp;
+EXTERN int cout;
+EXTERN Auto* curauto;
+EXTERN Auto* curhist;
+EXTERN Prog* curp;
+EXTERN Prog* curtext;
+EXTERN Prog* datap;
+EXTERN long datsize;
+EXTERN char debug[128];
+EXTERN Prog* etextp;
+EXTERN Prog* firstp;
+EXTERN char fnuxi4[4]; /* for 3l [sic] */
+EXTERN char fnuxi8[8];
+EXTERN char* noname;
+EXTERN Sym* hash[NHASH];
+EXTERN Sym* histfrog[MAXHIST];
+EXTERN int histfrogp;
+EXTERN int histgen;
+EXTERN char* library[50];
+EXTERN char* libraryobj[50];
+EXTERN int libraryp;
+EXTERN int xrefresolv;
+EXTERN char inuxi1[1];
+EXTERN char inuxi2[2];
+EXTERN char inuxi4[4];
+EXTERN char inuxi8[8];
+EXTERN Prog* lastp;
+EXTERN long lcsize;
+EXTERN char literal[32];
+EXTERN int nerrors;
+EXTERN vlong instoffset;
+EXTERN Opcross opcross[10];
+EXTERN Oprang oprange[ALAST];
+EXTERN char* outfile;
+EXTERN vlong pc;
+EXTERN uchar repop[ALAST];
+EXTERN long symsize;
+EXTERN Prog* textp;
+EXTERN vlong textsize;
+EXTERN int version;
+EXTERN char xcmp[32][32];
+EXTERN Prog zprg;
+EXTERN int dtype;
+
+EXTERN struct
+{
+ Count branch;
+ Count fcmp;
+ Count load;
+ Count mfrom;
+ Count page;
+ Count jump;
+ Count store;
+} nop;
+
+extern char* anames[];
+extern Optab optab[];
+
+#pragma varargck type "A" int
+#pragma varargck type "D" Adr*
+#pragma varargck type "N" Adr*
+#pragma varargck type "P" Prog*
+#pragma varargck type "S" char*
+
+#pragma varargck argpos diag 1
+
+int Aconv(Fmt*);
+int Dconv(Fmt*);
+int Nconv(Fmt*);
+int Pconv(Fmt*);
+int Sconv(Fmt*);
+int aclass(Adr*);
+void addhist(long, int);
+void addlibpath(char*);
+void addnop(Prog*);
+void append(Prog*, Prog*);
+void asmb(void);
+void asmlc(void);
+int asmout(Prog*, Optab*, int);
+void asmsym(void);
+vlong atolwhex(char*);
+vlong atovlwhex(char*);
+Prog* brloop(Prog*);
+void buildop(void);
+void buildrep(int, int);
+void cflush(void);
+int cmp(int, int);
+void cput(long);
+int compound(Prog*);
+double cputime(void);
+void datblk(long, long, int);
+void diag(char*, ...);
+void dodata(void);
+void doprof1(void);
+void doprof2(void);
+vlong entryvalue(void);
+void errorexit(void);
+void exchange(Prog*);
+int find1(long, int);
+void follow(void);
+void histtoauto(void);
+vlong ieeedtov(Ieee*);
+double ieeedtod(Ieee*);
+long ieeedtof(Ieee*);
+int isint32(vlong);
+int isuint32(uvlong);
+int isnop(Prog*);
+void ldobj(int, long, char*);
+void loadlib(void);
+void listinit(void);
+Sym* lookup(char*, int);
+void llput(vlong);
+void llputl(vlong);
+void lput(long);
+void lputl(long);
+void bput(long);
+void mkfwd(void);
+void* mysbrk(ulong);
+void names(void);
+void nocache(Prog*);
+void noops(void);
+void nopstat(char*, Count*);
+void nuxiinit(void);
+void objfile(char*);
+int ocmp(const void*, const void*);
+long opir(int);
+long opirr(int);
+Optab* oplook(Prog*);
+long oprrr(int);
+void patch(void);
+void prasm(Prog*);
+void prepend(Prog*, Prog*);
+Prog* prg(void);
+int pseudo(Prog*);
+void putsymb(char*, int, vlong, int);
+long regoff(Adr*);
+vlong vregoff(Adr*);
+int relinv(int);
+vlong rnd(vlong, long);
+void sched(Prog*, Prog*);
+void span(void);
+void strnput(char*, int);
+void undef(void);
+void wput(long);
+void wputl(long);
+void xdefine(char*, int, vlong);
+void xfol(Prog*);
+void xfol(Prog*);
--- /dev/null
+++ b/sys/src/cmd/zl/list.c
@@ -1,0 +1,263 @@
+#include "l.h"
+
+void
+listinit(void)
+{
+
+ fmtinstall('A', Aconv);
+ fmtinstall('D', Dconv);
+ fmtinstall('P', Pconv);
+ fmtinstall('S', Sconv);
+ fmtinstall('N', Nconv);
+}
+
+void
+prasm(Prog *p)
+{
+ print("%P\n", p);
+}
+
+int
+Pconv(Fmt *fp)
+{
+ char str[STRINGSZ], *s;
+ Prog *p;
+ int a;
+
+ p = va_arg(fp->args, Prog*);
+ curp = p;
+ a = p->as;
+ if(a == ADATA || a == ADYNT || a == AINIT)
+ sprint(str, "(%ld) %A %D/%d,%D",
+ p->line, a, &p->from, p->reg, &p->to);
+ else{
+ s = str;
+ s += sprint(s, "(%ld)", p->line);
+ if(p->reg == NREG)
+ sprint(s, " %A %D,%D",
+ a, &p->from, &p->to);
+ else
+ if(p->from.type != D_FREG)
+ sprint(s, " %A %D,R%d,%D",
+ a, &p->from, p->reg, &p->to);
+ else
+ sprint(s, " %A %D,F%d,%D",
+ a, &p->from, p->reg, &p->to);
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+ char *s;
+ int a;
+
+ a = va_arg(fp->args, int);
+ s = "???";
+ if(a >= AXXX && a < ALAST)
+ s = anames[a];
+ return fmtstrcpy(fp, s);
+}
+
+int
+Dconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ long v;
+
+ a = va_arg(fp->args, Adr*);
+ switch(a->type) {
+
+ default:
+ sprint(str, "GOK-type(%d)", a->type);
+ break;
+
+ case D_NONE:
+ str[0] = 0;
+ if(a->name != D_NONE || a->reg != NREG || a->sym != S)
+ sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ break;
+
+ case D_CONST:
+ sprint(str, "$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OCONST:
+ sprint(str, "$*$%N", a);
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG)
+ sprint(str, "%N(R%d)", a, a->reg);
+ else
+ sprint(str, "%N", a);
+ break;
+
+ case D_REG:
+ sprint(str, "R%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FREG:
+ sprint(str, "F%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCCREG:
+ sprint(str, "FCC%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_FCSREG:
+ sprint(str, "FCSR%d", a->reg);
+ if(a->name != D_NONE || a->sym != S)
+ sprint(str, "%N(R%d)(REG)", a, a->reg);
+ break;
+
+ case D_BRANCH: /* botch */
+ if(curp->cond != P) {
+ v = curp->cond->pc;
+ if(v >= INITTEXT)
+ v -= INITTEXT-HEADR;
+ if(a->sym != S)
+ sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ else
+ sprint(str, "%.5lux(BRANCH)", v);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%lld(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%lld(APC)", a->offset);
+ break;
+
+ case D_FCONST:
+ sprint(str, "$%e", ieeedtod(a->ieee));
+ break;
+
+ case D_SCONST:
+ sprint(str, "$\"%S\"", a->sval);
+ break;
+ }
+ return fmtstrcpy(fp, str);
+}
+
+int
+Nconv(Fmt *fp)
+{
+ char str[STRINGSZ];
+ Adr *a;
+ Sym *s;
+
+ a = va_arg(fp->args, Adr*);
+ s = a->sym;
+ switch(a->name) {
+ default:
+ sprint(str, "GOK-name(%d)", a->name);
+ break;
+
+ case D_NONE:
+ sprint(str, "%lld", a->offset);
+ break;
+
+ case D_EXTERN:
+ if(s == S)
+ sprint(str, "%lld(SB)", a->offset);
+ else
+ sprint(str, "%s+%lld(SB)", s->name, a->offset);
+ break;
+
+ case D_STATIC:
+ if(s == S)
+ sprint(str, "<>+%lld(SB)", a->offset);
+ else
+ sprint(str, "%s<>+%lld(SB)", s->name, a->offset);
+ break;
+
+ case D_AUTO:
+ if(s == S)
+ sprint(str, "%lld(SP)", a->offset);
+ else
+ sprint(str, "%s-%lld(SP)", s->name, -a->offset);
+ break;
+
+ case D_PARAM:
+ if(s == S)
+ sprint(str, "%lld(FP)", a->offset);
+ else
+ sprint(str, "%s+%lld(FP)", s->name, a->offset);
+ break;
+ }
+
+ return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+ int i, c;
+ char str[STRINGSZ], *p, *a;
+
+ a = va_arg(fp->args, char*);
+ p = str;
+ for(i=0; i<sizeof(long); i++) {
+ c = a[i] & 0xff;
+ if(c >= 'a' && c <= 'z' ||
+ c >= 'A' && c <= 'Z' ||
+ c >= '0' && c <= '9' ||
+ c == ' ' || c == '%') {
+ *p++ = c;
+ continue;
+ }
+ *p++ = '\\';
+ switch(c) {
+ case 0:
+ *p++ = 'z';
+ continue;
+ case '\\':
+ case '"':
+ *p++ = c;
+ continue;
+ case '\n':
+ *p++ = 'n';
+ continue;
+ case '\t':
+ *p++ = 't';
+ continue;
+ }
+ *p++ = (c>>6) + '0';
+ *p++ = ((c>>3) & 7) + '0';
+ *p++ = (c & 7) + '0';
+ }
+ *p = 0;
+ return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+ char buf[STRINGSZ], *tn;
+ va_list arg;
+
+ tn = "??none??";
+ if(curtext != P && curtext->from.sym != S)
+ tn = curtext->from.sym->name;
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ print("%s: %s\n", tn, buf);
+
+ nerrors++;
+ if(nerrors > 10) {
+ print("too many errors\n");
+ errorexit();
+ }
+}
--- /dev/null
+++ b/sys/src/cmd/zl/mkfile
@@ -1,0 +1,33 @@
+</$objtype/mkfile
+
+TARG=zl
+OFILES=\
+ asm.$O\
+ list.$O\
+ noop.$O\
+ obj.$O\
+ optab.$O\
+ pass.$O\
+ span.$O\
+ enam.$O\
+ compat.$O\
+
+HFILES=\
+ l.h\
+ ../zc/z.out.h\
+ ../cc/compat.h\
+
+BIN=/$objtype/bin
+CFLAGS=$CFLAGS -. -I.
+</sys/src/cmd/mkone
+
+compat.$O: ../cc/compat
+
+enam.$O: ../zc/enam.c
+ $CC $CFLAGS ../zc/enam.c
+
+test:V: $O.out
+ rm -f xxx
+ mv $O.out xxx
+ ./xxx $OFILES
+ cmp $O.out xxx
--- /dev/null
+++ b/sys/src/cmd/zl/noop.c
@@ -1,0 +1,363 @@
+#include "l.h"
+
+void
+noops(void)
+{
+ Prog *p, *q, *q1;
+ int o, curframe, curbecome, maxbecome;
+
+ /*
+ * find leaf subroutines
+ * become sizes
+ * frame sizes
+ * strip NOPs
+ * expand RET
+ * expand BECOME pseudo
+ */
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f noops\n", cputime());
+ Bflush(&bso);
+
+ curframe = 0;
+ curbecome = 0;
+ maxbecome = 0;
+ curtext = 0;
+
+ q = P;
+ for(p = firstp; p != P; p = p->link) {
+
+ /* find out how much arg space is used in this TEXT */
+ if(p->to.type == D_OREG && p->to.reg == REGSP)
+ if(p->to.offset > curframe)
+ curframe = p->to.offset;
+
+ switch(p->as) {
+ case ATEXT:
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+ curframe = 0;
+ curbecome = 0;
+
+ p->mark |= LABEL|LEAF|SYNC;
+ if(p->link)
+ p->link->mark |= LABEL;
+ curtext = p;
+ break;
+
+ /* too hard, just leave alone */
+ case AMOVW:
+ case AMOVV:
+ if(p->to.type == D_FCCREG ||
+ p->to.type == D_FCSREG) {
+ p->mark |= LABEL|SYNC;
+ break;
+ }
+ if(p->from.type == D_FCCREG ||
+ p->from.type == D_FCSREG) {
+ p->mark |= LABEL|SYNC;
+ break;
+ }
+ break;
+
+ /* too hard, just leave alone */
+ case ASYSCALL:
+ case AWORD:
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ANOR:
+ if(p->to.type == D_REG && p->to.reg == REGZERO)
+ p->mark |= LABEL|SYNC;
+ break;
+
+ case ARET:
+ /* special form of RET is BECOME */
+ if(p->from.type == D_CONST)
+ if(p->from.offset > curbecome)
+ curbecome = p->from.offset;
+
+ if(p->link != P)
+ p->link->mark |= LABEL;
+ break;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ q1->mark |= p->mark;
+ continue;
+
+ case AJAL:
+ if(curtext != P)
+ curtext->mark &= ~LEAF;
+
+ case AJMP:
+ case ABEQ:
+ case ABGEZ:
+ case ABGTZ:
+ case ABLEZ:
+ case ABLTZ:
+ case ABNE:
+ case ABFPT:
+ case ABFPF:
+ p->mark |= BRANCH;
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
+ }
+ if(!(q1->mark & LEAF))
+ q1->mark |= LABEL;
+ } else
+ p->mark |= LABEL;
+ q1 = p->link;
+ if(q1 != P)
+ q1->mark |= LABEL;
+ break;
+ }
+ q = p;
+ }
+
+ if(curtext && curtext->from.sym) {
+ curtext->from.sym->frame = curframe;
+ curtext->from.sym->become = curbecome;
+ if(curbecome > maxbecome)
+ maxbecome = curbecome;
+ }
+
+ if(debug['b'])
+ print("max become = %d\n", maxbecome);
+ xdefine("ALEFbecome", STEXT, maxbecome);
+
+ curtext = 0;
+ for(p = firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ATEXT:
+ curtext = p;
+ break;
+ case AJAL:
+ if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+ o = maxbecome - curtext->from.sym->frame;
+ if(o <= 0)
+ break;
+ /* calling a become or calling a variable */
+ if(p->to.sym == S || p->to.sym->become) {
+ curtext->to.offset += o;
+ if(debug['b']) {
+ curp = p;
+ print("%D calling %D increase %d\n",
+ &curtext->from, &p->to, o);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ curtext = p;
+ autosize = p->to.offset + 8;
+ if(autosize <= 8)
+ if(curtext->mark & LEAF) {
+ p->to.offset = -8;
+ autosize = 0;
+ }
+
+ q = p;
+ if(autosize) {
+ if(autosize & 7)
+ Bprint(&bso, "odd stack in: %s\n",
+ curtext->from.sym->name);
+ q = prg();
+ q->as = AADDV;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = -autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ } else
+ if(!(curtext->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ curtext->from.sym->name);
+ Bflush(&bso);
+ curtext->mark |= LEAF;
+ }
+
+ if(curtext->mark & LEAF) {
+ if(curtext->from.sym)
+ curtext->from.sym->type = SLEAF;
+ break;
+ }
+
+ q1 = prg();
+ q1->as = AMOVV;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGLINK;
+ q1->to.type = D_OREG;
+ q1->from.offset = 0;
+ q1->to.reg = REGSP;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ case ARET:
+ nocache(p);
+ if(p->from.type == D_CONST)
+ goto become;
+ if(curtext->mark & LEAF) {
+ if(!autosize) {
+ p->as = AJMP;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
+ p->mark |= BRANCH;
+ break;
+ }
+
+ p->as = AADDV;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ q = prg();
+ q->as = AJMP;
+ q->line = p->line;
+ q->to.type = D_OREG;
+ q->to.offset = 0;
+ q->to.reg = REGLINK;
+ q->mark |= BRANCH;
+
+ q->link = p->link;
+ p->link = q;
+ break;
+ }
+ p->as = AMOVV;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ q = p;
+ if(autosize) {
+ q = prg();
+ q->as = AADDV;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+
+ q->link = p->link;
+ p->link = q;
+ }
+
+ q1 = prg();
+ q1->as = AJMP;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 0;
+ q1->to.reg = 2;
+ q1->mark |= BRANCH;
+
+ q1->link = q->link;
+ q->link = q1;
+ break;
+
+ become:
+ if(curtext->mark & LEAF) {
+
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ p->as = AADDV;
+ p->from = zprg.from;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ break;
+ }
+ q = prg();
+ q->line = p->line;
+ q->as = AJMP;
+ q->from = zprg.from;
+ q->to = p->to;
+ q->cond = p->cond;
+ q->link = p->link;
+ q->mark |= BRANCH;
+ p->link = q;
+
+ q = prg();
+ q->line = p->line;
+ q->as = AADDV;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+
+ p->as = AMOVV;
+ p->from = zprg.from;
+ p->from.type = D_OREG;
+ p->from.offset = 0;
+ p->from.reg = REGSP;
+ p->to = zprg.to;
+ p->to.type = D_REG;
+ p->to.reg = REGLINK;
+
+ break;
+ }
+ }
+}
+
+void
+addnop(Prog *p)
+{
+ Prog *q;
+
+ q = prg();
+ q->as = ANOR;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGZERO;
+ q->to.type = D_REG;
+ q->to.reg = REGZERO;
+
+ q->link = p->link;
+ p->link = q;
+}
+
+void
+nocache(Prog *p)
+{
+ p->optab = 0;
+ p->from.class = 0;
+ p->to.class = 0;
+}
--- /dev/null
+++ b/sys/src/cmd/zl/obj.c
@@ -1,0 +1,1391 @@
+#define EXTERN
+#include "l.h"
+#include <ar.h>
+
+#ifndef DEFAULT
+#define DEFAULT '9'
+#endif
+
+char *noname = "<none>";
+char symname[] = SYMDEF;
+char thechar = 'z';
+char *thestring = "loong";
+
+char** libdir;
+int nlibdir = 0;
+static int maxlibdir = 0;
+
+/*
+ * -H0 no header
+ * -H2 -T0x100028 -R0x100000 is plan9 format
+ * -H6 -R0x10000 no header with segments padded to pages
+ * -H7 is elf
+ */
+
+void
+usage(void)
+{
+ diag("usage: %s [-options] objects", argv0);
+ errorexit();
+}
+
+void
+main(int argc, char *argv[])
+{
+ int c;
+ char *a;
+
+ Binit(&bso, 1, OWRITE);
+ cout = -1;
+ listinit();
+ outfile = 0;
+ nerrors = 0;
+ curtext = P;
+ INITTEXT = -1;
+ INITDAT = -1;
+ HEADTYPE = -1;
+ INITTEXTP = -1;
+ INITRND = -1;
+ INITENTRY = 0;
+
+ ARGBEGIN {
+ default:
+ c = ARGC();
+ if(c >= 0 && c < sizeof(debug))
+ debug[c]++;
+ break;
+ case 'o':
+ outfile = ARGF();
+ break;
+ case 'E':
+ a = ARGF();
+ if(a)
+ INITENTRY = a;
+ break;
+ case 'T':
+ a = ARGF();
+ if(a)
+ INITTEXT = atolwhex(a);
+ break;
+ case 'P':
+ a = ARGF();
+ if(a)
+ INITTEXTP = atolwhex(a);
+ break;
+ case 'D':
+ a = ARGF();
+ if(a)
+ INITDAT = atolwhex(a);
+ break;
+ case 'R':
+ a = ARGF();
+ if(a)
+ INITRND = atolwhex(a);
+ break;
+ case 'H':
+ a = ARGF();
+ if(a)
+ HEADTYPE = atolwhex(a);
+ break;
+ case 'L':
+ addlibpath(EARGF(usage()));
+ break;
+ } ARGEND
+
+ USED(argc);
+
+ if(*argv == 0)
+ usage();
+ if(!debug['9'] && !debug['U'] && !debug['B'])
+ debug[DEFAULT] = 1;
+ if(HEADTYPE == -1) {
+ if(debug['U'])
+ HEADTYPE = 0;
+ if(debug['B'])
+ HEADTYPE = 1;
+ if(debug['9'])
+ HEADTYPE = 2;
+ }
+ switch(HEADTYPE) {
+ default:
+ diag("unknown -H option");
+ errorexit();
+ case 0: /* no header */
+ case 6: /* no header, padded */
+ HEADR = 0L;
+ if(INITTEXT == -1)
+ INITTEXT = 0;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 4;
+ break;
+ case 2:
+ HEADR = 40L;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = 0x10000;
+ if(INITTEXT == -1)
+ INITTEXT = 0x10000+HEADR;
+ break;
+ }
+ if (INITTEXTP == -1)
+ INITTEXTP = INITTEXT;
+ if(INITDAT != 0 && INITRND != 0)
+ print("warning: -D%#llux is ignored because of -R%#llux\n",
+ INITDAT, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "HEADER = -H%d -T%#llux -D%#llux -R%#llux\n",
+ HEADTYPE, INITTEXT, INITDAT, INITRND);
+ Bflush(&bso);
+ zprg.as = AGOK;
+ zprg.reg = NREG;
+ zprg.from.name = D_NONE;
+ zprg.from.type = D_NONE;
+ zprg.from.reg = NREG;
+ zprg.to = zprg.from;
+ buildop();
+ histgen = 0;
+ textp = P;
+ datap = P;
+ pc = 0;
+ dtype = 4;
+ if(outfile == 0) {
+ static char name[20];
+
+ snprint(name, sizeof name, "%c.out", thechar);
+ outfile = name;
+ }
+ cout = create(outfile, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s: %r", outfile);
+ errorexit();
+ }
+ nuxiinit();
+
+ version = 0;
+ cbp = buf.cbuf;
+ cbc = sizeof(buf.cbuf);
+ firstp = prg();
+ lastp = firstp;
+
+ if(INITENTRY == 0) {
+ INITENTRY = "_main";
+ if(debug['p'])
+ INITENTRY = "_mainp";
+ if(!debug['l'])
+ lookup(INITENTRY, 0)->type = SXREF;
+ } else if(!(*INITENTRY >= '0' && *INITENTRY <= '9'))
+ lookup(INITENTRY, 0)->type = SXREF;
+
+ while(*argv)
+ objfile(*argv++);
+ if(!debug['l'])
+ loadlib();
+ firstp = firstp->link;
+ if(firstp == P)
+ goto out;
+ patch();
+ if(debug['p'])
+ if(debug['1'])
+ doprof1();
+ else
+ doprof2();
+ dodata();
+ follow();
+ if(firstp == P)
+ goto out;
+ noops();
+ span();
+ asmb();
+ undef();
+
+out:
+ if(debug['v']) {
+ Bprint(&bso, "%5.2f cpu time\n", cputime());
+ Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+ Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+ }
+ Bflush(&bso);
+ errorexit();
+}
+
+void
+addlibpath(char *arg)
+{
+ char **p;
+
+ if(nlibdir >= maxlibdir) {
+ if(maxlibdir == 0)
+ maxlibdir = 8;
+ else
+ maxlibdir *= 2;
+ p = malloc(maxlibdir*sizeof(*p));
+ if(p == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ memmove(p, libdir, nlibdir*sizeof(*p));
+ free(libdir);
+ libdir = p;
+ }
+ libdir[nlibdir++] = strdup(arg);
+}
+
+void
+loadlib(void)
+{
+ int i;
+ long h;
+ Sym *s;
+
+loop:
+ xrefresolv = 0;
+ for(i=0; i<libraryp; i++) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+ objfile(library[i]);
+ }
+ if(xrefresolv)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->type == SXREF)
+ goto loop;
+}
+
+void
+errorexit(void)
+{
+
+ if(nerrors) {
+ if(cout >= 0)
+ remove(outfile);
+ exits("error");
+ }
+ exits(0);
+}
+
+void
+objfile(char *file)
+{
+ vlong off, esym, cnt, l;
+ int f, work;
+ Sym *s;
+ char magbuf[SARMAG];
+ char name[100], pname[150];
+ struct ar_hdr arhdr;
+ char *e, *start, *stop;
+
+ if(file[0] == '-' && file[1] == 'l') {
+ if(debug['9'])
+ sprint(name, "/%s/lib/lib", thestring);
+ else
+ sprint(name, "/usr/%clib/lib", thechar);
+ strcat(name, file+2);
+ strcat(name, ".a");
+ file = name;
+ }
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+ Bflush(&bso);
+ f = open(file, 0);
+ if(f < 0) {
+ diag("cannot open file: %s", file);
+ errorexit();
+ }
+ l = read(f, magbuf, SARMAG);
+ if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+ /* load it as a regular file */
+ l = seek(f, 0L, 2);
+ seek(f, 0L, 0);
+ ldobj(f, l, file);
+ close(f);
+ return;
+ }
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file);
+ l = read(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
+ }
+ if(strncmp(arhdr.name, symname, strlen(symname))) {
+ diag("%s: first entry not symbol header", file);
+ goto out;
+ }
+
+ esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+ off = SARMAG + SAR_HDR;
+
+ /*
+ * just bang the whole symbol file into memory
+ */
+ seek(f, off, 0);
+ cnt = esym - off;
+ start = malloc(cnt + 10);
+ cnt = read(f, start, cnt);
+ if(cnt <= 0){
+ close(f);
+ return;
+ }
+ stop = &start[cnt];
+ memset(stop, 0, 10);
+
+ work = 1;
+ while(work){
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+ Bflush(&bso);
+ work = 0;
+ for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+ s = lookup(e+5, 0);
+ if(s->type != SXREF)
+ continue;
+ sprint(pname, "%s(%s)", file, s->name);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+ Bflush(&bso);
+ l = e[1] & 0xff;
+ l |= (e[2] & 0xff) << 8;
+ l |= (e[3] & 0xff) << 16;
+ l |= (e[4] & 0xff) << 24;
+ seek(f, l, 0);
+ /* need readn to read the dumps (at least) */
+ l = readn(f, &arhdr, SAR_HDR);
+ if(l != SAR_HDR)
+ goto bad;
+ if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+ goto bad;
+ l = atolwhex(arhdr.size);
+ ldobj(f, l, pname);
+ if(s->type == SXREF) {
+ diag("%s: failed to load: %s", file, s->name);
+ errorexit();
+ }
+ work = 1;
+ xrefresolv = 1;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: bad or out of date archive", file);
+out:
+ close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+ int i, c;
+ long l;
+ Sym *s;
+ Auto *u;
+
+ c = p[2];
+ if(c < 0 || c > NSYM){
+ print("sym out of range: %d\n", c);
+ p[0] = ALAST+1;
+ return 0;
+ }
+ a->type = p[0];
+ a->reg = p[1];
+ a->sym = h[c];
+ a->name = p[3];
+ c = 4;
+
+ if(a->reg < 0 || a->reg > NREG) {
+ print("register out of range %d\n", a->reg);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+ }
+
+ switch(a->type) {
+ default:
+ print("unknown type %d\n", a->type);
+ p[0] = ALAST+1;
+ return 0; /* force real diagnostic */
+
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_FCCREG:
+ case D_FCSREG:
+ break;
+
+ case D_BRANCH:
+ case D_OREG:
+ case D_CONST:
+ case D_OCONST:
+ l = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
+ a->offset = l;
+ c += 4;
+ break;
+
+ case D_SCONST:
+ a->sval = malloc(NSNAME);
+ memmove(a->sval, p+4, NSNAME);
+ c += NSNAME;
+ break;
+
+ case D_FCONST:
+ a->ieee = malloc(sizeof(Ieee));
+ a->ieee->l = p[4] | (p[5]<<8) |
+ (p[6]<<16) | (p[7]<<24);
+ a->ieee->h = p[8] | (p[9]<<8) |
+ (p[10]<<16) | (p[11]<<24);
+ c += 8;
+ break;
+
+ case D_VCONST:
+ l = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
+ a->offset = (uvlong)l & 0xfffffffful;
+ l = p[8] | (p[9]<<8) | (p[10]<<16) | (p[11]<<24);
+ a->offset |= (vlong)l << 32;
+ c += 8;
+ a->type = D_CONST;
+ break;
+ }
+ s = a->sym;
+ if(s == S)
+ return c;
+ i = a->name;
+ if(i != D_AUTO && i != D_PARAM)
+ return c;
+
+ l = a->offset;
+ for(u=curauto; u; u=u->link)
+ if(u->asym == s)
+ if(u->type == i) {
+ if(u->aoffset > l)
+ u->aoffset = l;
+ return c;
+ }
+
+ u = malloc(sizeof(Auto));
+ memset(u, 0, sizeof(Auto));
+ u->link = curauto;
+ curauto = u;
+ u->asym = s;
+ u->aoffset = l;
+ u->type = i;
+ return c;
+}
+
+void
+addlib(char *obj)
+{
+ char fn1[LIBNAMELEN], comp[LIBNAMELEN], *p, *name;
+ int i, search;
+
+ if(histfrogp <= 0)
+ return;
+
+ name = fn1;
+ search = 0;
+ if(histfrog[0]->name[1] == '/') {
+ sprint(name, "");
+ i = 1;
+ } else if(histfrog[0]->name[1] == '.') {
+ sprint(name, ".");
+ i = 0;
+ } else {
+ sprint(name, "");
+ i = 0;
+ search = 1;
+ }
+
+ for(; i<histfrogp; i++) {
+ snprint(comp, sizeof comp, histfrog[i]->name+1);
+ for(;;) {
+ p = strstr(comp, "$O");
+ if(p == 0)
+ break;
+ memmove(p+1, p+2, strlen(p+2)+1);
+ p[0] = thechar;
+ }
+ for(;;) {
+ p = strstr(comp, "$M");
+ if(p == 0)
+ break;
+ if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+ diag("library component too long");
+ return;
+ }
+ memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+ memmove(p, thestring, strlen(thestring));
+ }
+ if(strlen(fn1) + strlen(comp) + 3 >= sizeof(fn1)) {
+ diag("library component too long");
+ return;
+ }
+ if(i > 0 || !search)
+ strcat(fn1, "/");
+ strcat(fn1, comp);
+ }
+ for(i=0; i<libraryp; i++)
+ if(strcmp(name, library[i]) == 0)
+ return;
+ if(libraryp == nelem(library)){
+ diag("too many autolibs; skipping %s", name);
+ return;
+ }
+
+ p = malloc(strlen(name) + 1);
+ strcpy(p, name);
+ library[libraryp] = p;
+ p = malloc(strlen(obj) + 1);
+ strcpy(p, obj);
+ libraryobj[libraryp] = p;
+ libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+ Auto *u;
+ Sym *s;
+ int i, j, k;
+
+ u = malloc(sizeof(Auto));
+ s = malloc(sizeof(Sym));
+ s->name = malloc(2*(histfrogp+1) + 1);
+
+ u->asym = s;
+ u->type = type;
+ u->aoffset = line;
+ u->link = curhist;
+ curhist = u;
+
+ j = 1;
+ for(i=0; i<histfrogp; i++) {
+ k = histfrog[i]->value;
+ s->name[j+0] = k>>8;
+ s->name[j+1] = k;
+ j += 2;
+ }
+}
+
+void
+histtoauto(void)
+{
+ Auto *l;
+
+ while(l = curhist) {
+ curhist = l->link;
+ l->link = curauto;
+ curauto = l;
+ }
+}
+
+void
+collapsefrog(Sym *s)
+{
+ int i;
+
+ /*
+ * bad encoding of path components only allows
+ * MAXHIST components. if there is an overflow,
+ * first try to collapse xxx/..
+ */
+ for(i=1; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, "..") == 0) {
+ memmove(histfrog+i-1, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ histfrogp--;
+ goto out;
+ }
+
+ /*
+ * next try to collapse .
+ */
+ for(i=0; i<histfrogp; i++)
+ if(strcmp(histfrog[i]->name+1, ".") == 0) {
+ memmove(histfrog+i, histfrog+i+1,
+ (histfrogp-i-1)*sizeof(histfrog[0]));
+ goto out;
+ }
+
+ /*
+ * last chance, just truncate from front
+ */
+ memmove(histfrog+0, histfrog+1,
+ (histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+ histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+ p->from.type = D_NONE;
+ p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+ int n;
+
+ n = stop - good;
+ memmove(buf, good, stop - good);
+ stop = buf + n;
+ n = MAXIO - n;
+ if(n > max)
+ n = max;
+ n = read(f, stop, n);
+ if(n <= 0)
+ return 0;
+ return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+ vlong ipc;
+ Prog *p, *t;
+ uchar *bloc, *bsize, *stop;
+ Sym *h[NSYM], *s, *di;
+ int v, o, r, skip;
+
+ bsize = buf.xbuf;
+ bloc = buf.xbuf;
+ di = S;
+
+newloop:
+ memset(h, 0, sizeof(h));
+ version++;
+ histfrogp = 0;
+ ipc = pc;
+ skip = 0;
+
+loop:
+ if(c <= 0)
+ goto eof;
+ r = bsize - bloc;
+ if(r < 100 && r < c) { /* enough for largest prog */
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ goto loop;
+ }
+ o = bloc[0]; /* as */
+ if(o <= AXXX || o >= ALAST) {
+ diag("%s: line %lld: opcode out of range %d", pn, pc-ipc, o);
+ print(" probably not a .%c file\n", thechar);
+ errorexit();
+ }
+ if(o == ANAME || o == ASIGNAME) {
+ if(o == ASIGNAME) {
+ bloc += 4;
+ c -= 4;
+ }
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+ if(bsize == 0)
+ goto eof;
+ bloc = buf.xbuf;
+ stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
+ if(stop == 0){
+ fprint(2, "%s: name too long\n", pn);
+ errorexit();
+ }
+ }
+ v = bloc[1]; /* type */
+ o = bloc[2]; /* sym */
+ bloc += 3;
+ c -= 3;
+
+ r = 0;
+ if(v == D_STATIC)
+ r = version;
+ s = lookup((char*)bloc, r);
+ c -= &stop[1] - bloc;
+ bloc = stop + 1;
+
+ if(debug['W'])
+ print(" ANAME %s\n", s->name);
+ h[o] = s;
+ if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+ s->type = SXREF;
+ if(v == D_FILE) {
+ if(s->type != SFILE) {
+ histgen++;
+ s->type = SFILE;
+ s->value = histgen;
+ }
+ if(histfrogp < MAXHIST) {
+ histfrog[histfrogp] = s;
+ histfrogp++;
+ } else
+ collapsefrog(s);
+ }
+ goto loop;
+ }
+
+ p = prg();
+ p->as = o;
+ p->reg = bloc[1] & 0x7f;
+ p->line = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+
+ r = zaddr(bloc+6, &p->from, h) + 6;
+ r += zaddr(bloc+r, &p->to, h);
+ bloc += r;
+ c -= r;
+
+ if(p->reg < 0 || p->reg > NREG)
+ diag("register out of range %d", p->reg);
+
+ p->link = P;
+ p->cond = P;
+
+ if(debug['W'])
+ print("%P\n", p);
+
+ switch(o) {
+ case AHISTORY:
+ if(p->to.offset == -1) {
+ addlib(pn);
+ histfrogp = 0;
+ goto loop;
+ }
+ addhist(p->line, D_FILE); /* 'z' */
+ if(p->to.offset)
+ addhist(p->to.offset, D_FILE1); /* 'Z' */
+ histfrogp = 0;
+ goto loop;
+
+ case AEND:
+ histtoauto();
+ if(curtext != P)
+ curtext->to.autom = curauto;
+ curauto = 0;
+ curtext = P;
+ if(c)
+ goto newloop;
+ return;
+
+ case AGLOBL:
+ s = p->from.sym;
+ if(s == S) {
+ diag("GLOBL must have a name\n%P", p);
+ errorexit();
+ }
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(s->type != SBSS) {
+ diag("redefinition: %s\n%P", s->name, p);
+ s->type = SBSS;
+ s->value = 0;
+ }
+ if(p->to.offset > s->value)
+ s->value = p->to.offset;
+ break;
+
+ case ADYNT:
+ if(p->to.sym == S) {
+ diag("DYNT without a sym\n%P", p);
+ break;
+ }
+ di = p->to.sym;
+ p->reg = 4;
+ if(di->type == SXREF) {
+ if(debug['z'])
+ Bprint(&bso, "%P set to %d\n", p, dtype);
+ di->type = SCONST;
+ di->value = dtype;
+ dtype += 4;
+ }
+ if(p->from.sym == S)
+ break;
+
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ if(curtext == P) {
+ diag("DYNT not in text: %P", p);
+ break;
+ }
+ p->to.sym = curtext->from.sym;
+ p->to.type = D_CONST;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AINIT:
+ if(p->from.sym == S) {
+ diag("INIT without a sym\n%P", p);
+ break;
+ }
+ if(di == S) {
+ diag("INIT without previous DYNT\n%P", p);
+ break;
+ }
+ p->from.offset = di->value;
+ p->from.sym->type = SDATA;
+ p->link = datap;
+ datap = p;
+ break;
+
+ case ADATA:
+ if(p->from.sym == S) {
+ diag("DATA without a sym\n%P", p);
+ break;
+ }
+ p->link = datap;
+ datap = p;
+ break;
+
+ case AGOK:
+ diag("unknown opcode\n%P", p);
+ p->pc = pc;
+ pc++;
+ break;
+
+ case ATEXT:
+ if(curtext != P) {
+ histtoauto();
+ curtext->to.autom = curauto;
+ curauto = 0;
+ }
+ skip = 0;
+ curtext = p;
+ s = p->from.sym;
+ if(s == S) {
+ diag("TEXT must have a name\n%P", p);
+ errorexit();
+ }
+ autosize = p->to.offset;
+ if(autosize & 7) {
+ diag("stack frame not 8 multiple: %s\n%P", s->name, p);
+ autosize = autosize + 7 & ~7;
+ p->to.offset = autosize;
+ }
+ autosize += 8;
+ if(s->type != 0 && s->type != SXREF) {
+ if(p->reg & DUPOK) {
+ skip = 1;
+ goto casedef;
+ }
+ diag("redefinition: %s\n%P", s->name, p);
+ }
+ s->type = STEXT;
+ s->value = pc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ if(textp == P) {
+ textp = p;
+ etextp = p;
+ goto loop;
+ }
+ etextp->cond = p;
+ etextp = p;
+ break;
+
+ case ASUB:
+ case ASUBU:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE) {
+ p->from.offset = -p->from.offset;
+ if(p->as == ASUB)
+ p->as = AADD;
+ else
+ p->as = AADDU;
+ }
+ goto casedef;
+
+ case ASUBV:
+ case ASUBVU:
+ if(p->from.type == D_CONST)
+ if(p->from.name == D_NONE) {
+ p->from.offset = -p->from.offset;
+ if(p->as == ASUBV)
+ p->as = AADDV;
+ else
+ p->as = AADDVU;
+ }
+ goto casedef;
+
+ case AMOVF:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 9 max */
+ sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 4;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 4;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVD:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_FCONST) {
+ /* size sb 18 max */
+ sprint(literal, "$%lux.%lux",
+ p->from.ieee->l, p->from.ieee->h);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ case AMOVV:
+ if(skip)
+ goto casedef;
+
+ if(p->from.type == D_CONST)
+ if(!isint32(p->from.offset)) {
+ /* size sb 18 max */
+ sprint(literal, "$%llux", p->from.offset);
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SBSS;
+ s->value = 8;
+ t = prg();
+ t->as = ADATA;
+ t->line = p->line;
+ t->from.type = D_OREG;
+ t->from.sym = s;
+ t->from.name = D_EXTERN;
+ t->reg = 8;
+ t->to = p->from;
+ t->link = datap;
+ datap = t;
+ }
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ }
+ goto casedef;
+
+ default:
+ casedef:
+ if(skip)
+ nopout(p);
+
+ if(p->to.type == D_BRANCH)
+ p->to.offset += ipc;
+ lastp->link = p;
+ lastp = p;
+ p->pc = pc;
+ pc++;
+ break;
+ }
+ goto loop;
+
+eof:
+ diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+ Sym *s;
+ char *p;
+ long h;
+ int c, l;
+
+ h = v;
+ for(p=symb; c = *p; p++)
+ h = h+h+h + c;
+ l = (p - symb) + 1;
+ if(h < 0)
+ h = ~h;
+ h &= 0xffffff; // XXX
+ h %= NHASH;
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->version == v)
+ if(memcmp(s->name, symb, l) == 0)
+ return s;
+
+ s = malloc(sizeof(Sym));
+ memset(s, 0, sizeof(Sym));
+ s->name = malloc(l);
+ memmove(s->name, symb, l);
+
+ s->link = hash[h];
+ s->type = 0;
+ s->version = v;
+ s->value = 0;
+ hash[h] = s;
+ return s;
+}
+
+Prog*
+prg(void)
+{
+ Prog *p = malloc(sizeof(Prog));
+ *p = zprg;
+ return p;
+}
+
+void
+doprof1(void)
+{
+ Sym *s;
+ long n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDU;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *q2, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ if(debug['e']){
+ s2 = lookup("_tracein", 0);
+ s4 = lookup("_traceout", 0);
+ }else{
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ }
+ if(s2->type != STEXT || s4->type != STEXT) {
+ if(debug['e'])
+ diag("_tracein/_traceout not defined %d %d", s2->type, s4->type);
+ else
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->from.sym == s2) {
+ ps2 = p;
+ p->reg = 1;
+ }
+ if(p->from.sym == s4) {
+ ps4 = p;
+ p->reg = 1;
+ }
+ }
+ }
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ if(p->reg & NOPROF) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * JAL profin, R2
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ if(debug['e']){ /* embedded tracing */
+ q2 = prg();
+ p->link = q2;
+ q2->link = q;
+
+ q2->line = p->line;
+ q2->pc = p->pc;
+
+ q2->as = AJMP;
+ q2->to.type = D_BRANCH;
+ q2->to.sym = p->to.sym;
+ q2->cond = q->link;
+ }else
+ p->link = q;
+ p = q;
+ p->as = AJAL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET (default)
+ */
+ if(debug['e']){ /* embedded tracing */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ }
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = AJAL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
+
+void
+nuxiinit(void)
+{
+ int i, c;
+
+ for(i=0; i<4; i++){
+ c = find1(0x04030201L, i+1);
+ if(i < 2)
+ inuxi2[i] = c;
+ if(i < 1)
+ inuxi1[i] = c;
+ inuxi4[i] = c;
+ inuxi8[i] = c;
+ inuxi8[i+4] = c+4;
+ fnuxi4[i] = c;
+ fnuxi8[i] = c;
+ fnuxi8[i+4] = c+4;
+ }
+ if(debug['v']) {
+ Bprint(&bso, "inuxi = ");
+ for(i=0; i<1; i++)
+ Bprint(&bso, "%d", inuxi1[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<2; i++)
+ Bprint(&bso, "%d", inuxi2[i]);
+ Bprint(&bso, " ");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", inuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", inuxi8[i]);
+ Bprint(&bso, "\n");
+ for(i=0; i<4; i++)
+ Bprint(&bso, "%d", fnuxi4[i]);
+ Bprint(&bso, "\nfnuxi = ");
+ for(i=0; i<8; i++)
+ Bprint(&bso, "%d", fnuxi8[i]);
+ Bprint(&bso, "\n");
+ }
+ Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+ char *p;
+ int i;
+
+ p = (char*)&l;
+ for(i=0; i<4; i++)
+ if(*p++ == c)
+ return i;
+ return 0;
+}
+
+vlong
+ieeedtov(Ieee *ieeep)
+{
+ vlong v;
+
+ v = (vlong)ieeep->l & 0xffffffffLL;
+ v |= (vlong)ieeep->h << 32;
+ return v;
+}
+
+long
+ieeedtof(Ieee *ieeep)
+{
+ int exp;
+ long v;
+
+ if(ieeep->h == 0)
+ return 0;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ v = (ieeep->h & 0xfffffL) << 3;
+ v |= (ieeep->l >> 29) & 0x7L;
+ if((ieeep->l >> 28) & 1) {
+ v++;
+ if(v & 0x800000L) {
+ v = (v & 0x7fffffL) >> 1;
+ exp++;
+ }
+ }
+ if(exp <= -126 || exp >= 130)
+ diag("double fp to single fp overflow");
+ v |= ((exp + 126) & 0xffL) << 23;
+ v |= ieeep->h & 0x80000000L;
+ return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+ Ieee e;
+ double fr;
+ int exp;
+
+ if(ieeep->h & (1L<<31)) {
+ e.h = ieeep->h & ~(1L<<31);
+ e.l = ieeep->l;
+ return -ieeedtod(&e);
+ }
+ if(ieeep->l == 0 && ieeep->h == 0)
+ return 0;
+ fr = ieeep->l & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->l>>16) & ((1L<<16)-1L);
+ fr /= 1L<<16;
+ fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+ fr /= 1L<<21;
+ exp = (ieeep->h>>20) & ((1L<<11)-1L);
+ exp -= (1L<<10) - 2L;
+ return ldexp(fr, exp);
+}
--- /dev/null
+++ b/sys/src/cmd/zl/optab.c
@@ -1,0 +1,216 @@
+#include "l.h"
+
+Optab optab[] =
+{
+ { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_REG, 14, 8, 0 },
+ { AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0 },
+ { AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0 },
+ { AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0 },
+ { AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0 },
+
+ { ASUB, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AAND, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { ASUB, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AADD, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AAND, C_REG, C_NONE, C_REG, 2, 4, 0 },
+
+ { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 },
+ { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 },
+
+ { AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0 },
+ { AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0 },
+ { ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0 },
+ { AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+ { AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+ { AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB },
+ { AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+
+ { AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVV, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVB, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVBU, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVWL, C_SAUTO,C_NONE, C_REG, 8, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVV, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVB, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVBU, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+ { AMOVWL, C_SOREG,C_NONE, C_REG, 8, 4, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVV, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVB, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVBU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB },
+ { AMOVW, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVV, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVB, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP },
+ { AMOVW, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVV, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVB, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+ { AMOVBU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO },
+
+ { AMOVW, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVV, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVB, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVBU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVV, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVBU, C_LAUTO,C_NONE, C_REG, 36, 16, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVV, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+ { AMOVBU, C_LOREG,C_NONE, C_REG, 36, 16, REGZERO },
+
+ { AMOVW, C_SECON,C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVV, C_SECON,C_NONE, C_REG, 3, 4, REGSB },
+ { AMOVW, C_SACON,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVV, C_SACON,C_NONE, C_REG, 3, 4, REGSP },
+ { AMOVW, C_LECON,C_NONE, C_REG, 26, 12, REGSB },
+ { AMOVV, C_LECON,C_NONE, C_REG, 26, 12, REGSB },
+ { AMOVW, C_LACON,C_NONE, C_REG, 26, 12, REGSP },
+ { AMOVV, C_LACON,C_NONE, C_REG, 26, 12, REGSP },
+ { AMOVW, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVV, C_ADDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVW, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO },
+ { AMOVV, C_ANDCON,C_NONE,C_REG, 3, 4, REGZERO },
+
+ { AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0 },
+ { AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0 },
+ { AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0 },
+
+ { AMUL, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AMUL, C_REG, C_REG, C_REG, 2, 4, 0 },
+ { AMULV, C_REG, C_NONE, C_REG, 2, 4, 0 },
+ { AMULV, C_REG, C_REG, C_REG, 2, 4, 0 },
+
+ { AADD, C_ADD0CON,C_REG,C_REG, 4, 4, 0 },
+ { AADD, C_ADD0CON,C_NONE,C_REG, 4, 4, 0 },
+ { AADD, C_ANDCON,C_REG, C_REG, 10, 8, 0 },
+ { AADD, C_ANDCON,C_NONE,C_REG, 10, 8, 0 },
+
+ { AAND, C_AND0CON,C_REG,C_REG, 4, 4, 0 },
+ { AAND, C_AND0CON,C_NONE,C_REG, 4, 4, 0 },
+ { AAND, C_ADDCON,C_REG, C_REG, 10, 8, 0 },
+ { AAND, C_ADDCON,C_NONE,C_REG, 10, 8, 0 },
+
+ { AADD, C_UCON, C_REG, C_REG, 25, 8, 0 },
+ { AADD, C_UCON, C_NONE, C_REG, 25, 8, 0 },
+ { AAND, C_UCON, C_REG, C_REG, 25, 8, 0 },
+ { AAND, C_UCON, C_NONE, C_REG, 25, 8, 0 },
+
+ { AADD, C_LCON, C_NONE, C_REG, 23, 12, 0 },
+ { AAND, C_LCON, C_NONE, C_REG, 23, 12, 0 },
+ { AADD, C_LCON, C_REG, C_REG, 23, 12, 0 },
+ { AAND, C_LCON, C_REG, C_REG, 23, 12, 0 },
+
+ { ASLL, C_SCON, C_REG, C_REG, 16, 4, 0 },
+ { ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0 },
+
+ { ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0 },
+ { ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0 },
+ { ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0 },
+ { ABFPT, C_NONE, C_NONE, C_SBRA, 6, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+ { AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0 },
+
+ { AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO },
+ { AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK },
+
+ { AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB },
+ { AMOVW, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVF, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVD, C_SAUTO,C_NONE, C_FREG, 27, 4, REGSP },
+ { AMOVW, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+ { AMOVF, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+ { AMOVD, C_SOREG,C_NONE, C_FREG, 27, 4, REGZERO },
+
+ { AMOVW, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVF, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVD, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB },
+ { AMOVW, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVF, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVD, C_LAUTO,C_NONE, C_FREG, 27, 16, REGSP },
+ { AMOVW, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+ { AMOVF, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+ { AMOVD, C_LOREG,C_NONE, C_FREG, 27, 16, REGZERO },
+
+ { AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+ { AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+ { AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO },
+
+ { AMOVW, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVF, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVD, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB },
+ { AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP },
+ { AMOVW, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+ { AMOVF, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+ { AMOVD, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0 },
+ { AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0 },
+
+ { AMOVW, C_ADDCON,C_NONE,C_FREG, 34, 8, 0 },
+ { AMOVW, C_ANDCON,C_NONE,C_FREG, 34, 8, 0 },
+ { AMOVW, C_UCON, C_NONE, C_FREG, 35, 8, 0 },
+ { AMOVW, C_LCON, C_NONE, C_FREG, 36, 12, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCCREG, 37, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_FCCREG, 37, 4, 0 },
+ { AMOVW, C_FCCREG,C_NONE,C_REG, 38, 4, 0 },
+ { AMOVV, C_FCCREG,C_NONE,C_REG, 38, 4, 0 },
+
+ { AWORD, C_NONE, C_NONE, C_LCON, 40, 4, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FCSREG, 41, 4, 0 },
+ { AMOVV, C_REG, C_NONE, C_FCSREG, 41, 4, 0 },
+ { AMOVW, C_FCSREG,C_NONE,C_REG, 42, 4, 0 },
+ { AMOVV, C_FCSREG,C_NONE,C_REG, 42, 4, 0 },
+
+ { ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB }, /* really CACHE instruction */
+ { ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP },
+ { ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO },
+ { ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0 },
+
+ { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
+};
--- /dev/null
+++ b/sys/src/cmd/zl/pass.c
@@ -1,0 +1,534 @@
+#include "l.h"
+
+void
+dodata(void)
+{
+ int i, t;
+ Sym *s;
+ Prog *p, *p1;
+ vlong orig, orig1, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->as == ADYNT || p->as == AINIT)
+ s->value = dtype;
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type != SDATA)
+ diag("initialize non-data (%d): %s\n%P",
+ s->type, s->name, p);
+ v = p->from.offset + p->reg;
+ if(v > s->value)
+ diag("initialize bounds (%lld): %s\n%P",
+ s->value, s->name, p);
+ }
+
+ if(debug['t']) {
+ /*
+ * pull out string constants
+ */
+ for(p = datap; p != P; p = p->link) {
+ s = p->from.sym;
+ if(p->to.type == D_SCONST)
+ s->type = SSTRING;
+ }
+ }
+
+ /*
+ * pass 1
+ * assign 'small' variables to data segment
+ * (rational is that data segment is more easily
+ * addressed through offset on R30)
+ */
+ orig = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA && t != SBSS)
+ continue;
+ v = s->value;
+ if(v == 0) {
+ diag("%s: no size", s->name);
+ v = 1;
+ }
+ while(v & 7)
+ v++;
+ s->value = v;
+ if(v > MINSIZ)
+ continue;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+ orig1 = orig;
+
+ /*
+ * pass 2
+ * assign 'data' variables to data segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t != SDATA) {
+ if(t == SDATA1)
+ s->type = SDATA;
+ continue;
+ }
+ v = s->value;
+ while(v & 7)
+ v++;
+ s->value = orig;
+ orig += v;
+ s->type = SDATA1;
+ }
+
+ while(orig & 7)
+ orig++;
+ datsize = orig;
+
+ /*
+ * pass 3
+ * everything else to bss segment
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SBSS)
+ continue;
+ v = s->value;
+ while(v & 7)
+ v++;
+ s->value = orig;
+ orig += v;
+ }
+ while(orig & 7)
+ orig++;
+ bsssize = orig-datsize;
+
+ /*
+ * pass 4
+ * add literals to all large values.
+ * at this time:
+ * small data is allocated DATA
+ * large data is allocated DATA1
+ * large bss is allocated BSS
+ * the new literals are loaded between
+ * small data and large data.
+ */
+ orig = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as != AMOVW)
+ continue;
+ if(p->from.type != D_CONST)
+ continue;
+ if(s = p->from.sym) {
+ t = s->type;
+ if(t != SDATA && t != SDATA1 && t != SBSS)
+ continue;
+ t = p->from.name;
+ if(t != D_EXTERN && t != D_STATIC)
+ continue;
+ v = s->value + p->from.offset;
+ if(v >= 0 && v <= 0xfff)
+ continue;
+ if(!strcmp(s->name, "setSB"))
+ continue;
+ /* size should be 19 max */
+ if(strlen(s->name) >= 10) /* has loader address */
+ sprint(literal, "$%p.%llux", s, p->from.offset);
+ else
+ sprint(literal, "$%s.%d.%llux", s->name,
+ s->version, p->from.offset);
+ } else {
+ if(p->from.name != D_NONE)
+ continue;
+ if(p->from.reg != NREG)
+ continue;
+ v = p->from.offset;
+ if(v >= -0x7ff && v <= 0xfff)
+ continue;
+ if(!(v & 0xfff))
+ continue;
+ /* size should be 9 max */
+ sprint(literal, "$%llux", v);
+ }
+ s = lookup(literal, 0);
+ if(s->type == 0) {
+ s->type = SDATA;
+ s->value = orig1+orig;
+ orig += 8;
+ p1 = prg();
+ p1->line = p->line;
+ p1->as = ADATA;
+ p1->from.type = D_OREG;
+ p1->from.sym = s;
+ p1->from.name = D_EXTERN;
+ p1->reg = 4;
+ p1->to = p->from;
+ p1->link = datap;
+ datap = p1;
+ }
+ if(s->type != SDATA)
+ diag("literal not data: %s", s->name);
+ p->from.type = D_OREG;
+ p->from.sym = s;
+ p->from.name = D_EXTERN;
+ p->from.offset = 0;
+ nocache(p);
+ continue;
+ }
+ while(orig & 7)
+ orig++;
+ /*
+ * pass 5
+ * re-adjust offsets
+ */
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ t = s->type;
+ if(t == SBSS) {
+ s->value += orig;
+ continue;
+ }
+ if(t == SDATA1) {
+ s->type = SDATA;
+ s->value += orig;
+ continue;
+ }
+ }
+ datsize += orig;
+ xdefine("setSB", SDATA, 0L);
+ xdefine("bdata", SDATA, 0L);
+ xdefine("edata", SDATA, datsize);
+ xdefine("end", SBSS, datsize+bsssize);
+ xdefine("etext", STEXT, 0L);
+}
+
+void
+undef(void)
+{
+ int i;
+ Sym *s;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link)
+ if(s->type == SXREF)
+ diag("%s: not defined", s->name);
+}
+
+void
+follow(void)
+{
+ if(debug['v'])
+ Bprint(&bso, "%5.2f follow\n", cputime());
+ Bflush(&bso);
+
+ firstp = prg();
+ lastp = firstp;
+ xfol(textp);
+
+ firstp = firstp->link;
+ lastp->link = P;
+}
+
+void
+xfol(Prog *p)
+{
+ Prog *q, *r;
+ int a, i;
+
+loop:
+ if(p == P)
+ return;
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if(a == AJMP) {
+ q = p->cond;
+ if(q != P) {
+ p->mark |= FOLL;
+ p = q;
+ if(!(p->mark & FOLL))
+ goto loop;
+ }
+ }
+ if(p->mark & FOLL) {
+ for(i=0,q=p; i<4; i++,q=q->link) {
+ if(q == lastp)
+ break;
+ a = q->as;
+ if(a == ANOP) {
+ i--;
+ continue;
+ }
+ if(a == AJMP || a == ARET)
+ goto copy;
+ if(!q->cond || (q->cond->mark&FOLL))
+ continue;
+ if(a != ABEQ && a != ABNE)
+ continue;
+ copy:
+ for(;;) {
+ r = prg();
+ *r = *p;
+ if(!(r->mark&FOLL))
+ print("cant happen 1\n");
+ r->mark |= FOLL;
+ if(p != q) {
+ p = p->link;
+ lastp->link = r;
+ lastp = r;
+ continue;
+ }
+ lastp->link = r;
+ lastp = r;
+ if(a == AJMP || a == ARET)
+ return;
+ r->as = ABNE;
+ if(a == ABNE)
+ r->as = ABEQ;
+ r->cond = p->link;
+ r->link = p->cond;
+ if(!(r->link->mark&FOLL))
+ xfol(r->link);
+ if(!(r->cond->mark&FOLL))
+ print("cant happen 2\n");
+ return;
+ }
+ }
+ a = AJMP;
+ q = prg();
+ q->as = a;
+ q->line = p->line;
+ q->to.type = D_BRANCH;
+ q->to.offset = p->pc;
+ q->cond = p;
+ p = q;
+ }
+ p->mark |= FOLL;
+ lastp->link = p;
+ lastp = p;
+ if(a == AJMP || a == ARET)
+ return;
+ if(p->cond != P)
+ if(a != AJAL && p->link != P) {
+ xfol(p->link);
+ p = p->cond;
+ if(p == P || (p->mark&FOLL))
+ return;
+ goto loop;
+ }
+ p = p->link;
+ goto loop;
+}
+
+void
+patch(void)
+{
+ vlong c, vexit;
+ Prog *p, *q;
+ Sym *s;
+ int a;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f patch\n", cputime());
+ Bflush(&bso);
+ mkfwd();
+ s = lookup("exit", 0);
+ vexit = s->value;
+ for(p = firstp; p != P; p = p->link) {
+ a = p->as;
+ if(a == ATEXT)
+ curtext = p;
+ if((a == AJAL || a == AJMP || a == ARET) &&
+ p->to.type != D_BRANCH && p->to.sym != S) {
+ s = p->to.sym;
+ if(s->type != STEXT) {
+ diag("undefined: %s\n%P", s->name, p);
+ s->type = STEXT;
+ s->value = vexit;
+ }
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ }
+ if(p->to.type != D_BRANCH)
+ continue;
+ c = p->to.offset;
+ for(q = firstp; q != P;) {
+ if(q->forwd != P)
+ if(c >= q->forwd->pc) {
+ q = q->forwd;
+ continue;
+ }
+ if(c == q->pc)
+ break;
+ q = q->link;
+ }
+ if(q == P) {
+ diag("branch out of range %lld\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
+ }
+
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ if(p->cond != P) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
+ }
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ long dwn[LOG], cnt[LOG], i;
+ Prog *lst[LOG];
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1; else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ for(p = firstp; p != P; p = p->link) {
+ if(p->as == ATEXT)
+ curtext = p;
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+}
+
+Prog*
+brloop(Prog *p)
+{
+ Prog *q;
+ int c;
+
+ for(c=0; p!=P;) {
+ if(p->as != AJMP)
+ return p;
+ q = p->cond;
+ if(q <= p) {
+ c++;
+ if(q == p || c > 5000)
+ break;
+ }
+ p = q;
+ }
+ return P;
+}
+
+vlong
+atolwhex(char *s)
+{
+ vlong n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+vlong
+atovlwhex(char *s)
+{
+ vlong n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+vlong
+rnd(vlong v, long r)
+{
+ vlong c;
+
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
+}
--- /dev/null
+++ b/sys/src/cmd/zl/span.c
@@ -1,0 +1,651 @@
+#include "l.h"
+
+void
+span(void)
+{
+ Prog *p, *q;
+ Sym *setext, *s;
+ Optab *o;
+ int m, bflag, i;
+ vlong c, otxt, v;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
+ Bflush(&bso);
+
+ bflag = 0;
+ c = INITTEXT;
+ otxt = c;
+ for(p = firstp; p != P; p = p->link) {
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 8;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+
+ /*
+ * if any procedure is large enough to
+ * generate a large SBRA branch, then
+ * generate extra passes putting branches
+ * around jmps to fix. this is rare.
+ */
+ while(bflag) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span1\n", cputime());
+ bflag = 0;
+ c = INITTEXT;
+ for(p = firstp; p != P; p = p->link) {
+ p->pc = c;
+ o = oplook(p);
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AJMP;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AJMP;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ addnop(p->link);
+ addnop(p);
+ bflag = 1;
+ }
+ }
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ curtext = p;
+ autosize = p->to.offset + 8;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
+ continue;
+ }
+ c += m;
+ }
+ }
+
+ if(debug['t']) {
+ /*
+ * add strings to text segment
+ */
+ c = rnd(c, 8);
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->link) {
+ if(s->type != SSTRING)
+ continue;
+ v = s->value;
+ while(v & 3)
+ v++;
+ s->value = c;
+ c += v;
+ }
+ }
+
+ c = rnd(c, 8);
+
+ setext = lookup("etext", 0);
+ if(setext != S) {
+ setext->value = c;
+ textsize = c - INITTEXT;
+ }
+ if(INITRND)
+ INITDAT = rnd(c, INITRND);
+ if(debug['v'])
+ Bprint(&bso, "tsize = %llux\n", textsize);
+ Bflush(&bso);
+}
+
+void
+xdefine(char *p, int t, vlong v)
+{
+ Sym *s;
+
+ s = lookup(p, 0);
+ if(s->type == 0 || s->type == SXREF) {
+ s->type = t;
+ s->value = v;
+ }
+}
+
+long
+regoff(Adr *a)
+{
+
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+vlong
+vregoff(Adr *a)
+{
+ instoffset = 0;
+ aclass(a);
+ return instoffset;
+}
+
+int
+isint32(vlong v)
+{
+ long l;
+
+ l = v;
+ return (vlong)l == v;
+}
+
+int
+isuint32(uvlong v)
+{
+ ulong l;
+
+ l = v;
+ return (uvlong)l == v;
+}
+
+int
+aclass(Adr *a)
+{
+ Sym *s;
+ int t;
+
+ switch(a->type) {
+ case D_NONE:
+ return C_NONE;
+
+ case D_REG:
+ return C_REG;
+
+ case D_FREG:
+ return C_FREG;
+
+ case D_FCCREG:
+ return C_FCCREG;
+
+ case D_FCSREG:
+ return C_FCSREG;
+
+ case D_OREG:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ if(a->sym == 0 || a->sym->name == 0) {
+ print("null sym external\n");
+ print("%D\n", a);
+ return C_GOK;
+ }
+ t = a->sym->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ a->sym->name, TNAME);
+ a->sym->type = SDATA;
+ }
+ instoffset = a->sym->value + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SEXT;
+ return C_LEXT;
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 8L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SAUTO;
+ return C_LAUTO;
+ case D_NONE:
+ instoffset = a->offset;
+ if(instoffset == 0)
+ return C_ZOREG;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SOREG;
+ return C_LOREG;
+ }
+ return C_GOK;
+
+ case D_OCONST:
+ switch(a->name) {
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ t = s->type;
+ if(t == 0 || t == SXREF) {
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ if(s->type == STEXT || s->type == SLEAF)
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ return C_GOK;
+
+ case D_CONST:
+ switch(a->name) {
+ case D_NONE:
+ instoffset = a->offset;
+ consize:
+ if(instoffset > 0) {
+ if(instoffset <= 0x7ff)
+ return C_SCON;
+ if(instoffset <= 0xfff)
+ return C_ANDCON;
+ if((instoffset & 0xfff) == 0 && isuint32(instoffset))
+ return C_UCON;
+ return C_LCON;
+ }
+ if(instoffset == 0)
+ return C_ZCON;
+ if(instoffset >= -0x800)
+ return C_ADDCON;
+ if((instoffset & 0xfff) == 0 && isint32(instoffset))
+ return C_UCON;
+ return C_LCON;
+
+ case D_EXTERN:
+ case D_STATIC:
+ s = a->sym;
+ if(s == S)
+ break;
+ t = s->type;
+ switch(t) {
+ case 0:
+ case SXREF:
+ diag("undefined external: %s in %s",
+ s->name, TNAME);
+ s->type = SDATA;
+ break;
+ case SCONST:
+ instoffset = s->value + a->offset;
+ goto consize;
+ case STEXT:
+ case SLEAF:
+ instoffset = s->value + a->offset;
+ return C_LCON;
+ }
+ instoffset = s->value + a->offset + INITDAT;
+ return C_LCON;
+
+ case D_AUTO:
+ instoffset = autosize + a->offset;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+
+ case D_PARAM:
+ instoffset = autosize + a->offset + 8L;
+ if(instoffset >= -BIG && instoffset < BIG)
+ return C_SACON;
+ return C_LACON;
+ }
+ return C_GOK;
+
+ case D_BRANCH:
+ return C_SBRA;
+ }
+ return C_GOK;
+}
+
+Optab*
+oplook(Prog *p)
+{
+ int a1, a2, a3, r;
+ char *c1, *c3;
+ Optab *o, *e;
+
+ a1 = p->optab;
+ if(a1)
+ return optab+(a1-1);
+ a1 = p->from.class;
+ if(a1 == 0) {
+ a1 = aclass(&p->from) + 1;
+ p->from.class = a1;
+ }
+ a1--;
+ a3 = p->to.class;
+ if(a3 == 0) {
+ a3 = aclass(&p->to) + 1;
+ p->to.class = a3;
+ }
+ a3--;
+ a2 = C_NONE;
+ if(p->reg != NREG)
+ a2 = C_REG;
+ r = p->as;
+ o = oprange[r].start;
+ if(o == 0) {
+ a1 = opcross[repop[r]][a1][a2][a3];
+ if(a1) {
+ p->optab = a1+1;
+ return optab+a1;
+ }
+ o = oprange[r].stop; /* just generate an error */
+ }
+ e = oprange[r].stop;
+ c1 = xcmp[a1];
+ c3 = xcmp[a3];
+ for(; o<e; o++)
+ if(o->a2 == a2)
+ if(c1[o->a1])
+ if(c3[o->a3]) {
+ p->optab = (o-optab)+1;
+ return o;
+ }
+ diag("illegal combination %A %d %d %d",
+ p->as, p->from.class-1, a2, a3);
+ if(!debug['a'])
+ prasm(p);
+ o = optab;
+ p->optab = (o-optab)+1;
+ return o;
+}
+
+int
+cmp(int a, int b)
+{
+
+ if(a == b)
+ return 1;
+ switch(a) {
+ case C_LCON:
+ if(b == C_ZCON || b == C_SCON || b == C_UCON ||
+ b == C_ADDCON || b == C_ANDCON)
+ return 1;
+ break;
+ case C_ADD0CON:
+ if(b == C_ADDCON)
+ return 1;
+ case C_ADDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_AND0CON:
+ if(b == C_ANDCON)
+ return 1;
+ case C_ANDCON:
+ if(b == C_ZCON || b == C_SCON)
+ return 1;
+ break;
+ case C_UCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_SCON:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LACON:
+ if(b == C_SACON)
+ return 1;
+ break;
+ case C_LBRA:
+ if(b == C_SBRA)
+ return 1;
+ break;
+ case C_LEXT:
+ if(b == C_SEXT)
+ return 1;
+ break;
+ case C_LAUTO:
+ if(b == C_SAUTO)
+ return 1;
+ break;
+ case C_REG:
+ if(b == C_ZCON)
+ return 1;
+ break;
+ case C_LOREG:
+ if(b == C_ZOREG || b == C_SOREG)
+ return 1;
+ break;
+ case C_SOREG:
+ if(b == C_ZOREG)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+int
+ocmp(const void *a1, const void *a2)
+{
+ Optab *p1, *p2;
+ int n;
+
+ p1 = (Optab*)a1;
+ p2 = (Optab*)a2;
+ n = p1->as - p2->as;
+ if(n)
+ return n;
+ n = p1->a1 - p2->a1;
+ if(n)
+ return n;
+ n = p1->a2 - p2->a2;
+ if(n)
+ return n;
+ n = p1->a3 - p2->a3;
+ if(n)
+ return n;
+ return 0;
+}
+
+void
+buildop(void)
+{
+ int i, n, r;
+
+ for(i=0; i<32; i++)
+ for(n=0; n<32; n++)
+ xcmp[i][n] = cmp(n, i);
+ for(n=0; optab[n].as != AXXX; n++)
+ ;
+ qsort(optab, n, sizeof(optab[0]), ocmp);
+ for(i=0; i<n; i++) {
+ r = optab[i].as;
+ oprange[r].start = optab+i;
+ while(optab[i].as == r)
+ i++;
+ oprange[r].stop = optab+i;
+ i--;
+
+ switch(r)
+ {
+ default:
+ diag("unknown op in build: %A", r);
+ errorexit();
+ case AABSF:
+ oprange[AMOVFD] = oprange[r];
+ oprange[AMOVDF] = oprange[r];
+ oprange[AMOVWF] = oprange[r];
+ oprange[AMOVFW] = oprange[r];
+ oprange[AMOVWD] = oprange[r];
+ oprange[AMOVDW] = oprange[r];
+ oprange[ANEGF] = oprange[r];
+ oprange[ANEGD] = oprange[r];
+ oprange[AABSD] = oprange[r];
+ oprange[ATRUNCDW] = oprange[r];
+ oprange[ATRUNCFW] = oprange[r];
+ oprange[ATRUNCDV] = oprange[r];
+ oprange[ATRUNCFV] = oprange[r];
+ oprange[AMOVDV] = oprange[r];
+ oprange[AMOVFV] = oprange[r];
+ oprange[AMOVVD] = oprange[r];
+ oprange[AMOVVF] = oprange[r];
+ break;
+ case AADD:
+ buildrep(1, AADD);
+ oprange[ASGT] = oprange[r];
+ repop[ASGT] = 1;
+ oprange[ASGTU] = oprange[r];
+ repop[ASGTU] = 1;
+ oprange[AADDU] = oprange[r];
+ repop[AADDU] = 1;
+ oprange[AADDVU] = oprange[r];
+ repop[AADDVU] = 1;
+ oprange[AADDV] = oprange[r];
+ repop[AADDV] = 1;
+ break;
+ case AADDF:
+ oprange[ADIVF] = oprange[r];
+ oprange[ADIVD] = oprange[r];
+ oprange[AMULF] = oprange[r];
+ oprange[AMULD] = oprange[r];
+ oprange[ASUBF] = oprange[r];
+ oprange[ASUBD] = oprange[r];
+ oprange[AADDD] = oprange[r];
+ break;
+ case AAND:
+ buildrep(2, AAND);
+ oprange[AXOR] = oprange[r];
+ repop[AXOR] = 2;
+ oprange[AOR] = oprange[r];
+ repop[AOR] = 2;
+ break;
+ case ABEQ:
+ oprange[ABNE] = oprange[r];
+ break;
+ case ABLEZ:
+ oprange[ABGEZ] = oprange[r];
+ oprange[ABLTZ] = oprange[r];
+ oprange[ABGTZ] = oprange[r];
+ break;
+ case AMOVB:
+ buildrep(3, AMOVB);
+ oprange[AMOVH] = oprange[r];
+ repop[AMOVH] = 3;
+ break;
+ case AMOVBU:
+ buildrep(4, AMOVBU);
+ oprange[AMOVHU] = oprange[r];
+ repop[AMOVHU] = 4;
+ break;
+ case AMUL:
+ oprange[AMULU] = oprange[r];
+ oprange[AREM] = oprange[r];
+ oprange[AREMU] = oprange[r];
+ oprange[ADIV] = oprange[r];
+ oprange[ADIVU] = oprange[r];
+ break;
+ case AMULV:
+ oprange[AMULVU] = oprange[r];
+ oprange[AREMV] = oprange[r];
+ oprange[AREMVU] = oprange[r];
+ oprange[ADIVV] = oprange[r];
+ oprange[ADIVVU] = oprange[r];
+ break;
+ case ASLL:
+ oprange[ASRL] = oprange[r];
+ oprange[ASRA] = oprange[r];
+ oprange[ASLLV] = oprange[r];
+ oprange[ASRAV] = oprange[r];
+ oprange[ASRLV] = oprange[r];
+ break;
+ case ASUB:
+ oprange[ASUBU] = oprange[r];
+ oprange[ASUBV] = oprange[r];
+ oprange[ASUBVU] = oprange[r];
+ oprange[ANOR] = oprange[r];
+ break;
+ case ACMPEQF:
+ oprange[ACMPGTF] = oprange[r];
+ oprange[ACMPGTD] = oprange[r];
+ oprange[ACMPGEF] = oprange[r];
+ oprange[ACMPGED] = oprange[r];
+ oprange[ACMPEQD] = oprange[r];
+ break;
+ case ABFPT:
+ oprange[ABFPF] = oprange[r];
+ break;
+ case AMOVWL:
+ oprange[AMOVWR] = oprange[r];
+ oprange[AMOVVR] = oprange[r];
+ oprange[AMOVVL] = oprange[r];
+ break;
+ case AMOVW:
+ buildrep(5, AMOVW);
+ break;
+ case AMOVD:
+ buildrep(6, AMOVD);
+ break;
+ case AMOVF:
+ buildrep(7, AMOVF);
+ break;
+ case AMOVV:
+ buildrep(8, AMOVV);
+ break;
+ case ASYSCALL:
+ case ABREAK:
+ case AWORD:
+ case AJAL:
+ case AJMP:
+ case ATEXT:
+ case AMOVWU:
+ break;
+ }
+ }
+}
+
+void
+buildrep(int x, int as)
+{
+ Opcross *p;
+ Optab *e, *s, *o;
+ int a1, a2, a3, n;
+
+ if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
+ diag("assumptions fail in buildrep");
+ errorexit();
+ }
+ repop[as] = x;
+ p = (opcross + x);
+ s = oprange[as].start;
+ e = oprange[as].stop;
+ for(o=e-1; o>=s; o--) {
+ n = o-optab;
+ for(a2=0; a2<2; a2++) {
+ if(a2) {
+ if(o->a2 == C_NONE)
+ continue;
+ } else
+ if(o->a2 != C_NONE)
+ continue;
+ for(a1=0; a1<32; a1++) {
+ if(!xcmp[a1][o->a1])
+ continue;
+ for(a3=0; a3<32; a3++)
+ if(xcmp[a3][o->a3])
+ (*p)[a1][a2][a3] = n;
+ }
+ }
+ }
+ oprange[as].start = 0;
+}
--- /dev/null
+++ b/sys/src/libmach/elf.h
@@ -1,0 +1,156 @@
+/*
+ * Definitions needed for accessing ELF headers
+ */
+typedef struct {
+ uchar ident[16]; /* ident bytes */
+ ushort type; /* file type */
+ ushort machine; /* target machine */
+ int version; /* file version */
+ ulong elfentry; /* start address */
+ ulong phoff; /* phdr file offset */
+ ulong shoff; /* shdr file offset */
+ int flags; /* file flags */
+ ushort ehsize; /* sizeof ehdr */
+ ushort phentsize; /* sizeof phdr */
+ ushort phnum; /* number phdrs */
+ ushort shentsize; /* sizeof shdr */
+ ushort shnum; /* number shdrs */
+ ushort shstrndx; /* shdr string index */
+} Ehdr;
+
+typedef struct {
+ u8int ident[16]; /* ident bytes */
+ u16int type; /* file type */
+ u16int machine; /* target machine */
+ u32int version; /* file version */
+ u64int elfentry; /* start address */
+ u64int phoff; /* phdr file offset */
+ u64int shoff; /* shdr file offset */
+ u32int flags; /* file flags */
+ u16int ehsize; /* sizeof ehdr */
+ u16int phentsize; /* sizeof phdr */
+ u16int phnum; /* number phdrs */
+ u16int shentsize; /* sizeof shdr */
+ u16int shnum; /* number shdrs */
+ u16int shstrndx; /* shdr string index */
+} E64hdr;
+
+typedef struct {
+ int type; /* entry type */
+ ulong offset; /* file offset */
+ ulong vaddr; /* virtual address */
+ ulong paddr; /* physical address */
+ int filesz; /* file size */
+ ulong memsz; /* memory size */
+ int flags; /* entry flags */
+ int align; /* memory/file alignment */
+} Phdr;
+
+typedef struct {
+ u32int type; /* entry type */
+ u32int flags; /* entry flags */
+ u64int offset; /* file offset */
+ u64int vaddr; /* virtual address */
+ u64int paddr; /* physical address */
+ u64int filesz; /* file size */
+ u64int memsz; /* memory size */
+ u64int align; /* memory/file alignment */
+} P64hdr;
+
+typedef struct {
+ ulong name; /* section name */
+ ulong type; /* SHT_... */
+ ulong flags; /* SHF_... */
+ ulong addr; /* virtual address */
+ ulong offset; /* file offset */
+ ulong size; /* section size */
+ ulong link; /* misc info */
+ ulong info; /* misc info */
+ ulong addralign; /* memory alignment */
+ ulong entsize; /* entry size if table */
+} Shdr;
+
+typedef struct {
+ u32int name; /* section name */
+ u32int type; /* SHT_... */
+ u64int flags; /* SHF_... */
+ u64int addr; /* virtual address */
+ u64int offset; /* file offset */
+ u64int size; /* section size */
+ u32int link; /* misc info */
+ u32int info; /* misc info */
+ u64int addralign; /* memory alignment */
+ u64int entsize; /* entry size if table */
+} S64hdr;
+
+enum {
+ /* Ehdr codes */
+ MAG0 = 0, /* ident[] indexes */
+ MAG1 = 1,
+ MAG2 = 2,
+ MAG3 = 3,
+ CLASS = 4,
+ DATA = 5,
+ VERSION = 6,
+
+ ELFCLASSNONE = 0, /* ident[CLASS] */
+ ELFCLASS32 = 1,
+ ELFCLASS64 = 2,
+ ELFCLASSNUM = 3,
+
+ ELFDATANONE = 0, /* ident[DATA] */
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2,
+ ELFDATANUM = 3,
+
+ NOETYPE = 0, /* type */
+ REL = 1,
+ EXEC = 2,
+ DYN = 3,
+ CORE = 4,
+
+ NONE = 0, /* machine */
+ M32 = 1, /* AT&T WE 32100 */
+ SPARC = 2, /* Sun SPARC */
+ I386 = 3, /* Intel 80386 */
+ M68K = 4, /* Motorola 68000 */
+ M88K = 5, /* Motorola 88000 */
+ I486 = 6, /* Intel 80486 */
+ I860 = 7, /* Intel i860 */
+ MIPS = 8, /* Mips R2000 */
+ S370 = 9, /* Amdhal */
+ SPARC64 = 18, /* Sun SPARC v9 */
+ POWER = 20, /* PowerPC */
+ POWER64 = 21, /* PowerPC64 */
+ ARM = 40, /* ARM */
+ AMD64 = 62, /* Amd64 */
+ ARM64 = 183, /* ARM64 */
+ LOONGARCH = 258, /* LoongArch */
+
+ NO_VERSION = 0, /* version, ident[VERSION] */
+ CURRENT = 1,
+
+ /* Phdr Codes */
+ NOPTYPE = 0, /* type */
+ LOAD = 1,
+ DYNAMIC = 2,
+ INTERP = 3,
+ NOTE = 4,
+ SHLIB = 5,
+ PHDR = 6,
+
+ R = 0x4, /* flags */
+ W = 0x2,
+ X = 0x1,
+
+ /* Shdr Codes */
+ Progbits = 1, /* section types */
+ Strtab = 3,
+ Nobits = 8,
+
+ Swrite = 1, /* section attributes */
+ Salloc = 2,
+ Sexec = 4,
+};
+
+#define ELF_MAG ((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F')
--- /dev/null
+++ b/sys/src/libmach/executable.c
@@ -1,0 +1,912 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <bootexec.h>
+#include <mach.h>
+#include "elf.h"
+
+/*
+ * All a.out header types. The dummy entry allows canonical
+ * processing of the union as a sequence of longs
+ */
+
+typedef struct {
+ union{
+ struct {
+ Exec; /* a.out.h */
+ uvlong hdr[1];
+ };
+ Ehdr; /* elf.h */
+ E64hdr;
+ struct mipsexec; /* bootexec.h */
+ struct mips4kexec; /* bootexec.h */
+ struct sparcexec; /* bootexec.h */
+ struct nextexec; /* bootexec.h */
+ } e;
+ long dummy; /* padding to ensure extra long */
+} ExecHdr;
+
+static int nextboot(int, Fhdr*, ExecHdr*);
+static int sparcboot(int, Fhdr*, ExecHdr*);
+static int mipsboot(int, Fhdr*, ExecHdr*);
+static int mips4kboot(int, Fhdr*, ExecHdr*);
+static int common(int, Fhdr*, ExecHdr*);
+static int commonllp64(int, Fhdr*, ExecHdr*);
+static int adotout(int, Fhdr*, ExecHdr*);
+static int elfdotout(int, Fhdr*, ExecHdr*);
+static int armdotout(int, Fhdr*, ExecHdr*);
+static void setsym(Fhdr*, long, long, long, vlong);
+static void setdata(Fhdr*, uvlong, long, vlong, long);
+static void settext(Fhdr*, uvlong, uvlong, long, vlong);
+static void hswal(void*, int, ulong(*)(ulong));
+static uvlong _round(uvlong, ulong);
+
+/*
+ * definition of per-executable file type structures
+ */
+
+typedef struct Exectable{
+ long magic; /* big-endian magic number of file */
+ char *name; /* executable identifier */
+ char *dlmname; /* dynamically loadable module identifier */
+ uchar type; /* Internal code */
+ uchar _magic; /* _MAGIC() magic */
+ Mach *mach; /* Per-machine data */
+ long hsize; /* header size */
+ ulong (*swal)(ulong); /* beswal or leswal */
+ int (*hparse)(int, Fhdr*, ExecHdr*);
+} ExecTable;
+
+extern Mach mmips;
+extern Mach mmips2le;
+extern Mach mmips2be;
+extern Mach msparc;
+extern Mach msparc64;
+extern Mach m68020;
+extern Mach mi386;
+extern Mach mamd64;
+extern Mach marm;
+extern Mach mthumb;
+extern Mach marm64;
+extern Mach mpower;
+extern Mach mpower64;
+extern Mach mloong;
+
+ExecTable exectab[] =
+{
+ { V_MAGIC, /* Mips v.out */
+ "mips plan 9 executable BE",
+ "mips plan 9 dlm BE",
+ FMIPS,
+ 1,
+ &mmips,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { P_MAGIC, /* Mips 0.out (r3k le) */
+ "mips plan 9 executable LE",
+ "mips plan 9 dlm LE",
+ FMIPSLE,
+ 1,
+ &mmips,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { M_MAGIC, /* Mips 4.out */
+ "mips 4k plan 9 executable BE",
+ "mips 4k plan 9 dlm BE",
+ FMIPS2BE,
+ 1,
+ &mmips2be,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { N_MAGIC, /* Mips 0.out */
+ "mips 4k plan 9 executable LE",
+ "mips 4k plan 9 dlm LE",
+ FMIPS2LE,
+ 1,
+ &mmips2le,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { 0x160<<16, /* Mips boot image */
+ "mips plan 9 boot image",
+ nil,
+ FMIPSB,
+ 0,
+ &mmips,
+ sizeof(struct mipsexec),
+ beswal,
+ mipsboot },
+ { (0x160<<16)|3, /* Mips boot image */
+ "mips 4k plan 9 boot image",
+ nil,
+ FMIPSB,
+ 0,
+ &mmips2be,
+ sizeof(struct mips4kexec),
+ beswal,
+ mips4kboot },
+ { K_MAGIC, /* Sparc k.out */
+ "sparc plan 9 executable",
+ "sparc plan 9 dlm",
+ FSPARC,
+ 1,
+ &msparc,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { 0x01030107, /* Sparc boot image */
+ "sparc plan 9 boot image",
+ nil,
+ FSPARCB,
+ 0,
+ &msparc,
+ sizeof(struct sparcexec),
+ beswal,
+ sparcboot },
+ { U_MAGIC, /* Sparc64 u.out */
+ "sparc64 plan 9 executable",
+ "sparc64 plan 9 dlm",
+ FSPARC64,
+ 1,
+ &msparc64,
+ sizeof(Exec),
+ beswal,
+ adotout },
+ { A_MAGIC, /* 68020 2.out & boot image */
+ "68020 plan 9 executable",
+ "68020 plan 9 dlm",
+ F68020,
+ 1,
+ &m68020,
+ sizeof(Exec),
+ beswal,
+ common },
+ { 0xFEEDFACE, /* Next boot image */
+ "next plan 9 boot image",
+ nil,
+ FNEXTB,
+ 0,
+ &m68020,
+ sizeof(struct nextexec),
+ beswal,
+ nextboot },
+ { I_MAGIC, /* I386 8.out & boot image */
+ "386 plan 9 executable",
+ "386 plan 9 dlm",
+ FI386,
+ 1,
+ &mi386,
+ sizeof(Exec),
+ beswal,
+ common },
+ { S_MAGIC, /* amd64 6.out & boot image */
+ "amd64 plan 9 executable",
+ "amd64 plan 9 dlm",
+ FAMD64,
+ 1,
+ &mamd64,
+ sizeof(Exec)+8,
+ nil,
+ commonllp64 },
+ { Q_MAGIC, /* PowerPC q.out & boot image */
+ "power plan 9 executable",
+ "power plan 9 dlm",
+ FPOWER,
+ 1,
+ &mpower,
+ sizeof(Exec),
+ beswal,
+ common },
+ { T_MAGIC, /* power64 9.out & boot image */
+ "power64 plan 9 executable",
+ "power64 plan 9 dlm",
+ FPOWER64,
+ 1,
+ &mpower64,
+ sizeof(Exec)+8,
+ nil,
+ commonllp64 },
+ { ELF_MAG, /* any ELF */
+ "elf executable",
+ nil,
+ FNONE,
+ 0,
+ &mi386,
+ sizeof(Ehdr),
+ nil,
+ elfdotout },
+ { E_MAGIC, /* Arm 5.out and boot image */
+ "arm plan 9 executable",
+ "arm plan 9 dlm",
+ FARM,
+ 1,
+ &marm,
+ sizeof(Exec),
+ beswal,
+ common },
+ { (143<<16)|0413, /* (Free|Net)BSD Arm */
+ "arm *bsd executable",
+ nil,
+ FARM,
+ 0,
+ &marm,
+ sizeof(Exec),
+ leswal,
+ armdotout },
+ { R_MAGIC, /* Arm64 7.out and boot image */
+ "arm64 plan 9 executable",
+ "arm64 plan 9 dlm",
+ FARM64,
+ 1,
+ &marm64,
+ sizeof(Exec)+8,
+ nil,
+ commonllp64 },
+ { Z_MAGIC, /* LoongArch z.out and boot image */
+ "loong plan 9 executable",
+ "loong plan 9 dlm",
+ FLOONG,
+ 1,
+ &mloong,
+ sizeof(Exec)+8,
+ nil,
+ commonllp64 },
+ { 0 },
+};
+
+Mach *mach = &mi386; /* Global current machine table */
+
+int
+crackhdr(int fd, Fhdr *fp)
+{
+ ExecTable *mp;
+ ExecHdr d;
+ int nb, ret;
+ ulong magic;
+
+ fp->type = FNONE;
+ nb = read(fd, (char *)&d.e, sizeof(d.e));
+ if (nb <= 0)
+ return 0;
+
+ ret = 0;
+ magic = beswal(d.e.magic); /* big-endian */
+ for (mp = exectab; mp->magic; mp++) {
+ if (nb < mp->hsize)
+ continue;
+
+ /*
+ * The magic number has morphed into something
+ * with fields (the straw was DYN_MAGIC) so now
+ * a flag is needed in Fhdr to distinguish _MAGIC()
+ * magic numbers from foreign magic numbers.
+ *
+ * This code is creaking a bit and if it has to
+ * be modified/extended much more it's probably
+ * time to step back and redo it all.
+ */
+ if(mp->_magic){
+ if(mp->magic != (magic & ~DYN_MAGIC))
+ continue;
+
+ if ((magic & DYN_MAGIC) && mp->dlmname != nil)
+ fp->name = mp->dlmname;
+ else
+ fp->name = mp->name;
+ }
+ else{
+ if(mp->magic != magic)
+ continue;
+ fp->name = mp->name;
+ }
+ fp->type = mp->type;
+ fp->hdrsz = mp->hsize; /* will be zero on bootables */
+ fp->_magic = mp->_magic;
+ fp->magic = magic;
+
+ mach = mp->mach;
+ if(mp->swal != nil)
+ hswal(&d, sizeof(d.e)/sizeof(ulong), mp->swal);
+ ret = mp->hparse(fd, fp, &d);
+ seek(fd, mp->hsize, 0); /* seek to end of header */
+ break;
+ }
+ switch(mp->magic){
+ case E_MAGIC:
+ thumbpctab(fd, fp);
+ break;
+ case 0:
+ werrstr("unknown header type");
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Convert header to canonical form
+ */
+static void
+hswal(void *v, int n, ulong (*swap)(ulong))
+{
+ ulong *ulp;
+
+ for(ulp = v; n--; ulp++)
+ *ulp = (*swap)(*ulp);
+}
+
+/*
+ * Crack a normal a.out-type header
+ */
+static int
+adotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ long pgsize;
+
+ USED(fd);
+ pgsize = mach->pgsize;
+ settext(fp, hp->e.entry, pgsize+sizeof(Exec),
+ hp->e.text, sizeof(Exec));
+ setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
+ hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss);
+ setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
+ return 1;
+}
+
+static void
+commonboot(Fhdr *fp)
+{
+ /* arm needs to check for both arm and thumb */
+ if(fp->type == FARM && (fp->entry & mthumb.ktmask))
+ goto FTHUM;
+ if (!(fp->entry & mach->ktmask))
+ return;
+
+ switch(fp->type) { /* boot image */
+ case F68020:
+ fp->type = F68020B;
+ fp->name = "68020 plan 9 boot image";
+ break;
+ case FI386:
+ fp->type = FI386B;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "386 plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ break;
+ FTHUM:
+ case FARM:
+ fp->type = FARMB;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "ARM plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ return;
+ case FARM64:
+ fp->type = FARM64B;
+ fp->txtaddr = fp->entry;
+ fp->name = "arm64 plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ return;
+ case FLOONG:
+ fp->type = FLOONGB;
+ fp->txtaddr = fp->entry;
+ fp->name = "loong plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+ return;
+ case FPOWER:
+ fp->type = FPOWERB;
+ fp->txtaddr = (u32int)fp->entry;
+ fp->name = "power plan 9 boot image";
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ break;
+ case FAMD64:
+ fp->type = FAMD64B;
+ fp->txtaddr = fp->entry;
+ fp->name = "amd64 plan 9 boot image";
+ fp->dataddr = _round(fp->txtaddr+fp->txtsz, 4096);
+ break;
+ case FPOWER64:
+ fp->type = FPOWER64B;
+ fp->txtaddr = fp->entry;
+ fp->name = "power64 plan 9 boot image";
+ fp->dataddr = fp->txtaddr+fp->txtsz;
+ break;
+ default:
+ return;
+ }
+ fp->hdrsz = 0; /* header stripped */
+}
+
+/*
+ * _MAGIC() style headers and
+ * alpha plan9-style bootable images for axp "headerless" boot
+ *
+ */
+static int
+common(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ adotout(fd, fp, hp);
+ if(hp->e.magic & DYN_MAGIC) {
+ fp->txtaddr = 0;
+ fp->dataddr = fp->txtsz;
+ return 1;
+ }
+ commonboot(fp);
+ return 1;
+}
+
+static int
+commonllp64(int, Fhdr *fp, ExecHdr *hp)
+{
+ long pgsize;
+ uvlong entry;
+
+ hswal(&hp->e, sizeof(Exec)/sizeof(long), beswal);
+ if(!(hp->e.magic & HDR_MAGIC))
+ return 0;
+
+ /*
+ * There can be more magic here if the
+ * header ever needs more expansion.
+ * For now just catch use of any of the
+ * unused bits.
+ */
+ if((hp->e.magic & ~DYN_MAGIC)>>16)
+ return 0;
+ entry = beswav(hp->e.hdr[0]);
+
+ pgsize = mach->pgsize;
+ settext(fp, entry, pgsize+fp->hdrsz, hp->e.text, fp->hdrsz);
+ setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
+ hp->e.data, fp->txtsz+fp->hdrsz, hp->e.bss);
+ setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
+
+ if(hp->e.magic & DYN_MAGIC) {
+ fp->txtaddr = 0;
+ fp->dataddr = fp->txtsz;
+ return 1;
+ }
+ commonboot(fp);
+ return 1;
+}
+
+/*
+ * mips bootable image.
+ */
+static int
+mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ fp->type = FMIPSB;
+ switch(hp->e.amagic) {
+ default:
+ case 0407: /* some kind of mips */
+ settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
+ hp->e.tsize, sizeof(struct mipsexec)+4);
+ setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
+ fp->txtoff+hp->e.tsize, hp->e.bsize);
+ break;
+ case 0413: /* some kind of mips */
+ settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
+ hp->e.tsize, 0);
+ setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
+ hp->e.tsize, hp->e.bsize);
+ break;
+ }
+ setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * mips4k bootable image.
+ */
+static int
+mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ fp->type = FMIPSB;
+ switch(hp->e.h.amagic) {
+ default:
+ case 0407: /* some kind of mips */
+ settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
+ hp->e.h.tsize, sizeof(struct mips4kexec));
+ setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
+ fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
+ break;
+ case 0413: /* some kind of mips */
+ settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
+ hp->e.h.tsize, 0);
+ setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
+ hp->e.h.tsize, hp->e.h.bsize);
+ break;
+ }
+ setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * sparc bootable image
+ */
+static int
+sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ fp->type = FSPARCB;
+ settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
+ sizeof(struct sparcexec));
+ setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
+ fp->txtoff+hp->e.stext, hp->e.sbss);
+ setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * next bootable image
+ */
+static int
+nextboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ USED(fd);
+ fp->type = FNEXTB;
+ settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
+ hp->e.texts.size, hp->e.texts.offset);
+ setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
+ hp->e.datas.offset, hp->e.bsss.size);
+ setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
+ hp->e.symc.symoff);
+ fp->hdrsz = 0; /* header stripped */
+ return 1;
+}
+
+/*
+ * ELF64 binaries.
+ */
+static int
+elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ E64hdr *ep;
+ P64hdr *ph;
+ ushort (*swab)(ushort);
+ ulong (*swal)(ulong);
+ uvlong (*swav)(uvlong);
+ int i, it, id, is, phsz;
+ uvlong uvl;
+
+ ep = &hp->e;
+ if(ep->ident[DATA] == ELFDATA2LSB) {
+ swab = leswab;
+ swal = leswal;
+ swav = leswav;
+ } else if(ep->ident[DATA] == ELFDATA2MSB) {
+ swab = beswab;
+ swal = beswal;
+ swav = beswav;
+ } else {
+ werrstr("bad ELF64 encoding - not big or little endian");
+ return 0;
+ }
+
+ ep->type = swab(ep->type);
+ ep->machine = swab(ep->machine);
+ ep->version = swal(ep->version);
+ if(ep->type != EXEC || ep->version != CURRENT)
+ return 0;
+ ep->elfentry = swav(ep->elfentry);
+ ep->phoff = swav(ep->phoff);
+ ep->shoff = swav(ep->shoff);
+ ep->flags = swal(ep->flags);
+ ep->ehsize = swab(ep->ehsize);
+ ep->phentsize = swab(ep->phentsize);
+ ep->phnum = swab(ep->phnum);
+ ep->shentsize = swab(ep->shentsize);
+ ep->shnum = swab(ep->shnum);
+ ep->shstrndx = swab(ep->shstrndx);
+
+ fp->magic = ELF_MAG;
+ fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+ switch(ep->machine) {
+ default:
+ return 0;
+ case AMD64:
+ mach = &mamd64;
+ fp->type = FAMD64;
+ fp->name = "amd64 ELF64 executable";
+ break;
+ case POWER64:
+ mach = &mpower64;
+ fp->type = FPOWER64;
+ fp->name = "power64 ELF64 executable";
+ break;
+ }
+
+ if(ep->phentsize != sizeof(P64hdr)) {
+ werrstr("bad ELF64 header size");
+ return 0;
+ }
+ phsz = sizeof(P64hdr)*ep->phnum;
+ ph = malloc(phsz);
+ if(!ph)
+ return 0;
+ seek(fd, ep->phoff, 0);
+ if(read(fd, ph, phsz) < 0) {
+ free(ph);
+ return 0;
+ }
+ for(i = 0; i < ep->phnum; i++) {
+ ph[i].type = swal(ph[i].type);
+ ph[i].flags = swal(ph[i].flags);
+ ph[i].offset = swav(ph[i].offset);
+ ph[i].vaddr = swav(ph[i].vaddr);
+ ph[i].paddr = swav(ph[i].paddr);
+ ph[i].filesz = swav(ph[i].filesz);
+ ph[i].memsz = swav(ph[i].memsz);
+ ph[i].align = swav(ph[i].align);
+ }
+
+ /* find text, data and symbols and install them */
+ it = id = is = -1;
+ for(i = 0; i < ep->phnum; i++) {
+ if(ph[i].type == LOAD
+ && (ph[i].flags & (R|X)) == (R|X) && it == -1)
+ it = i;
+ else if(ph[i].type == LOAD
+ && (ph[i].flags & (R|W)) == (R|W) && id == -1)
+ id = i;
+ else if(ph[i].type == NOPTYPE && is == -1)
+ is = i;
+ }
+ if(it == -1 || id == -1) {
+ werrstr("No ELF64 TEXT or DATA sections");
+ free(ph);
+ return 0;
+ }
+
+ settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
+ /* 8c: out of fixed registers */
+ uvl = ph[id].memsz - ph[id].filesz;
+ setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, uvl);
+ if(is != -1)
+ setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
+ free(ph);
+ return 1;
+}
+
+/*
+ * ELF32 binaries.
+ */
+static int
+elf32dotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ ulong (*swal)(ulong);
+ ushort (*swab)(ushort);
+ Ehdr *ep;
+ Phdr *ph;
+ int i, it, id, is, phsz;
+
+ /* bitswap the header according to the DATA format */
+ ep = &hp->e;
+ if(ep->ident[DATA] == ELFDATA2LSB) {
+ swab = leswab;
+ swal = leswal;
+ } else if(ep->ident[DATA] == ELFDATA2MSB) {
+ swab = beswab;
+ swal = beswal;
+ } else {
+ werrstr("bad ELF32 encoding - not big or little endian");
+ return 0;
+ }
+
+ ep->type = swab(ep->type);
+ ep->machine = swab(ep->machine);
+ ep->version = swal(ep->version);
+ ep->elfentry = swal(ep->elfentry);
+ ep->phoff = swal(ep->phoff);
+ ep->shoff = swal(ep->shoff);
+ ep->flags = swal(ep->flags);
+ ep->ehsize = swab(ep->ehsize);
+ ep->phentsize = swab(ep->phentsize);
+ ep->phnum = swab(ep->phnum);
+ ep->shentsize = swab(ep->shentsize);
+ ep->shnum = swab(ep->shnum);
+ ep->shstrndx = swab(ep->shstrndx);
+ if(ep->type != EXEC || ep->version != CURRENT)
+ return 0;
+
+ /* we could definitely support a lot more machines here */
+ fp->magic = ELF_MAG;
+ fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+ switch(ep->machine) {
+ case I386:
+ mach = &mi386;
+ fp->type = FI386;
+ fp->name = "386 ELF32 executable";
+ break;
+ case MIPS:
+ mach = &mmips;
+ if(ep->ident[DATA] == ELFDATA2LSB){
+ fp->type = FMIPSLE;
+ fp->name = "mips le ELF32 executable";
+ } else {
+ fp->type = FMIPS;
+ fp->name = "mips be ELF32 executable";
+ }
+ break;
+ case SPARC64:
+ mach = &msparc64;
+ fp->type = FSPARC64;
+ fp->name = "sparc64 ELF32 executable";
+ break;
+ case POWER:
+ mach = &mpower;
+ fp->type = FPOWER;
+ fp->name = "power ELF32 executable";
+ break;
+ case POWER64:
+ mach = &mpower64;
+ fp->type = FPOWER64;
+ fp->name = "power64 ELF32 executable";
+ break;
+ case AMD64:
+ mach = &mamd64;
+ fp->type = FAMD64;
+ fp->name = "amd64 ELF32 executable";
+ break;
+ case ARM:
+ mach = &marm;
+ fp->type = FARM;
+ fp->name = "arm ELF32 executable";
+ break;
+ default:
+ return 0;
+ }
+
+ if(ep->phentsize != sizeof(Phdr)) {
+ werrstr("bad ELF32 header size");
+ return 0;
+ }
+ phsz = sizeof(Phdr)*ep->phnum;
+ ph = malloc(phsz);
+ if(!ph)
+ return 0;
+ seek(fd, ep->phoff, 0);
+ if(read(fd, ph, phsz) < 0) {
+ free(ph);
+ return 0;
+ }
+ hswal(ph, phsz/sizeof(ulong), swal);
+
+ /* find text, data and symbols and install them */
+ it = id = is = -1;
+ for(i = 0; i < ep->phnum; i++) {
+ if(ph[i].type == LOAD
+ && (ph[i].flags & (R|X)) == (R|X) && it == -1)
+ it = i;
+ else if(ph[i].type == LOAD
+ && (ph[i].flags & (R|W)) == (R|W) && id == -1)
+ id = i;
+ else if(ph[i].type == NOPTYPE && is == -1)
+ is = i;
+ }
+ if(it == -1 || id == -1) {
+ /*
+ * The SPARC64 boot image is something of an ELF hack.
+ * Text+Data+BSS are represented by ph[0]. Symbols
+ * are represented by ph[1]:
+ *
+ * filesz, memsz, vaddr, paddr, off
+ * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
+ * ph[1] : symsz, lcsz, 0, 0, symoff
+ */
+ if(ep->machine == SPARC64 && ep->phnum == 2) {
+ ulong txtaddr, txtsz, dataddr, bsssz;
+
+ txtaddr = ph[0].vaddr | 0x80000000;
+ txtsz = ph[0].filesz - ph[0].paddr;
+ dataddr = txtaddr + txtsz;
+ bsssz = ph[0].memsz - ph[0].filesz;
+ settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
+ setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
+ setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
+ free(ph);
+ return 1;
+ }
+
+ werrstr("No ELF32 TEXT or DATA sections");
+ free(ph);
+ return 0;
+ }
+
+ settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
+ setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
+ if(is != -1)
+ setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
+ free(ph);
+ return 1;
+}
+
+/*
+ * Elf binaries.
+ */
+static int
+elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ Ehdr *ep;
+
+ /* bitswap the header according to the DATA format */
+ ep = &hp->e;
+ if(ep->ident[CLASS] == ELFCLASS32)
+ return elf32dotout(fd, fp, hp);
+ else if(ep->ident[CLASS] == ELFCLASS64)
+ return elf64dotout(fd, fp, hp);
+
+ werrstr("bad ELF class - not 32 bit");
+ return 0;
+}
+
+/*
+ * (Free|Net)BSD ARM header.
+ */
+static int
+armdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ uvlong kbase;
+
+ USED(fd);
+ settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec));
+ setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss);
+ setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz);
+
+ kbase = 0xF0000000;
+ if ((fp->entry & kbase) == kbase) { /* Boot image */
+ fp->txtaddr = kbase+sizeof(Exec);
+ fp->name = "ARM *BSD boot image";
+ fp->hdrsz = 0; /* header stripped */
+ fp->dataddr = kbase+fp->txtsz;
+ }
+ return 1;
+}
+
+static void
+settext(Fhdr *fp, uvlong e, uvlong a, long s, vlong off)
+{
+ fp->txtaddr = a;
+ fp->entry = e;
+ fp->txtsz = s;
+ fp->txtoff = off;
+}
+
+static void
+setdata(Fhdr *fp, uvlong a, long s, vlong off, long bss)
+{
+ fp->dataddr = a;
+ fp->datsz = s;
+ fp->datoff = off;
+ fp->bsssz = bss;
+}
+
+static void
+setsym(Fhdr *fp, long symsz, long sppcsz, long lnpcsz, vlong symoff)
+{
+ fp->symsz = symsz;
+ fp->symoff = symoff;
+ fp->sppcsz = sppcsz;
+ fp->sppcoff = fp->symoff+fp->symsz;
+ fp->lnpcsz = lnpcsz;
+ fp->lnpcoff = fp->sppcoff+fp->sppcsz;
+}
+
+
+static uvlong
+_round(uvlong a, ulong b)
+{
+ uvlong w;
+
+ w = (a/b)*b;
+ if (a!=w)
+ w += b;
+ return(w);
+}
--- /dev/null
+++ b/sys/src/libmach/mkfile
@@ -1,0 +1,75 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libmach.a
+FILES=\
+ executable\
+ map\
+ obj\
+ swap\
+ sym\
+ access\
+ machdata\
+ setmach\
+ t\
+ v\
+ k\
+ u\
+ q\
+ 0\
+ 2\
+ 5\
+ 6\
+ 7\
+ 8\
+ 9\
+ z\
+ tdb\
+ vdb\
+ kdb\
+ udb\
+ qdb\
+ 2db\
+ 5db\
+ 7db\
+ 8db\
+ zdb\
+ vobj\
+ kobj\
+ uobj\
+ 2obj\
+ 5obj\
+ 6obj\
+ 7obj\
+ 8obj\
+ 9obj\
+ qobj\
+ zobj\
+ vcodas\
+
+HFILES=/sys/include/mach.h elf.h obj.h
+
+CFILES=${FILES:%=%.c}
+
+OFILES=${FILES:%=%.$O}
+
+UPDATE=mkfile\
+ /386/lib/libmach.a\
+ $HFILES\
+ $CFILES\
+
+</sys/src/cmd/mksyslib
+
+CFLAGS=$CFLAGS -I/sys/src/cmd
+
+2obj.$O: /sys/src/cmd/2c/2.out.h
+5obj.$O: /sys/src/cmd/5c/5.out.h
+6obj.$O: /sys/src/cmd/6c/6.out.h
+7obj.$O: /sys/src/cmd/7c/7.out.h
+8obj.$O: /sys/src/cmd/8c/8.out.h
+kobj.$O: /sys/src/cmd/kc/k.out.h
+qobj.$O: /sys/src/cmd/qc/q.out.h
+vobj.$O: /sys/src/cmd/vc/v.out.h
+zobj.$O: /sys/src/cmd/zc/z.out.h
+
+# 9obj.$O: /sys/src/cmd/9c/9.out.h
+# uobj.$O: uc/u.out.h
--- /dev/null
+++ b/sys/src/libmach/obj.c
@@ -1,0 +1,331 @@
+/*
+ * obj.c
+ * routines universal to all object files
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ar.h>
+#include <mach.h>
+#include "obj.h"
+
+#define islocal(t) ((t)=='a' || (t)=='p')
+
+enum
+{
+ NNAMES = 50,
+ MAXIS = 8, /* max length to determine if a file is a .? file */
+ MAXOFF = 0x7fffffff, /* larger than any possible local offset */
+ NHASH = 1024, /* must be power of two */
+ HASHMUL = 79L,
+};
+
+int _is2(char*), /* in [$OS].c */
+ _is5(char*),
+ _is6(char*),
+ _is7(char*),
+ _isz(char*),
+ _is8(char*),
+ _is9(char*),
+ _isk(char*),
+ _isq(char*),
+ _isv(char*),
+ _isu(char*),
+ _read2(Biobuf*, Prog*),
+ _read5(Biobuf*, Prog*),
+ _read6(Biobuf*, Prog*),
+ _read7(Biobuf*, Prog*),
+ _readz(Biobuf*, Prog*),
+ _read8(Biobuf*, Prog*),
+ _read9(Biobuf*, Prog*),
+ _readk(Biobuf*, Prog*),
+ _readq(Biobuf*, Prog*),
+ _readv(Biobuf*, Prog*),
+ _readu(Biobuf*, Prog*);
+
+typedef struct Obj Obj;
+typedef struct Symtab Symtab;
+
+struct Obj /* functions to handle each intermediate (.$O) file */
+{
+ char *name; /* name of each $O file */
+ int (*is)(char*); /* test for each type of $O file */
+ int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
+};
+
+static Obj obj[] =
+{ /* functions to identify and parse each type of obj */
+ [Obj68020] "68020 .2", _is2, _read2,
+ [ObjAmd64] "amd64 .6", _is6, _read6,
+ [ObjArm] "arm .5", _is5, _read5,
+ [ObjArm64] "arm64 .7", _is7, _read7,
+ [ObjLoong] "loong .z", _isz, _readz,
+ [Obj386] "386 .8", _is8, _read8,
+ [ObjSparc] "sparc .k", _isk, _readk,
+ [ObjPower] "power .q", _isq, _readq,
+ [ObjMips] "mips .v", _isv, _readv,
+ [ObjSparc64] "sparc64 .u", _isu, _readu,
+ [ObjPower64] "power64 .9", _is9, _read9,
+ [Maxobjtype] 0, 0
+};
+
+struct Symtab
+{
+ struct Sym s;
+ struct Symtab *next;
+};
+
+static Symtab *hash[NHASH];
+static Sym *names[NNAMES]; /* working set of active names */
+
+static int processprog(Prog*,int); /* decode each symbol reference */
+static void objreset(void);
+static void objlookup(int, char *, int, uint);
+static void objupdate(int, int);
+
+int
+objtype(Biobuf *bp, char **name)
+{
+ int i;
+ char buf[MAXIS];
+
+ if(Bread(bp, buf, MAXIS) < MAXIS)
+ return -1;
+ Bseek(bp, -MAXIS, 1);
+ for (i = 0; i < Maxobjtype; i++) {
+ if (obj[i].is && (*obj[i].is)(buf)) {
+ if (name)
+ *name = obj[i].name;
+ return i;
+ }
+ }
+ return -1;
+}
+
+int
+isar(Biobuf *bp)
+{
+ int n;
+ char magbuf[SARMAG];
+
+ n = Bread(bp, magbuf, SARMAG);
+ if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * determine what kind of object file this is and process it.
+ * return whether or not this was a recognized intermediate file.
+ */
+int
+readobj(Biobuf *bp, int objtype)
+{
+ Prog p;
+
+ if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+ return 1;
+ objreset();
+ while ((*obj[objtype].read)(bp, &p))
+ if (!processprog(&p, 1))
+ return 0;
+ return 1;
+}
+
+int
+readar(Biobuf *bp, int objtype, vlong end, int doautos)
+{
+ Prog p;
+
+ if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+ return 1;
+ objreset();
+ while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
+ if (!processprog(&p, doautos))
+ return 0;
+ return 1;
+}
+
+/*
+ * decode a symbol reference or definition
+ */
+static int
+processprog(Prog *p, int doautos)
+{
+ if(p->kind == aNone)
+ return 1;
+ if(p->sym < 0 || p->sym >= NNAMES)
+ return 0;
+ switch(p->kind)
+ {
+ case aName:
+ if (!doautos)
+ if(p->type != 'U' && p->type != 'b')
+ break;
+ objlookup(p->sym, p->id, p->type, p->sig);
+ break;
+ case aText:
+ objupdate(p->sym, 'T');
+ break;
+ case aData:
+ objupdate(p->sym, 'D');
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/*
+ * find the entry for s in the symbol array.
+ * make a new entry if it is not already there.
+ */
+static void
+objlookup(int id, char *name, int type, uint sig)
+{
+ long h;
+ char *cp;
+ Sym *s;
+ Symtab *sp;
+
+ s = names[id];
+ if(s && strcmp(s->name, name) == 0) {
+ s->type = type;
+ s->sig = sig;
+ return;
+ }
+
+ h = *name;
+ for(cp = name+1; *cp; h += *cp++)
+ h *= HASHMUL;
+ if(h < 0)
+ h = ~h;
+ h &= (NHASH-1);
+ if (type == 'U' || type == 'b' || islocal(type)) {
+ for(sp = hash[h]; sp; sp = sp->next)
+ if(strcmp(sp->s.name, name) == 0) {
+ switch(sp->s.type) {
+ case 'T':
+ case 'D':
+ case 'U':
+ if (type == 'U') {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ case 't':
+ case 'd':
+ case 'b':
+ if (type == 'b') {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ case 'a':
+ case 'p':
+ if (islocal(type)) {
+ names[id] = &sp->s;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ sp = malloc(sizeof(Symtab));
+ sp->s.name = name;
+ sp->s.type = type;
+ sp->s.sig = sig;
+ sp->s.value = islocal(type) ? MAXOFF : 0;
+ names[id] = &sp->s;
+ sp->next = hash[h];
+ hash[h] = sp;
+ return;
+}
+/*
+ * traverse the symbol lists
+ */
+void
+objtraverse(void (*fn)(Sym*, void*), void *pointer)
+{
+ int i;
+ Symtab *s;
+
+ for(i = 0; i < NHASH; i++)
+ for(s = hash[i]; s; s = s->next)
+ (*fn)(&s->s, pointer);
+}
+
+/*
+ * update the offset information for a 'a' or 'p' symbol in an intermediate file
+ */
+void
+_offset(int id, vlong off)
+{
+ Sym *s;
+
+ s = names[id];
+ if (s && s->name[0] && islocal(s->type) && s->value > off)
+ s->value = off;
+}
+
+/*
+ * update the type of a global text or data symbol
+ */
+static void
+objupdate(int id, int type)
+{
+ Sym *s;
+
+ s = names[id];
+ if (s && s->name[0])
+ if (s->type == 'U')
+ s->type = type;
+ else if (s->type == 'b')
+ s->type = tolower(type);
+}
+
+/*
+ * look for the next file in an archive
+ */
+int
+nextar(Biobuf *bp, int offset, char *buf)
+{
+ struct ar_hdr a;
+ int i, r;
+ long arsize;
+
+ if (offset&01)
+ offset++;
+ Bseek(bp, offset, 0);
+ r = Bread(bp, &a, SAR_HDR);
+ if(r != SAR_HDR)
+ return 0;
+ if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
+ return -1;
+ for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
+ buf[i] = a.name[i];
+ buf[i] = 0;
+ arsize = strtol(a.size, 0, 0);
+ if (arsize&1)
+ arsize++;
+ return arsize + SAR_HDR;
+}
+
+static void
+objreset(void)
+{
+ int i;
+ Symtab *s, *n;
+
+ for(i = 0; i < NHASH; i++) {
+ for(s = hash[i]; s; s = n) {
+ n = s->next;
+ free(s->s.name);
+ free(s);
+ }
+ hash[i] = 0;
+ }
+ memset(names, 0, sizeof names);
+}
--- /dev/null
+++ b/sys/src/libmach/setmach.c
@@ -1,0 +1,181 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+ /* table for selecting machine-dependent parameters */
+
+typedef struct machtab Machtab;
+
+struct machtab
+{
+ char *name; /* machine name */
+ short type; /* executable type */
+ short boottype; /* bootable type */
+ int asstype; /* disassembler code */
+ Mach *mach; /* machine description */
+ Machdata *machdata; /* machine functions */
+};
+
+extern Mach mmips, msparc, m68020, mi386, mamd64,
+ marm, marm64, mmips2be, mmips2le, mpower, mpower64, msparc64, mloong;
+extern Machdata mipsmach, mipsmachle, sparcmach, m68020mach, i386mach,
+ armmach, arm64mach, mipsmach2le, powermach, sparc64mach, loongmach;
+
+/*
+ * machine selection table. machines with native disassemblers should
+ * follow the plan 9 variant in the table; native modes are selectable
+ * only by name.
+ */
+Machtab machines[] =
+{
+ { "68020", /*68020*/
+ F68020,
+ F68020B,
+ A68020,
+ &m68020,
+ &m68020mach, },
+ { "68020", /*Next 68040 bootable*/
+ F68020,
+ FNEXTB,
+ A68020,
+ &m68020,
+ &m68020mach, },
+ { "spim2", /*plan 9 mips2 little endian*/
+ FMIPS2LE,
+ 0,
+ AMIPS,
+ &mmips2le,
+ &mipsmach2le, },
+ { "spim", /*plan 9 mips little endian*/
+ FMIPSLE,
+ 0,
+ AMIPS,
+ &mmips,
+ &mipsmachle, },
+ { "mips", /*plan 9 mips*/
+ FMIPS,
+ FMIPSB,
+ AMIPS,
+ &mmips,
+ &mipsmach, },
+ { "mips2", /*plan 9 mips2*/
+ FMIPS2BE,
+ FMIPSB,
+ AMIPS,
+ &mmips2be,
+ &mipsmach, }, /* shares debuggers with native mips */
+ { "mipsco", /*native mips - must follow plan 9*/
+ FMIPS,
+ FMIPSB,
+ AMIPSCO,
+ &mmips,
+ &mipsmach, },
+ { "sparc", /*plan 9 sparc */
+ FSPARC,
+ FSPARCB,
+ ASPARC,
+ &msparc,
+ &sparcmach, },
+ { "sunsparc", /*native sparc - must follow plan 9*/
+ FSPARC,
+ FSPARCB,
+ ASUNSPARC,
+ &msparc,
+ &sparcmach, },
+ { "386", /*plan 9 386*/
+ FI386,
+ FI386B,
+ AI386,
+ &mi386,
+ &i386mach, },
+ { "86", /*8086 - a peach of a machine*/
+ FI386,
+ FI386B,
+ AI8086,
+ &mi386,
+ &i386mach, },
+ { "amd64", /*amd64*/
+ FAMD64,
+ FAMD64B,
+ AAMD64,
+ &mamd64,
+ &i386mach, },
+ { "arm", /*ARM*/
+ FARM,
+ FARMB,
+ AARM,
+ &marm,
+ &armmach, },
+ { "arm64", /*ARM64*/
+ FARM64,
+ FARM64B,
+ AARM64,
+ &marm64,
+ &arm64mach, },
+ { "loong", /*LoongArch*/
+ FLOONG,
+ FLOONGB,
+ ALOONG,
+ &mloong,
+ &loongmach, },
+ { "power", /*PowerPC*/
+ FPOWER,
+ FPOWERB,
+ APOWER,
+ &mpower,
+ &powermach, },
+ { "power64", /*PowerPC*/
+ FPOWER64,
+ FPOWER64B,
+ APOWER64,
+ &mpower64,
+ &powermach, },
+ { "sparc64", /*plan 9 sparc64 */
+ FSPARC64,
+ FSPARCB, /* XXX? */
+ ASPARC64,
+ &msparc64,
+ &sparc64mach, },
+ { 0 }, /*the terminator*/
+};
+
+/*
+ * select a machine by executable file type
+ */
+void
+machbytype(int type)
+{
+ Machtab *mp;
+
+ for (mp = machines; mp->name; mp++){
+ if (mp->type == type || mp->boottype == type) {
+ asstype = mp->asstype;
+ machdata = mp->machdata;
+ break;
+ }
+ }
+}
+/*
+ * select a machine by name
+ */
+int
+machbyname(char *name)
+{
+ Machtab *mp;
+
+ if (!name) {
+ asstype = AMIPS;
+ machdata = &mipsmach;
+ mach = &mmips;
+ return 1;
+ }
+ for (mp = machines; mp->name; mp++){
+ if (strcmp(mp->name, name) == 0) {
+ asstype = mp->asstype;
+ machdata = mp->machdata;
+ mach = mp->mach;
+ return 1;
+ }
+ }
+ return 0;
+}
--- /dev/null
+++ b/sys/src/libmach/z.c
@@ -1,0 +1,152 @@
+/*
+ * TODO: LoongArch
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+#include "/loong/include/ureg.h"
+
+#define REGSIZE sizeof(struct Ureg)
+#define FPREGSIZE 520
+
+#define REGOFF(x) (uintptr)(&((struct Ureg *) 0)->x)
+#define FP_REG(x) (REGSIZE+16*(x))
+#define FP_CTL(x) (FP_REG(32)+4*(x))
+
+#define SP REGOFF(sp)
+#define PC REGOFF(pc)
+
+Reglist loongreglist[] =
+{
+ {"TYPE", REGOFF(type), RINT|RRDONLY, 'Y'},
+ {"PSR", REGOFF(psr), RINT|RRDONLY, 'Y'},
+ {"PC", PC, RINT, 'Y'},
+ {"SP", SP, RINT, 'Y'},
+ {"R30", REGOFF(r30), RINT, 'Y'},
+ {"R29", REGOFF(r29), RINT, 'Y'},
+ {"R28", REGOFF(r28), RINT, 'Y'},
+ {"R27", REGOFF(r27), RINT, 'Y'},
+ {"R26", REGOFF(r26), RINT, 'Y'},
+ {"R25", REGOFF(r25), RINT, 'Y'},
+ {"R24", REGOFF(r24), RINT, 'Y'},
+ {"R23", REGOFF(r23), RINT, 'Y'},
+ {"R22", REGOFF(r22), RINT, 'Y'},
+ {"R21", REGOFF(r21), RINT, 'Y'},
+ {"R20", REGOFF(r20), RINT, 'Y'},
+ {"R19", REGOFF(r19), RINT, 'Y'},
+ {"R18", REGOFF(r18), RINT, 'Y'},
+ {"R17", REGOFF(r17), RINT, 'Y'},
+ {"R16", REGOFF(r16), RINT, 'Y'},
+ {"R15", REGOFF(r15), RINT, 'Y'},
+ {"R14", REGOFF(r14), RINT, 'Y'},
+ {"R13", REGOFF(r13), RINT, 'Y'},
+ {"R12", REGOFF(r12), RINT, 'Y'},
+ {"R11", REGOFF(r11), RINT, 'Y'},
+ {"R10", REGOFF(r10), RINT, 'Y'},
+ {"R9", REGOFF(r9), RINT, 'Y'},
+ {"R8", REGOFF(r8), RINT, 'Y'},
+ {"R7", REGOFF(r7), RINT, 'Y'},
+ {"R6", REGOFF(r6), RINT, 'Y'},
+ {"R5", REGOFF(r5), RINT, 'Y'},
+ {"R4", REGOFF(r4), RINT, 'Y'},
+ {"R3", REGOFF(r3), RINT, 'Y'},
+ {"R2", REGOFF(r2), RINT, 'Y'},
+ {"R1", REGOFF(r1), RINT, 'Y'},
+ {"R0", REGOFF(r0), RINT, 'Y'},
+
+ {"FPSR", FP_CTL(1), RINT, 'X'},
+ {"FPCR", FP_CTL(0), RINT, 'X'},
+
+ {"F31", FP_REG(31), RFLT, 'F'}, /* double */
+ {"F30", FP_REG(30), RFLT, 'F'},
+ {"F29", FP_REG(29), RFLT, 'F'},
+ {"F28", FP_REG(28), RFLT, 'F'},
+ {"F27", FP_REG(27), RFLT, 'F'},
+ {"F26", FP_REG(26), RFLT, 'F'},
+ {"F25", FP_REG(25), RFLT, 'F'},
+ {"F24", FP_REG(24), RFLT, 'F'},
+ {"F23", FP_REG(23), RFLT, 'F'},
+ {"F22", FP_REG(22), RFLT, 'F'},
+ {"F21", FP_REG(21), RFLT, 'F'},
+ {"F20", FP_REG(20), RFLT, 'F'},
+ {"F19", FP_REG(19), RFLT, 'F'},
+ {"F18", FP_REG(18), RFLT, 'F'},
+ {"F17", FP_REG(17), RFLT, 'F'},
+ {"F16", FP_REG(16), RFLT, 'F'},
+ {"F15", FP_REG(15), RFLT, 'F'},
+ {"F14", FP_REG(14), RFLT, 'F'},
+ {"F13", FP_REG(13), RFLT, 'F'},
+ {"F12", FP_REG(12), RFLT, 'F'},
+ {"F11", FP_REG(11), RFLT, 'F'},
+ {"F10", FP_REG(10), RFLT, 'F'},
+ {"F9", FP_REG(9), RFLT, 'F'},
+ {"F8", FP_REG(8), RFLT, 'F'},
+ {"F7", FP_REG(7), RFLT, 'F'},
+ {"F6", FP_REG(6), RFLT, 'F'},
+ {"F5", FP_REG(5), RFLT, 'F'},
+ {"F4", FP_REG(4), RFLT, 'F'},
+ {"F3", FP_REG(3), RFLT, 'F'},
+ {"F2", FP_REG(2), RFLT, 'F'},
+ {"F1", FP_REG(1), RFLT, 'F'},
+ {"F0", FP_REG(0), RFLT, 'F'},
+
+ {"f31", FP_REG(31), RFLT, 'f'}, /* double */
+ {"f30", FP_REG(30), RFLT, 'f'},
+ {"f29", FP_REG(29), RFLT, 'f'},
+ {"f28", FP_REG(28), RFLT, 'f'},
+ {"f27", FP_REG(27), RFLT, 'f'},
+ {"f26", FP_REG(26), RFLT, 'f'},
+ {"f25", FP_REG(25), RFLT, 'f'},
+ {"f24", FP_REG(24), RFLT, 'f'},
+ {"f23", FP_REG(23), RFLT, 'f'},
+ {"f22", FP_REG(22), RFLT, 'f'},
+ {"f21", FP_REG(21), RFLT, 'f'},
+ {"f20", FP_REG(20), RFLT, 'f'},
+ {"f19", FP_REG(19), RFLT, 'f'},
+ {"f18", FP_REG(18), RFLT, 'f'},
+ {"f17", FP_REG(17), RFLT, 'f'},
+ {"f16", FP_REG(16), RFLT, 'f'},
+ {"f15", FP_REG(15), RFLT, 'f'},
+ {"f14", FP_REG(14), RFLT, 'f'},
+ {"f13", FP_REG(13), RFLT, 'f'},
+ {"f12", FP_REG(12), RFLT, 'f'},
+ {"f11", FP_REG(11), RFLT, 'f'},
+ {"f10", FP_REG(10), RFLT, 'f'},
+ {"f9", FP_REG(9), RFLT, 'f'},
+ {"f8", FP_REG(8), RFLT, 'f'},
+ {"f7", FP_REG(7), RFLT, 'f'},
+ {"f6", FP_REG(6), RFLT, 'f'},
+ {"f5", FP_REG(5), RFLT, 'f'},
+ {"f4", FP_REG(4), RFLT, 'f'},
+ {"f3", FP_REG(3), RFLT, 'f'},
+ {"f2", FP_REG(2), RFLT, 'f'},
+ {"f1", FP_REG(1), RFLT, 'f'},
+ {"f0", FP_REG(0), RFLT, 'f'},
+ { 0 }
+};
+
+ /* the machine description */
+Mach mloong =
+{
+ "loong",
+ MLOONG, /* machine type */
+ loongreglist, /* register set */
+ REGSIZE, /* register set size */
+ FPREGSIZE, /* fp register set size */
+ "PC", /* name of PC */
+ "SP", /* name of SP */
+ "R1", /* name of link register */
+ "setSB", /* static base register name */
+ 0, /* static base register value */
+ 0x10000, /* page size (for segment alignment) */
+ 0xFFFFFFFF80000000ULL, /* kernel base */
+ 0xFFFF800000000000ULL, /* kernel text mask */
+ 0x00007FFFFFFF0000ULL, /* user stack top */
+ 4, /* quantization of pc */
+ 8, /* szaddr */
+ 8, /* szreg */
+ 4, /* szfloat */
+ 8, /* szdouble */
+};
--- /dev/null
+++ b/sys/src/libmach/zdb.c
@@ -1,0 +1,65 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+/*
+ * LoongArch-specific debugger interface
+ */
+static char* loongexcep(Map*, Rgetter);
+static int loongfoll(Map*, uvlong, Rgetter, uvlong*);
+static int loonginst(Map*, uvlong, char, char*, int);
+static int loongdas(Map*, uvlong, char*, int);
+static int loonginstlen(Map*, uvlong);
+
+/*
+ * Debugger interface
+ */
+Machdata loongmach =
+{
+ {0x00, 0x2A, 0x20, 0x00}, /* break point 0x002A0000 */
+ 4, /* break point size */
+ leswab, /* short to local byte order */
+ leswal, /* long to local byte order */
+ leswav, /* long to local byte order */
+ risctrace, /* C traceback */
+ riscframe, /* Frame finder */
+ loongexcep, /* print exception */
+ 0, /* breakpoint fixup */
+ leieeesftos, /* single precision float printer */
+ leieeedftos, /* double precision float printer */
+ loongfoll, /* following addresses */
+ loonginst, /* print instruction */
+ loongdas, /* dissembler */
+ loonginstlen, /* instruction size */
+};
+
+static char*
+loongexcep(Map *, Rgetter)
+{
+ return "???";
+}
+
+static int
+loonginst(Map *, uvlong, char, char *, int)
+{
+ return -1;
+}
+
+static int
+loongdas(Map *, uvlong, char *, int)
+{
+ return -1;
+}
+
+static int
+loonginstlen(Map*, uvlong)
+{
+ return 4;
+}
+
+static int
+loongfoll(Map *, uvlong, Rgetter, uvlong *)
+{
+ return -1;
+}
--- /dev/null
+++ b/sys/src/libmach/zobj.c
@@ -1,0 +1,137 @@
+/*
+ * zobj.c - identify and parse a LoongArch object file
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "zc/z.out.h"
+#include "obj.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ char type;
+ char sym;
+ char name;
+};
+static Addr addr(Biobuf*);
+static char type2char(int);
+static void skip(Biobuf*, int);
+
+int
+_isz(char *s)
+{
+ return s[0] == ANAME /* ANAME */
+ && s[1] == D_FILE /* type */
+ && s[2] == 1 /* sym */
+ && s[3] == '<'; /* name of file */
+}
+
+int
+_readz(Biobuf *bp, Prog *p)
+{
+ int as, n;
+ Addr a;
+
+ as = Bgetc(bp); /* as */
+ if(as < 0)
+ return 0;
+ p->kind = aNone;
+ p->sig = 0;
+ if(as == ANAME || as == ASIGNAME){
+ if(as == ASIGNAME){
+ Bread(bp, &p->sig, 4);
+ p->sig = leswal(p->sig);
+ }
+ p->kind = aName;
+ p->type = type2char(Bgetc(bp)); /* type */
+ p->sym = Bgetc(bp); /* sym */
+ n = 0;
+ for(;;) {
+ as = Bgetc(bp);
+ if(as < 0)
+ return 0;
+ n++;
+ if(as == 0)
+ break;
+ }
+ p->id = malloc(n);
+ if(p->id == 0)
+ return 0;
+ Bseek(bp, -n, 1);
+ if(Bread(bp, p->id, n) != n)
+ return 0;
+ return 1;
+ }
+ if(as == ATEXT)
+ p->kind = aText;
+ else if(as == AGLOBL)
+ p->kind = aData;
+ skip(bp, 5); /* reg(1), lineno(4) */
+ a = addr(bp);
+ addr(bp);
+ if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
+ p->kind = aNone;
+ p->sym = a.sym;
+ return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+ Addr a;
+ long off;
+
+ a.type = Bgetc(bp); /* a.type */
+ skip(bp,1); /* reg */
+ a.sym = Bgetc(bp); /* sym index */
+ a.name = Bgetc(bp); /* sym type */
+ switch(a.type){
+ default:
+ case D_NONE:
+ case D_REG:
+ case D_FREG:
+ case D_FCCREG:
+ case D_FCSREG:
+ break;
+ case D_OREG:
+ case D_CONST:
+ case D_BRANCH:
+ off = Bgetc(bp);
+ off |= Bgetc(bp) << 8;
+ off |= Bgetc(bp) << 16;
+ off |= Bgetc(bp) << 24;
+ if(off < 0)
+ off = -off;
+ if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
+ _offset(a.sym, off);
+ break;
+ case D_SCONST:
+ skip(bp, NSNAME);
+ break;
+ case D_FCONST:
+ skip(bp, 8);
+ break;
+ }
+ return a;
+}
+
+static char
+type2char(int t)
+{
+ switch(t){
+ case D_EXTERN: return 'U';
+ case D_STATIC: return 'b';
+ case D_AUTO: return 'a';
+ case D_PARAM: return 'p';
+ default: return UNKNOWN;
+ }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+ while (n-- > 0)
+ Bgetc(bp);
+}
--- /dev/null
+++ b/sys/src/mkfile.proto
@@ -1,0 +1,19 @@
+#
+# common mkfile parameters shared by all architectures
+#
+
+OS=05678qvtz
+CPUS=spim arm arm64 amd64 386 power mips loong
+CFLAGS=-FTVw
+LEX=lex
+YACC=yacc
+MK=/bin/mk
+
+# recursive mk will have these set from the parent
+# this is never what we want. clear them
+
+TARG=
+OFILES=
+HFILES=
+YFILES=
+LIB=